Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(455)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelper.java

Issue 1505913003: Add update menu item and app menu icon badge (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix a couple of bugs Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package org.chromium.chrome.browser.omaha;
6
7 import android.content.ActivityNotFoundException;
8 import android.content.Context;
9 import android.content.Intent;
10 import android.graphics.Bitmap;
11 import android.graphics.BitmapFactory;
12 import android.graphics.Canvas;
13 import android.graphics.Paint;
14 import android.graphics.PorterDuff;
15 import android.graphics.PorterDuffXfermode;
16 import android.net.Uri;
17 import android.os.AsyncTask;
18 import android.text.TextUtils;
19
20 import org.chromium.base.CommandLine;
21 import org.chromium.base.Log;
22 import org.chromium.base.ThreadUtils;
23 import org.chromium.base.metrics.RecordHistogram;
24 import org.chromium.chrome.R;
25 import org.chromium.chrome.browser.ChromeActivity;
26 import org.chromium.chrome.browser.ChromeSwitches;
27 import org.chromium.chrome.browser.appmenu.AppMenu;
28 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
29 import org.chromium.components.variations.VariationsAssociatedData;
30 import org.chromium.ui.base.LocalizationUtils;
31
32 /**
33 * Contains logic for whether the update menu item should be shown, whether the update toolbar badge
34 * should be shown, and UMA logging for the update menu item.
35 */
36 public class UpdateMenuItemHelper {
37 private static UpdateMenuItemHelper sInstance;
38 private static Object sCreateInstanceLock = new Object();
39
40 private static final String TAG = "UpdateMenuItemHelper";
gone 2015/12/10 21:45:09 nit: private static finals go above private static
Theresa 2015/12/11 19:44:46 Done.
41
42 // VariationsAssociatedData configs
43 private static final String FIELD_TRIAL_NAME = "UpdateMenuItem";
44 private static final String ENABLED_VALUE = "true";
45 private static final String ENABLE_UPDATE_MENU_ITEM = "enable_update_menu_it em";
46 private static final String ENABLE_UPDATE_BADGE = "enable_update_badge";
47 private static final String SHOW_SUMMARY = "show_summary";
48 private static final String CUSTOM_SUMMARY = "custom_summary";
49
50 // UMA constants for logging whether the menu item was clicked.
51 private static final int ITEM_NOT_CLICKED = 0;
52 private static final int ITEM_CLICKED_INTENT_LAUNCHED = 1;
53 private static final int ITEM_CLICKED_INTENT_FAILED = 2;
54 private static final int ITEM_CLICKED_BOUNDARY = 3;
55
56 // UMA constants for logging whether Chrome was updated after the menu item was clicked.
57 private static final int UPDATED = 0;
58 private static final int NOT_UPDATED = 1;
59 private static final int UPDATED_BOUNDARY = 2;
60
61 // Whether OmahaClient has already been checked for an update.
62 private boolean mAlreadyCheckedForUpdates;
63
64 // Whether an update is available.
65 private boolean mUpdateAvailable;
66
67 // URL to direct the user to when Omaha detects a newer version available.
68 private String mUpdateUrl;
69
70 // Whether the menu item was clicked. This is used to log the click-through rate.
71 private boolean mMenuItemClicked;
72
73 // The bitmap to use for the menu button when the badge is showing.
74 private Bitmap mBadgedMenuButtonBitmap;
75
76 /**
77 * @return The {@link UpdateMenuItemHelper} instance.
78 */
79 public static UpdateMenuItemHelper getInstance() {
80 if (sInstance == null) {
81 synchronized (UpdateMenuItemHelper.sCreateInstanceLock) {
gone 2015/12/10 21:45:10 you should put the synchronized on the outside of
Theresa 2015/12/11 19:44:46 Done.
82 sInstance = new UpdateMenuItemHelper();
83 String testMarketUrl = getStringParamValue(ChromeSwitches.MARKET _URL_FOR_TESTING);
84 if (!TextUtils.isEmpty(testMarketUrl)) {
85 sInstance.mUpdateUrl = testMarketUrl;
86 }
87 }
88 }
89 return sInstance;
90 }
91
92 /**
93 * Checks if the {@link OmahaClient} knows about an update.
94 * @param activity The current {@link ChromeActivity}.
95 */
96 public void checkForUpdateOnBackgroundThread(final ChromeActivity activity) {
97 if (!getBooleanParam(ENABLE_UPDATE_MENU_ITEM)) return;
98
99 ThreadUtils.assertOnUiThread();
100
101 if (mAlreadyCheckedForUpdates) {
102 if (activity.isActivityDestroyed()) return;
103 activity.onCheckForUpdate(mUpdateAvailable);
104 return;
105 }
106
107 mAlreadyCheckedForUpdates = true;
108
109 new AsyncTask<Void, Void, Void>() {
110 @Override
111 protected Void doInBackground(Void... params) {
112 if (OmahaClient.isNewerVersionAvailable(activity)) {
113 mUpdateUrl = OmahaClient.getMarketURL(activity);
114 mUpdateAvailable = true;
115 } else {
116 mUpdateAvailable = false;
117 }
118 return null;
119 }
120
121 @Override
122 protected void onPostExecute(Void result) {
123 if (activity.isActivityDestroyed()) return;
124 activity.onCheckForUpdate(mUpdateAvailable);
125 recordUpdateHistogram();
126 }
127 }.execute();
128 }
129
130 /**
131 * Logs whether an update was performed if the update menu item was clicked.
132 * Should be called from ChromeActivity#onStart().
133 */
134 public void onStart() {
135 if (mAlreadyCheckedForUpdates) {
136 recordUpdateHistogram();
137 }
138 }
139
140 /**
141 * @param activity The current {@link ChromeActivity}.
142 * @return Whether the update menu item should be shown.
143 */
144 public boolean shouldShowMenuItem(ChromeActivity activity) {
145 if (getBooleanParam(ChromeSwitches.FORCE_SHOW_UPDATE_MENU_ITEM)) {
146 return true;
147 }
148
149 if (!getBooleanParam(ENABLE_UPDATE_MENU_ITEM)) {
150 return false;
151 }
152
153 return updateAvailable(activity);
154 }
155
156 /**
157 * @param context The current {@link Context}.
158 * @return The string to use for summary text or the empty string if no summ ary should be shown.
159 */
160 public String getMenuItemSummaryText(Context context) {
161 if (!getBooleanParam(SHOW_SUMMARY)) {
162 return "";
163 }
164
165 String customSummary = getStringParamValue(CUSTOM_SUMMARY);
166 if (!TextUtils.isEmpty(customSummary)) {
167 return customSummary;
168 }
169
170 return context.getResources().getString(R.string.menu_update_summary_def ault);
171 }
172
173 /**
174 * @param activity The current {@link ChromeActivity}.
175 * @return Whether the update badge should be shown in the toolbar.
176 */
177 public boolean shouldShowToolbarBadge(ChromeActivity activity) {
178 if (getBooleanParam(ChromeSwitches.FORCE_SHOW_UPDATE_MENU_ITEM)) {
179 return true;
180 }
181
182 if (!getBooleanParam(ENABLE_UPDATE_BADGE)) {
183 return false;
184 }
185
186 return updateAvailable(activity);
187 }
188
189 /**
190 * Handles a click on the update menu item.
191 * @param activity The current {@link ChromeActivity}.
192 */
193 public void onMenuItemClicked(ChromeActivity activity) {
194 if (mUpdateUrl == null) return;
195
196 // Fire an intent to open the URL.
197 try {
198 Intent launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(mUpda teUrl));
199 activity.startActivity(launchIntent);
200 recordItemClickedHistogram(ITEM_CLICKED_INTENT_LAUNCHED);
201 PrefServiceBridge.getInstance().setClickedUpdateMenuItem(true);
202 } catch (ActivityNotFoundException e) {
203 Log.e(TAG, "Failed to launch Activity for: " + mUpdateUrl);
204 recordItemClickedHistogram(ITEM_CLICKED_INTENT_FAILED);
205 }
206 }
207
208 /**
209 * Returns a {@link Bitmap} to use for the menu button with part of the orig inal image removed
210 * to simulate a 1dp transparent border around the update badge.
211 *
212 * @param context The current {@link Context}.
213 * @return The {@link Bitmap} to use for the the menu button when showing th e update badge.
214 */
215 public Bitmap getBadgedMenuButtonBitmap(Context context) {
216 if (mBadgedMenuButtonBitmap == null) {
217 // Punch a hole in the app menu button to create the illusion of a 1 dp transparent
218 // border around the update badge.
219 // Load btn_menu bitmap and use it to initialize a canvas.
220 BitmapFactory.Options opts = new BitmapFactory.Options();
221 opts.inMutable = true;
222 mBadgedMenuButtonBitmap = BitmapFactory.decodeResource(context.getRe sources(),
223 R.drawable.btn_menu, opts);
224 Canvas canvas = new Canvas();
225 canvas.setBitmap(mBadgedMenuButtonBitmap);
226
227 // Calculate the dimensions and offsets for the update badge.
228 float menuBadgeBackgroundSize = context.getResources().getDimension(
229 R.dimen.menu_badge_background_size);
230 float radius = menuBadgeBackgroundSize / 2.f;
231 // The design specification calls for 4.5dp right offset and 9dp top offset.
232 float xPos = 4.5f * context.getResources().getDisplayMetrics().densi ty + radius;
233 float yPos = 9f * context.getResources().getDisplayMetrics().density + radius;
234
235 if (LocalizationUtils.isLayoutRtl()) {
236 // In RTL layouts, the badge should be placed to the left of the menu button icon.
237 xPos = mBadgedMenuButtonBitmap.getWidth() - xPos;
238 }
239
240 // Draw a transparent circle on top of the bitmap, creating a hole.
241 Paint paint = new Paint();
242 paint.setFlags(Paint.ANTI_ALIAS_FLAG);
243 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
244 canvas.drawCircle(xPos, yPos, radius, paint);
245 }
246
247 return mBadgedMenuButtonBitmap;
248 }
249
250 /**
251 * Should be called before the AppMenu is dismissed if the update menu item was clicked.
252 */
253 public void setMenuItemClicked() {
254 mMenuItemClicked = true;
255 }
256
257 /**
258 * Called when the {@link AppMenu} is dimissed. Logs a histogram immediately if the update menu
259 * item was not clicked. If it was clicked, logging is delayed until #onMenu ItemClicked().
260 */
261 public void onMenuDismissed() {
262 if (!mMenuItemClicked) {
263 recordItemClickedHistogram(ITEM_NOT_CLICKED);
264 }
265 mMenuItemClicked = false;
266 }
267
268 private boolean updateAvailable(ChromeActivity activity) {
269 if (!mAlreadyCheckedForUpdates) {
270 checkForUpdateOnBackgroundThread(activity);
271 return false;
272 }
273
274 return mUpdateAvailable;
275 }
276
277 private void recordItemClickedHistogram(int action) {
278 RecordHistogram.recordEnumeratedHistogram("GoogleUpdate.MenuItem.ActionT akenOnMenuOpen",
279 action, ITEM_CLICKED_BOUNDARY);
280 }
281
282 private void recordUpdateHistogram() {
283 if (PrefServiceBridge.getInstance().getClickedUpdateMenuItem()) {
284 RecordHistogram.recordEnumeratedHistogram(
285 "GoogleUpdate.MenuItem.ActionTakenAfterItemClicked",
286 mUpdateAvailable ? NOT_UPDATED : UPDATED, UPDATED_BOUNDARY);
287 PrefServiceBridge.getInstance().setClickedUpdateMenuItem(false);
288 }
289 }
290
291 /**
292 * Gets a boolean VariationsAssociatedData parameter, assuming the <paramNam e>="true" format.
293 * Also checks for a command-line switch with the same name, for easy local testing.
294 * @param paramName The name of the parameter (or command-line switch) to ge t a value for.
295 * @return Whether the param is defined with a value "true", if there's a co mmand-line
296 * flag present with any value.
297 */
298 private static boolean getBooleanParam(String paramName) {
299 if (CommandLine.getInstance().hasSwitch(paramName)) {
300 return true;
301 }
302 return TextUtils.equals(ENABLED_VALUE,
303 VariationsAssociatedData.getVariationParamValue(FIELD_TRIAL_NAME , paramName));
304 }
305
306 /**
307 * Gets a String VariationsAssociatedData parameter. Also checks for a comma nd-line switch with
308 * the same name, for easy local testing.
309 * @param paramName The name of the parameter (or command-line switch) to ge t a value for.
310 * @return The command-line flag value if present, or the param is value if present.
311 */
312 private static String getStringParamValue(String paramName) {
313 String value = CommandLine.getInstance().getSwitchValue(paramName);
314 if (TextUtils.isEmpty(value)) {
315 value = VariationsAssociatedData.getVariationParamValue(FIELD_TRIAL_ NAME, paramName);
316 }
317 return value;
318 }
319 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698