Merge "Adding logging for various interaction in PinItemRequest UI" into ub-launcher3-dorval
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 68a6b28..909a429 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -154,4 +154,6 @@
optional int64 action_duration_millis = 4;
optional int64 elapsed_container_millis = 5;
optional int64 elapsed_session_millis = 6;
+
+ optional bool is_in_multi_window_mode = 7;
}
diff --git a/res/drawable/ic_instant_app.xml b/res/drawable/ic_instant_app.xml
deleted file mode 100644
index be5a3e0..0000000
--- a/res/drawable/ic_instant_app.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/badge_size"
- android:height="@dimen/badge_size"
- android:viewportWidth="18"
- android:viewportHeight="18">
-
- <path
- android:fillColor="@android:color/black"
- android:fillType="evenOdd"
- android:strokeWidth="1"
- android:pathData="M 9 0 C 13.9705627485 0 18 4.02943725152 18 9 C 18 13.9705627485 13.9705627485 18 9 18 C 4.02943725152 18 0 13.9705627485 0 9 C 0 4.02943725152 4.02943725152 0 9 0 Z" />
- <path
- android:fillColor="@android:color/white"
- android:fillType="evenOdd"
- android:strokeWidth="1"
- android:pathData="M 9 0 C 13.9705627485 0 18 4.02943725152 18 9 C 18 13.9705627485 13.9705627485 18 9 18 C 4.02943725152 18 0 13.9705627485 0 9 C 0 4.02943725152 4.02943725152 0 9 0 Z" />
- <path
- android:fillColor="@android:color/white"
- android:fillType="evenOdd"
- android:strokeWidth="1"
- android:pathData="M 9 0 C 13.9705627485 0 18 4.02943725152 18 9 C 18 13.9705627485 13.9705627485 18 9 18 C 4.02943725152 18 0 13.9705627485 0 9 C 0 4.02943725152 4.02943725152 0 9 0 Z" />
- <path
- android:fillColor="@android:color/black"
- android:fillAlpha="0.87"
- android:fillType="evenOdd"
- android:strokeWidth="1"
- android:pathData="M 6 10.4123279 L 8.63934949 10.4123279 L 8.63934949 15.6 L 12.5577168 7.84517705 L 9.94547194 7.84517705 L 9.94547194 2 Z" />
-</vector>
diff --git a/res/drawable/pending_widget_bg.xml b/res/drawable/pending_widget_bg.xml
new file mode 100644
index 0000000..cf29f90
--- /dev/null
+++ b/res/drawable/pending_widget_bg.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/round_rect_primary"
+ android:inset="@dimen/pending_widget_min_padding" />
diff --git a/res/layout/all_apps_discovery_item.xml b/res/layout/all_apps_discovery_item.xml
index 2b21ef5..1a7eaa7 100644
--- a/res/layout/all_apps_discovery_item.xml
+++ b/res/layout/all_apps_discovery_item.xml
@@ -27,18 +27,6 @@
android:padding="8dp"
android:scaleType="fitCenter"/>
- <ImageView
- android:id="@+id/badge"
- android:layout_width="16dp"
- android:layout_height="16dp"
- android:scaleType="fitCenter"
- android:src="@drawable/ic_instant_app"
- android:layout_marginRight="6dp"
- android:layout_marginBottom="6dp"
- android:layout_alignRight="@+id/image"
- android:layout_alignBottom="@+id/image"
- android:clickable="false"/>
-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index 2a62037..9ec26e2 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -56,11 +56,10 @@
* Must not hold the Context.
*/
public AppInfo(Context context, LauncherActivityInfo info, UserHandle user) {
- this(context, info, user, UserManagerCompat.getInstance(context).isQuietModeEnabled(user));
+ this(info, user, UserManagerCompat.getInstance(context).isQuietModeEnabled(user));
}
- public AppInfo(Context context, LauncherActivityInfo info, UserHandle user,
- boolean quietModeEnabled) {
+ public AppInfo(LauncherActivityInfo info, UserHandle user, boolean quietModeEnabled) {
this.componentName = info.getComponentName();
this.container = ItemInfo.NO_ID;
this.user = user;
@@ -71,7 +70,7 @@
isDisabled |= ShortcutInfo.FLAG_DISABLED_QUIET_USER;
}
- intent = makeLaunchIntent(context, info, user);
+ intent = makeLaunchIntent(info);
}
public AppInfo(AppInfo info) {
@@ -95,14 +94,11 @@
return new ComponentKey(componentName, user);
}
- public static Intent makeLaunchIntent(Context context, LauncherActivityInfo info,
- UserHandle user) {
- long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
+ public static Intent makeLaunchIntent(LauncherActivityInfo info) {
return new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_LAUNCHER)
.setComponent(info.getComponentName())
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
- .putExtra(EXTRA_PROFILE, serialNumber);
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
}
@Override
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 2e017df..c4086a8 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -195,7 +195,7 @@
try {
return parseLayout(mLayoutId, screenIds);
} catch (Exception e) {
- Log.w(TAG, "Got exception parsing layout.", e);
+ Log.e(TAG, "Error parsing layout: " + e);
return -1;
}
}
@@ -362,7 +362,7 @@
return addShortcut(info.loadLabel(mPackageManager).toString(),
intent, Favorites.ITEM_TYPE_APPLICATION);
} catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Unable to add favorite: " + packageName + "/" + className, e);
+ Log.e(TAG, "Favorite not found: " + packageName + "/" + className);
}
return -1;
} else {
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index e1a3ad0..410d590 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -38,11 +38,16 @@
public final UserEventDispatcher getUserEventDispatcher() {
if (mUserEventDispatcher == null) {
- mUserEventDispatcher = UserEventDispatcher.get(this);
+ mUserEventDispatcher = UserEventDispatcher.newInstance(this,
+ isInMultiWindowModeCompat());
}
return mUserEventDispatcher;
}
+ public boolean isInMultiWindowModeCompat() {
+ return Utilities.ATLEAST_NOUGAT && isInMultiWindowMode();
+ }
+
public static BaseActivity fromContext(Context context) {
if (context instanceof BaseActivity) {
return (BaseActivity) context;
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 80dec16..ce85570 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -328,7 +328,7 @@
user = info.getUser();
mContext = context;
- launchIntent = AppInfo.makeLaunchIntent(context, info, user);
+ launchIntent = AppInfo.makeLaunchIntent(info);
label = info.getLabel().toString();
}
@@ -344,7 +344,7 @@
mContext = context;
user = info.getUserHandle();
- launchIntent = info.makeIntent(context);
+ launchIntent = info.makeIntent();
label = info.getShortLabel().toString();
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 2dd3198..9e214d1 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -29,7 +29,6 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.ProviderConfig;
-import com.android.launcher3.logging.FileLog;
import com.android.launcher3.util.Thunk;
import org.xmlpull.v1.XmlPullParser;
@@ -188,23 +187,6 @@
}
}
- public void dumpDisplayInfo(Context context) {
- WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- Display display = wm.getDefaultDisplay();
- DisplayMetrics dm = new DisplayMetrics();
- display.getMetrics(dm);
-
- Point smallestSize = new Point();
- Point largestSize = new Point();
- display.getCurrentSizeRange(smallestSize, largestSize);
-
- FileLog.e("DisplayInfo", "Default Density: " + DisplayMetrics.DENSITY_DEFAULT);
- FileLog.e("DisplayInfo", "Density: " + dm.densityDpi);
- FileLog.e("DisplayInfo", "Smallest size: " + smallestSize);
- FileLog.e("DisplayInfo", "Largest size: " + largestSize);
- FileLog.e("DisplayInfo", "minWidth/Height DPS: " + minWidthDps + ", " + minHeightDps);
- }
-
ArrayList<InvariantDeviceProfile> getPredefinedDeviceProfiles(Context context) {
ArrayList<InvariantDeviceProfile> profiles = new ArrayList<>();
try (XmlResourceParser parser = context.getResources().getXml(R.xml.device_profiles)) {
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index aec6c7d..0779a3d 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -29,11 +29,6 @@
*/
public class ItemInfo {
- /**
- * Intent extra to store the profile. Format: UserHandle
- */
- public static final String EXTRA_PROFILE = "profile";
-
public static final int NO_ID = -1;
/**
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d4bfc49..84a5930 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -366,7 +366,7 @@
// Load configuration-specific DeviceProfile
mDeviceProfile = app.getInvariantDeviceProfile().getDeviceProfile(this);
- if (Utilities.ATLEAST_NOUGAT && isInMultiWindowMode()) {
+ if (isInMultiWindowModeCompat()) {
Display display = getWindowManager().getDefaultDisplay();
Point mwSize = new Point();
display.getSize(mwSize);
@@ -483,7 +483,7 @@
// It's possible that All Apps is visible when this is run,
// so always use light status bar in that case. Only change nav bar color to status bar
// color when All Apps is visible.
- activateLightStatusBar(lightStatusBar || isAllAppsVisible(), isAllAppsVisible());
+ activateLightSystemBars(lightStatusBar || isAllAppsVisible(), true, isAllAppsVisible());
}
}
@@ -491,21 +491,26 @@
private static final int SYSTEM_UI_FLAG_LIGHT_NAV_BAR = 0x10;
/**
- * Sets the status bar to be light or not. Light status bar means dark icons.
- * @param lightStatusBar make sure the status bar is light
- * @param changeNavBar if true, make the nav bar theme in sync with status bar.
+ * Sets the status and/or nav bar to be light or not. Light status bar means dark icons.
+ * @param isLight make sure the system bar is light.
+ * @param statusBar if true, make the status bar theme match the isLight param.
+ * @param navBar if true, make the nav bar theme match the isLight param.
*/
- public void activateLightStatusBar(boolean lightStatusBar, boolean changeNavBar) {
+ public void activateLightSystemBars(boolean isLight, boolean statusBar, boolean navBar) {
int oldSystemUiFlags = getWindow().getDecorView().getSystemUiVisibility();
int newSystemUiFlags = oldSystemUiFlags;
- if (lightStatusBar) {
- newSystemUiFlags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR ;
- if (changeNavBar && Utilities.isAtLeastO()) {
+ if (isLight) {
+ if (statusBar) {
+ newSystemUiFlags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ }
+ if (navBar && Utilities.isAtLeastO()) {
newSystemUiFlags |= SYSTEM_UI_FLAG_LIGHT_NAV_BAR;
}
} else {
- newSystemUiFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
- if (changeNavBar && Utilities.isAtLeastO()) {
+ if (statusBar) {
+ newSystemUiFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ }
+ if (navBar && Utilities.isAtLeastO()) {
newSystemUiFlags &= ~(SYSTEM_UI_FLAG_LIGHT_NAV_BAR);
}
}
@@ -2265,6 +2270,9 @@
if (v instanceof Workspace) {
if (mWorkspace.isInOverviewMode()) {
+ getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Type.TOUCH,
+ LauncherLogProto.Action.Direction.NONE,
+ LauncherLogProto.ContainerType.OVERVIEW, mWorkspace.getCurrentPage());
showWorkspace(true);
}
return;
@@ -2701,11 +2709,7 @@
!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
Bundle optsBundle = useLaunchAnimation ? getActivityLaunchOptions(v) : null;
- UserHandle user = null;
- if (intent.hasExtra(AppInfo.EXTRA_PROFILE)) {
- long serialNumber = intent.getLongExtra(AppInfo.EXTRA_PROFILE, -1);
- user = UserManagerCompat.getInstance(this).getUserForSerialNumber(serialNumber);
- }
+ UserHandle user = item == null ? null : item.user;
// Prepare intent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 2e75579..180c202 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -28,7 +28,6 @@
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dynamicui.ExtractionUtils;
-import com.android.launcher3.model.GridSizeMigrationTask;
import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.TestingUtils;
@@ -54,8 +53,6 @@
if (INSTANCE == null) {
if (Looper.myLooper() == Looper.getMainLooper()) {
INSTANCE = new LauncherAppState(context.getApplicationContext());
- GridSizeMigrationTask.logDeviceProfileIfChanged(
- INSTANCE.getInvariantDeviceProfile(), context);
} else {
try {
return new MainThreadExecutor().submit(new Callable<LauncherAppState>() {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index dc668e6..5a41eeb 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -1069,9 +1069,6 @@
info.rank = c.getInt(rankIndex);
info.spanX = 1;
info.spanY = 1;
- // TODO: Remove this extra. Instead we should be using
- // itemInfo#user.
- info.intent.putExtra(ItemInfo.EXTRA_PROFILE, c.serialNumber);
info.isDisabled |= disabledState;
if (isSafeMode && !Utilities.isSystemApp(context, intent)) {
info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;
@@ -1685,7 +1682,7 @@
for (int i = 0; i < apps.size(); i++) {
LauncherActivityInfo app = apps.get(i);
// This builds the icon bitmaps.
- mBgAllAppsList.add(new AppInfo(mContext, app, user, quietMode), app);
+ mBgAllAppsList.add(new AppInfo(app, user, quietMode), app);
}
final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index e250b3f..a750406 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -72,7 +72,7 @@
private static final String TAG = "LauncherProvider";
private static final boolean LOGD = false;
- private static final int DATABASE_VERSION = 27;
+ private static final int DATABASE_VERSION = 28;
public static final String AUTHORITY = ProviderConfig.AUTHORITY;
@@ -791,6 +791,26 @@
break;
}
case 27: {
+ // Remove "profile extra"
+ db.beginTransaction();
+ try {
+ UserManagerCompat um = UserManagerCompat.getInstance(mContext);
+ for (UserHandle user : um.getUserProfiles()) {
+ long serial = um.getSerialNumberForUser(user);
+ String sql = "update favorites set intent = replace(intent, "
+ + "';l.profile=" + serial + ";', ';') where itemType = 0;";
+ db.execSQL(sql);
+ }
+ db.setTransactionSuccessful();
+ } catch (SQLException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ // Old version remains, which means we wipe old data
+ break;
+ } finally {
+ db.endTransaction();
+ }
+ }
+ case 28: {
// DB Upgraded successfully
return;
}
diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java
index 43fa4aa..b163464 100644
--- a/src/com/android/launcher3/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/PendingAppWidgetHostView.java
@@ -73,7 +73,7 @@
mPaint.setColor(Themes.getAttrColor(getContext(), android.R.attr.textColorPrimary));
mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics()));
- setBackgroundResource(R.drawable.round_rect_primary);
+ setBackgroundResource(R.drawable.pending_widget_bg);
setWillNotDraw(false);
setElevation(getResources().getDimension(R.dimen.pending_widget_elevation));
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index e8bf0a5..203bc25 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -19,14 +19,17 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
+import android.util.Log;
import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserManagerCompat;
import java.util.List;
@@ -35,9 +38,13 @@
*/
public class SessionCommitReceiver extends BroadcastReceiver {
+ private static final long SESSION_IGNORE_DURATION = 3 * 60 * 60 * 1000; // 3 hours
+
// Preference key for automatically adding icon to homescreen.
public static final String ADD_ICON_PREFERENCE_KEY = "pref_add_icon_to_home";
+ private static final String KEY_FIRST_TIME = "first_session_broadcast_time";
+
@Override
public void onReceive(Context context, Intent intent) {
if (!isEnabled(context)) {
@@ -57,6 +64,17 @@
return;
}
+ // STOPSHIP: Remove this workaround when we start getting proper install reason
+ SharedPreferences prefs = context
+ .getSharedPreferences(LauncherFiles.DEVICE_PREFERENCES_KEY, 0);
+ long now = System.currentTimeMillis();
+ long firstTime = prefs.getLong(KEY_FIRST_TIME, now);
+ prefs.edit().putLong(KEY_FIRST_TIME, firstTime).apply();
+ if ((now - firstTime) < SESSION_IGNORE_DURATION) {
+ Log.d("SessionCommitReceiver", "Temporarily ignoring session broadcast");
+ return;
+ }
+
List<LauncherActivityInfo> activities = LauncherAppsCompat.getInstance(context)
.getActivityList(info.getAppPackageName(), user);
if (activities == null || activities.isEmpty()) {
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index f0bb1c0..6f0417c 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -199,7 +199,7 @@
public void updateFromDeepShortcutInfo(ShortcutInfoCompat shortcutInfo, Context context) {
// {@link ShortcutInfoCompat#getActivity} can change during an update. Recreate the intent
- intent = shortcutInfo.makeIntent(context);
+ intent = shortcutInfo.makeIntent();
title = shortcutInfo.getShortLabel();
CharSequence label = shortcutInfo.getLongLabel();
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index abc5367..207a7d4 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -468,13 +468,8 @@
&& TextUtils.isEmpty(launchIntent.getDataString())) {
// An app target can either have no extra or have ItemInfo.EXTRA_PROFILE.
Bundle extras = launchIntent.getExtras();
- if (extras == null) {
- return true;
- } else {
- Set<String> keys = extras.keySet();
- return keys.size() == 1 && keys.contains(ItemInfo.EXTRA_PROFILE);
- }
- };
+ return extras == null || extras.keySet().isEmpty();
+ }
return false;
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index b436fa2..30ed180 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -9,7 +9,6 @@
import android.graphics.Color;
import android.support.v4.graphics.ColorUtils;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
@@ -47,11 +46,10 @@
private final Interpolator mAccelInterpolator = new AccelerateInterpolator(2f);
private final Interpolator mDecelInterpolator = new DecelerateInterpolator(3f);
private final Interpolator mFastOutSlowInInterpolator = new FastOutSlowInInterpolator();
- private final ScrollInterpolator mScrollInterpolator = new ScrollInterpolator();
+ private final VerticalPullDetector.ScrollInterpolator mScrollInterpolator
+ = new VerticalPullDetector.ScrollInterpolator();
- private static final float ANIMATION_DURATION = 1200;
private static final float PARALLAX_COEFFICIENT = .125f;
- private static final float FAST_FLING_PX_MS = 10;
private static final int SINGLE_FRAME_MS = 16;
private AllAppsContainerView mAppsView;
@@ -262,7 +260,7 @@
// Use a light status bar (dark icons) if all apps is behind at least half of the status
// bar. If the status bar is already light due to wallpaper extraction, keep it that way.
boolean forceLight = shift <= mStatusBarHeight / 2;
- mLauncher.activateLightStatusBar(forceLight, true);
+ mLauncher.activateLightSystemBars(forceLight, true /* statusBar */, true /* navBar */);
}
/**
@@ -315,13 +313,7 @@
}
private void calculateDuration(float velocity, float disp) {
- // TODO: make these values constants after tuning.
- float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity));
- float travelDistance = Math.max(0.2f, disp / mShiftRange);
- mAnimationDuration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance);
- if (DBG) {
- Log.d(TAG, String.format("calculateDuration=%d, v=%f, d=%f", mAnimationDuration, velocity, disp));
- }
+ mAnimationDuration = mDetector.calculateDuration(velocity, disp / mShiftRange);
}
public boolean animateToAllApps(AnimatorSet animationOut, long duration) {
@@ -511,21 +503,4 @@
setProgress(mProgress);
}
- static class ScrollInterpolator implements Interpolator {
-
- boolean mSteeper;
-
- public void setVelocityAtZero(float velocity) {
- mSteeper = velocity > FAST_FLING_PX_MS;
- }
-
- public float getInterpolation(float t) {
- t -= 1.0f;
- float output = t * t * t;
- if (mSteeper) {
- output *= t * t; // Make interpolation initial slope steeper
- }
- return output + 1;
- }
- }
}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index f228470..f5cf7ef 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -292,7 +292,7 @@
mDiscoveredApps.clear();
break;
case UPDATE:
- mDiscoveredApps.add(new AppDiscoveryAppInfo(app, mLauncher));
+ mDiscoveredApps.add(new AppDiscoveryAppInfo(app));
break;
}
updateAdapterItems();
@@ -494,10 +494,13 @@
if (hasFilter()) {
if (isAppDiscoveryRunning() || mDiscoveredApps.size() > 0) {
mAdapterItems.add(AdapterItem.asLoadingDivider(position++));
-
// Append all app discovery results
for (int i = 0; i < mDiscoveredApps.size(); i++) {
AppDiscoveryAppInfo appDiscoveryAppInfo = mDiscoveredApps.get(i);
+ if (appDiscoveryAppInfo.isRecent) {
+ // already handled in getFilteredAppInfos()
+ continue;
+ }
AdapterItem item = AdapterItem.asDiscoveryItem(position++,
"", appDiscoveryAppInfo, appIndex++);
mAdapterItems.add(item);
@@ -589,6 +592,17 @@
result.add(match);
}
}
+
+ // adding recently used instant apps
+ if (mDiscoveredApps.size() > 0) {
+ for (int i = 0; i < mDiscoveredApps.size(); i++) {
+ AppDiscoveryAppInfo discoveryAppInfo = mDiscoveredApps.get(i);
+ if (discoveryAppInfo.isRecent) {
+ result.add(discoveryAppInfo);
+ }
+ }
+ Collections.sort(result, mAppNameComparator);
+ }
return result;
}
diff --git a/src/com/android/launcher3/allapps/VerticalPullDetector.java b/src/com/android/launcher3/allapps/VerticalPullDetector.java
index 96e1299..7800c01 100644
--- a/src/com/android/launcher3/allapps/VerticalPullDetector.java
+++ b/src/com/android/launcher3/allapps/VerticalPullDetector.java
@@ -4,6 +4,7 @@
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import android.view.animation.Interpolator;
/**
* One dimensional scroll gesture detector for all apps container pull up interaction.
@@ -23,6 +24,9 @@
public static final int DIRECTION_DOWN = 1 << 1;
public static final int DIRECTION_BOTH = DIRECTION_DOWN | DIRECTION_UP;
+ private static final float ANIMATION_DURATION = 1200;
+ private static final float FAST_FLING_PX_MS = 10;
+
/**
* The minimum release velocity in pixels per millisecond that triggers fling..
*/
@@ -112,7 +116,7 @@
mListener = l;
}
- interface Listener {
+ public interface Listener {
void onDragStart(boolean start);
boolean onDrag(float displacement, float velocity);
@@ -272,4 +276,33 @@
private static float interpolate(float from, float to, float alpha) {
return (1.0f - alpha) * from + alpha * to;
}
+
+ public long calculateDuration(float velocity, float progressNeeded) {
+ // TODO: make these values constants after tuning.
+ float velocityDivisor = Math.max(2f, Math.abs(0.5f * velocity));
+ float travelDistance = Math.max(0.2f, progressNeeded);
+ long duration = (long) Math.max(100, ANIMATION_DURATION / velocityDivisor * travelDistance);
+ if (DBG) {
+ Log.d(TAG, String.format("calculateDuration=%d, v=%f, d=%f", duration, velocity, progressNeeded));
+ }
+ return duration;
+ }
+
+ public static class ScrollInterpolator implements Interpolator {
+
+ boolean mSteeper;
+
+ public void setVelocityAtZero(float velocity) {
+ mSteeper = velocity > FAST_FLING_PX_MS;
+ }
+
+ public float getInterpolation(float t) {
+ t -= 1.0f;
+ float output = t * t * t;
+ if (mSteeper) {
+ output *= t * t; // Make interpolation initial slope steeper
+ }
+ return output + 1;
+ }
+ }
}
diff --git a/src/com/android/launcher3/badge/BadgeInfo.java b/src/com/android/launcher3/badge/BadgeInfo.java
index 532396c..08d8ad4 100644
--- a/src/com/android/launcher3/badge/BadgeInfo.java
+++ b/src/com/android/launcher3/badge/BadgeInfo.java
@@ -25,6 +25,7 @@
import android.support.annotation.Nullable;
import com.android.launcher3.notification.NotificationInfo;
+import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
@@ -35,6 +36,8 @@
*/
public class BadgeInfo {
+ public static final int MAX_COUNT = 999;
+
/** Used to link this BadgeInfo to icons on the workspace and all apps */
private PackageUserKey mPackageUserKey;
@@ -42,7 +45,13 @@
* The keys of the notifications that this badge represents. These keys can later be
* used to retrieve {@link NotificationInfo}'s.
*/
- private List<String> mNotificationKeys;
+ private List<NotificationKeyData> mNotificationKeys;
+
+ /**
+ * The current sum of the counts in {@link #mNotificationKeys},
+ * updated whenever a key is added or removed.
+ */
+ private int mTotalCount;
/** This will only be initialized if the badge should display the notification icon. */
private NotificationInfo mNotificationInfo;
@@ -59,28 +68,46 @@
}
/**
- * Returns whether the notification was added (false if it already existed).
+ * Returns whether the notification was added or its count changed.
*/
- public boolean addNotificationKeyIfNotExists(String notificationKey) {
- if (mNotificationKeys.contains(notificationKey)) {
- return false;
+ public boolean addOrUpdateNotificationKey(NotificationKeyData notificationKey) {
+ int indexOfPrevKey = mNotificationKeys.indexOf(notificationKey);
+ NotificationKeyData prevKey = indexOfPrevKey == -1 ? null
+ : mNotificationKeys.get(indexOfPrevKey);
+ if (prevKey != null) {
+ if (prevKey.count == notificationKey.count) {
+ return false;
+ }
+ // Notification was updated with a new count.
+ mTotalCount -= prevKey.count;
+ mTotalCount += notificationKey.count;
+ prevKey.count = notificationKey.count;
+ return true;
}
- return mNotificationKeys.add(notificationKey);
+ boolean added = mNotificationKeys.add(notificationKey);
+ if (added) {
+ mTotalCount += notificationKey.count;
+ }
+ return added;
}
/**
* Returns whether the notification was removed (false if it didn't exist).
*/
- public boolean removeNotificationKey(String notificationKey) {
- return mNotificationKeys.remove(notificationKey);
+ public boolean removeNotificationKey(NotificationKeyData notificationKey) {
+ boolean removed = mNotificationKeys.remove(notificationKey);
+ if (removed) {
+ mTotalCount -= notificationKey.count;
+ }
+ return removed;
}
- public List<String> getNotificationKeys() {
+ public List<NotificationKeyData> getNotificationKeys() {
return mNotificationKeys;
}
public int getNotificationCount() {
- return mNotificationKeys.size();
+ return Math.min(mTotalCount, MAX_COUNT);
}
public void setNotificationToShow(@Nullable NotificationInfo notificationInfo) {
diff --git a/src/com/android/launcher3/badge/FolderBadgeInfo.java b/src/com/android/launcher3/badge/FolderBadgeInfo.java
index 4d1e5c2..f7c64aa 100644
--- a/src/com/android/launcher3/badge/FolderBadgeInfo.java
+++ b/src/com/android/launcher3/badge/FolderBadgeInfo.java
@@ -18,8 +18,6 @@
import com.android.launcher3.Utilities;
-import static com.android.launcher3.Utilities.boundToRange;
-
/**
* Subclass of BadgeInfo that only contains the badge count,
* which is the sum of all the Folder's items' counts.
@@ -27,7 +25,6 @@
public class FolderBadgeInfo extends BadgeInfo {
private static final int MIN_COUNT = 0;
- private static final int MAX_COUNT = 999;
private int mTotalNotificationCount;
@@ -41,7 +38,7 @@
}
mTotalNotificationCount += badgeToAdd.getNotificationCount();
mTotalNotificationCount = Utilities.boundToRange(
- mTotalNotificationCount, MIN_COUNT, MAX_COUNT);
+ mTotalNotificationCount, MIN_COUNT, BadgeInfo.MAX_COUNT);
}
public void subtractBadgeInfo(BadgeInfo badgeToSubtract) {
@@ -50,7 +47,7 @@
}
mTotalNotificationCount -= badgeToSubtract.getNotificationCount();
mTotalNotificationCount = Utilities.boundToRange(
- mTotalNotificationCount, MIN_COUNT, MAX_COUNT);
+ mTotalNotificationCount, MIN_COUNT, BadgeInfo.MAX_COUNT);
}
@Override
diff --git a/src/com/android/launcher3/discovery/AppDiscoveryAppInfo.java b/src/com/android/launcher3/discovery/AppDiscoveryAppInfo.java
index 50e979a..06493b2 100644
--- a/src/com/android/launcher3/discovery/AppDiscoveryAppInfo.java
+++ b/src/com/android/launcher3/discovery/AppDiscoveryAppInfo.java
@@ -18,24 +18,18 @@
import android.content.ComponentName;
import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.android.launcher3.AppInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
public class AppDiscoveryAppInfo extends AppInfo {
- private final @NonNull Launcher mLauncher;
-
public final boolean showAsDiscoveryItem;
public final boolean isInstantApp;
+ public final boolean isRecent;
public final float rating;
public final long reviewCount;
public final @NonNull String publisher;
@@ -43,14 +37,14 @@
public final @NonNull Intent launchIntent;
public final @Nullable String priceFormatted;
- public AppDiscoveryAppInfo(AppDiscoveryItem item, Launcher launcher) {
- this.mLauncher = launcher;
+ public AppDiscoveryAppInfo(AppDiscoveryItem item) {
this.intent = item.isInstantApp ? item.launchIntent : item.installIntent;
this.title = item.title;
this.iconBitmap = item.bitmap;
this.isDisabled = ShortcutInfo.DEFAULT;
this.usingLowResIcon = false;
this.isInstantApp = item.isInstantApp;
+ this.isRecent = item.isRecent;
this.rating = item.starRating;
this.showAsDiscoveryItem = true;
this.publisher = item.publisher != null ? item.publisher : "";
@@ -67,18 +61,7 @@
if (!isDragAndDropSupported()) {
throw new RuntimeException("DnD is currently not supported for discovered store apps");
}
- ShortcutInfo shortcutInfo = super.makeShortcut();
- if (isInstantApp) {
- int iconSize = iconBitmap.getWidth();
- int badgeSize = mLauncher.getResources().getDimensionPixelOffset(R.dimen.badge_size);
- Bitmap icon = Bitmap.createBitmap(iconBitmap);
- Drawable badgeDrawable = mLauncher.getDrawable(R.drawable.ic_instant_app);
- badgeDrawable.setBounds(iconSize - badgeSize, iconSize - badgeSize, iconSize, iconSize);
- Canvas canvas = new Canvas(icon);
- badgeDrawable.draw(canvas);
- shortcutInfo.iconBitmap = icon;
- }
- return shortcutInfo;
+ return super.makeShortcut();
}
public boolean isDragAndDropSupported() {
diff --git a/src/com/android/launcher3/discovery/AppDiscoveryItem.java b/src/com/android/launcher3/discovery/AppDiscoveryItem.java
index 7c10371..09c91ac 100644
--- a/src/com/android/launcher3/discovery/AppDiscoveryItem.java
+++ b/src/com/android/launcher3/discovery/AppDiscoveryItem.java
@@ -28,6 +28,7 @@
public final String packageName;
public final boolean isInstantApp;
+ public final boolean isRecent;
public final float starRating;
public final long reviewCount;
public final Intent launchIntent;
@@ -39,6 +40,7 @@
public AppDiscoveryItem(String packageName,
boolean isInstantApp,
+ boolean isRecent,
float starRating,
long reviewCount,
CharSequence title,
@@ -49,6 +51,7 @@
Intent installIntent) {
this.packageName = packageName;
this.isInstantApp = isInstantApp;
+ this.isRecent = isRecent;
this.starRating = starRating;
this.reviewCount = reviewCount;
this.launchIntent = launchIntent;
diff --git a/src/com/android/launcher3/discovery/AppDiscoveryItemView.java b/src/com/android/launcher3/discovery/AppDiscoveryItemView.java
index 6faad87..9bb3b10 100644
--- a/src/com/android/launcher3/discovery/AppDiscoveryItemView.java
+++ b/src/com/android/launcher3/discovery/AppDiscoveryItemView.java
@@ -34,7 +34,6 @@
private static boolean SHOW_REVIEW_COUNT = false;
private ImageView mImage;
- private ImageView mBadge;
private TextView mTitle;
private TextView mRatingText;
private RatingView mRatingView;
@@ -58,7 +57,6 @@
protected void onFinishInflate() {
super.onFinishInflate();
this.mImage = (ImageView) findViewById(R.id.image);
- this.mBadge = (ImageView) findViewById(R.id.badge);
this.mTitle = (TextView) findViewById(R.id.title);
this.mRatingText = (TextView) findViewById(R.id.rating);
this.mRatingView = (RatingView) findViewById(R.id.rating_view);
@@ -80,7 +78,6 @@
mImage.setTag(info);
mImage.setImageBitmap(info.iconBitmap);
mImage.setOnLongClickListener(info.isDragAndDropSupported() ? mOnLongClickListener : null);
- mBadge.setVisibility(info.isInstantApp ? View.VISIBLE : View.GONE);
mTitle.setText(info.title);
mPrice.setText(info.priceFormatted != null ? info.priceFormatted : "");
mReviewCount.setVisibility(SHOW_REVIEW_COUNT ? View.VISIBLE : View.GONE);
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 90e4531..07e99c6 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -30,7 +30,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.ProviderConfig;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
@@ -63,17 +62,11 @@
private static final boolean IS_VERBOSE =
ProviderConfig.IS_DOGFOOD_BUILD && Utilities.isPropertyEnabled(LogConfig.USEREVENT);
- private static UserEventDispatcher sInstance;
- private static final Object LOCK = new Object();
-
- public static UserEventDispatcher get(Context context) {
- synchronized (LOCK) {
- if (sInstance == null) {
- sInstance = Utilities.getOverrideObject(UserEventDispatcher.class,
- context.getApplicationContext(), R.string.user_event_dispatcher_class);
- }
- return sInstance;
- }
+ public static UserEventDispatcher newInstance(Context context, boolean isInMultiWindowMode) {
+ UserEventDispatcher ued = Utilities.getOverrideObject(UserEventDispatcher.class,
+ context.getApplicationContext(), R.string.user_event_dispatcher_class);
+ ued.mIsInMultiWindowMode = isInMultiWindowMode;
+ return ued;
}
/**
@@ -118,6 +111,7 @@
private long mElapsedContainerMillis;
private long mElapsedSessionMillis;
private long mActionDurationMillis;
+ private boolean mIsInMultiWindowMode;
// Used for filling in predictedRank on {@link Target}s.
private List<ComponentKey> mPredictedApps;
@@ -302,6 +296,7 @@
}
public void dispatchUserEvent(LauncherEvent ev, Intent intent) {
+ ev.isInMultiWindowMode = mIsInMultiWindowMode;
ev.elapsedContainerMillis = SystemClock.uptimeMillis() - mElapsedContainerMillis;
ev.elapsedSessionMillis = SystemClock.uptimeMillis() - mElapsedSessionMillis;
@@ -320,6 +315,7 @@
ev.elapsedContainerMillis,
ev.elapsedSessionMillis,
ev.actionDurationMillis);
+ log += "\n isInMultiWindowMode " + ev.isInMultiWindowMode;
Log.d(TAG, log);
}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index e50b912..221798b 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -27,7 +27,6 @@
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.logging.FileLog;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.LongArrayMap;
@@ -890,23 +889,6 @@
.apply();
}
- public static void logDeviceProfileIfChanged(InvariantDeviceProfile idp, Context context) {
- SharedPreferences prefs = Utilities.getPrefs(context);
- String gridSizeString = getPointString(idp.numColumns, idp.numRows);
-
- int oldHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons);
- String oldSize = prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString);
- if (gridSizeString.equals(oldSize) && idp.numHotseatIcons == oldHotseatCount) {
- // Skip if workspace and hotseat sizes have not changed.
- return;
- }
-
- FileLog.e(TAG, "Grid size changed" + gridSizeString);
- FileLog.e(TAG, " oldSize: " + oldSize + " , hotseat: " + oldHotseatCount);
- FileLog.e(TAG, " newSize: " + gridSizeString + " , hotseat: " + idp.numHotseatIcons);
- idp.dumpDisplayInfo(context);
- }
-
/**
* Migrates the workspace and hotseat in case their sizes changed.
* @return false if the migration failed.
diff --git a/src/com/android/launcher3/notification/NotificationInfo.java b/src/com/android/launcher3/notification/NotificationInfo.java
index ba7675c..f6779b3 100644
--- a/src/com/android/launcher3/notification/NotificationInfo.java
+++ b/src/com/android/launcher3/notification/NotificationInfo.java
@@ -38,7 +38,7 @@
* only be created when we need to show the notification contents on the UI; until then, a
* {@link com.android.launcher3.badge.BadgeInfo} with only the notification key should
* be passed around, and then this can be constructed using the StatusBarNotification from
- * {@link NotificationListener#getNotificationsForKeys(String[])}.
+ * {@link NotificationListener#getNotificationsForKeys(java.util.List)}.
*/
public class NotificationInfo implements View.OnClickListener {
diff --git a/src/com/android/launcher3/notification/NotificationKeyData.java b/src/com/android/launcher3/notification/NotificationKeyData.java
new file mode 100644
index 0000000..bf7ae1a
--- /dev/null
+++ b/src/com/android/launcher3/notification/NotificationKeyData.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.notification;
+
+import android.app.Notification;
+import android.service.notification.StatusBarNotification;
+import android.support.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The key data associated with the notification, used to determine what to include
+ * in badges and dummy popup views before they are populated.
+ *
+ * @see NotificationInfo for the full data used when populating the dummy views.
+ */
+public class NotificationKeyData {
+ public final String notificationKey;
+ public final String shortcutId;
+ public int count;
+
+ private NotificationKeyData(String notificationKey, String shortcutId, int count) {
+ this.notificationKey = notificationKey;
+ this.shortcutId = shortcutId;
+ this.count = Math.max(1, count);
+ }
+
+ public static NotificationKeyData fromNotification(StatusBarNotification sbn) {
+ Notification notif = sbn.getNotification();
+ return new NotificationKeyData(sbn.getKey(), notif.getShortcutId(), notif.number);
+ }
+
+ public static List<String> extractKeysOnly(@NonNull List<NotificationKeyData> notificationKeys) {
+ List<String> keysOnly = new ArrayList<>(notificationKeys.size());
+ for (NotificationKeyData notificationKeyData : notificationKeys) {
+ keysOnly.add(notificationKeyData.notificationKey);
+ }
+ return keysOnly;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof NotificationKeyData)) {
+ return false;
+ }
+ // Only compare the keys.
+ return ((NotificationKeyData) obj).notificationKey.equals(notificationKey);
+ }
+}
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 16cb5fb..75a1b8a 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -94,8 +94,8 @@
break;
case MSG_NOTIFICATION_REMOVED:
if (sNotificationsChangedListener != null) {
- Pair<PackageUserKey, String> pair
- = (Pair<PackageUserKey, String>) message.obj;
+ Pair<PackageUserKey, NotificationKeyData> pair
+ = (Pair<PackageUserKey, NotificationKeyData>) message.obj;
sNotificationsChangedListener.onNotificationRemoved(pair.first, pair.second);
}
break;
@@ -165,12 +165,12 @@
*/
private class NotificationPostedMsg {
PackageUserKey packageUserKey;
- String notificationKey;
+ NotificationKeyData notificationKey;
boolean shouldBeFilteredOut;
NotificationPostedMsg(StatusBarNotification sbn) {
packageUserKey = PackageUserKey.fromNotification(sbn);
- notificationKey = sbn.getKey();
+ notificationKey = NotificationKeyData.fromNotification(sbn);
shouldBeFilteredOut = shouldBeFilteredOut(sbn);
}
}
@@ -178,16 +178,18 @@
@Override
public void onNotificationRemoved(final StatusBarNotification sbn) {
super.onNotificationRemoved(sbn);
- Pair<PackageUserKey, String> packageUserKeyAndNotificationKey
- = new Pair<>(PackageUserKey.fromNotification(sbn), sbn.getKey());
+ Pair<PackageUserKey, NotificationKeyData> packageUserKeyAndNotificationKey
+ = new Pair<>(PackageUserKey.fromNotification(sbn),
+ NotificationKeyData.fromNotification(sbn));
mWorkerHandler.obtainMessage(MSG_NOTIFICATION_REMOVED, packageUserKeyAndNotificationKey)
.sendToTarget();
}
/** This makes a potentially expensive binder call and should be run on a background thread. */
- public List<StatusBarNotification> getNotificationsForKeys(String[] keys) {
+ public List<StatusBarNotification> getNotificationsForKeys(List<NotificationKeyData> keys) {
StatusBarNotification[] notifications = NotificationListener.this
- .getActiveNotifications(keys);
+ .getActiveNotifications(NotificationKeyData.extractKeysOnly(keys)
+ .toArray(new String[keys.size()]));
return notifications == null ? Collections.EMPTY_LIST : Arrays.asList(notifications);
}
@@ -238,9 +240,10 @@
}
public interface NotificationsChangedListener {
- void onNotificationPosted(PackageUserKey postedPackageUserKey, String notificationKey,
- boolean shouldBeFilteredOut);
- void onNotificationRemoved(PackageUserKey removedPackageUserKey, String notificationKey);
+ void onNotificationPosted(PackageUserKey postedPackageUserKey,
+ NotificationKeyData notificationKey, boolean shouldBeFilteredOut);
+ void onNotificationRemoved(PackageUserKey removedPackageUserKey,
+ NotificationKeyData notificationKey);
void onNotificationFullRefresh(List<StatusBarNotification> activeNotifications);
}
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 1eac076..b2018b9 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -65,6 +65,7 @@
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.graphics.TriangleShape;
import com.android.launcher3.notification.NotificationItemView;
+import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutsItemView;
import com.android.launcher3.util.PackageUserKey;
@@ -138,9 +139,9 @@
}
ItemInfo itemInfo = (ItemInfo) icon.getTag();
List<String> shortcutIds = launcher.getPopupDataProvider().getShortcutIdsForItem(itemInfo);
- String[] notificationKeys = launcher.getPopupDataProvider()
+ List<NotificationKeyData> notificationKeys = launcher.getPopupDataProvider()
.getNotificationKeysForItem(itemInfo);
- if (shortcutIds.size() > 0 || notificationKeys.length > 0) {
+ if (shortcutIds.size() > 0 || notificationKeys.size() > 0) {
final PopupContainerWithArrow container =
(PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
R.layout.popup_container, launcher.getDragLayer(), false);
@@ -153,7 +154,7 @@
}
public void populateAndShow(final BubbleTextView originalIcon, final List<String> shortcutIds,
- final String[] notificationKeys) {
+ final List<NotificationKeyData> notificationKeys) {
final Resources resources = getResources();
final int arrowWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcuts_arrow_width);
final int arrowHeight = resources.getDimensionPixelSize(R.dimen.deep_shortcuts_arrow_height);
@@ -165,7 +166,7 @@
// Add dummy views first, and populate with real info when ready.
PopupPopulator.Item[] itemsToPopulate = PopupPopulator
.getItemsToPopulate(shortcutIds, notificationKeys);
- addDummyViews(originalIcon, itemsToPopulate, notificationKeys.length > 1);
+ addDummyViews(originalIcon, itemsToPopulate, notificationKeys.size() > 1);
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset);
@@ -176,7 +177,7 @@
mNotificationItemView = null;
mShortcutsItemView = null;
itemsToPopulate = PopupPopulator.reverseItems(itemsToPopulate);
- addDummyViews(originalIcon, itemsToPopulate, notificationKeys.length > 1);
+ addDummyViews(originalIcon, itemsToPopulate, notificationKeys.size() > 1);
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
orientAboutIcon(originalIcon, arrowHeight + arrowVerticalOffset);
@@ -606,7 +607,8 @@
removeNotification.start();
return;
}
- mNotificationItemView.trimNotifications(badgeInfo.getNotificationKeys());
+ mNotificationItemView.trimNotifications(NotificationKeyData.extractKeysOnly(
+ badgeInfo.getNotificationKeys()));
}
private ObjectAnimator createArrowScaleAnim(float scale) {
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index f0ccb1b..9c4faed 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.service.notification.StatusBarNotification;
+import android.support.annotation.NonNull;
import android.util.Log;
import com.android.launcher3.ItemInfo;
@@ -25,6 +26,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.notification.NotificationInfo;
+import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.util.ComponentKey;
@@ -58,33 +60,34 @@
}
@Override
- public void onNotificationPosted(PackageUserKey postedPackageUserKey, String notificationKey,
- boolean shouldBeFilteredOut) {
+ public void onNotificationPosted(PackageUserKey postedPackageUserKey,
+ NotificationKeyData notificationKey, boolean shouldBeFilteredOut) {
BadgeInfo badgeInfo = mPackageUserToBadgeInfos.get(postedPackageUserKey);
- boolean notificationWasAddedOrRemoved; // As opposed to updated.
+ boolean badgeShouldBeRefreshed;
if (badgeInfo == null) {
if (!shouldBeFilteredOut) {
BadgeInfo newBadgeInfo = new BadgeInfo(postedPackageUserKey);
- newBadgeInfo.addNotificationKeyIfNotExists(notificationKey);
+ newBadgeInfo.addOrUpdateNotificationKey(notificationKey);
mPackageUserToBadgeInfos.put(postedPackageUserKey, newBadgeInfo);
- notificationWasAddedOrRemoved = true;
+ badgeShouldBeRefreshed = true;
} else {
- notificationWasAddedOrRemoved = false;
+ badgeShouldBeRefreshed = false;
}
} else {
- notificationWasAddedOrRemoved = shouldBeFilteredOut
+ badgeShouldBeRefreshed = shouldBeFilteredOut
? badgeInfo.removeNotificationKey(notificationKey)
- : badgeInfo.addNotificationKeyIfNotExists(notificationKey);
+ : badgeInfo.addOrUpdateNotificationKey(notificationKey);
if (badgeInfo.getNotificationCount() == 0) {
mPackageUserToBadgeInfos.remove(postedPackageUserKey);
}
}
updateLauncherIconBadges(Utilities.singletonHashSet(postedPackageUserKey),
- notificationWasAddedOrRemoved);
+ badgeShouldBeRefreshed);
}
@Override
- public void onNotificationRemoved(PackageUserKey removedPackageUserKey, String notificationKey) {
+ public void onNotificationRemoved(PackageUserKey removedPackageUserKey,
+ NotificationKeyData notificationKey) {
BadgeInfo oldBadgeInfo = mPackageUserToBadgeInfos.get(removedPackageUserKey);
if (oldBadgeInfo != null && oldBadgeInfo.removeNotificationKey(notificationKey)) {
if (oldBadgeInfo.getNotificationCount() == 0) {
@@ -112,7 +115,8 @@
badgeInfo = new BadgeInfo(packageUserKey);
mPackageUserToBadgeInfos.put(packageUserKey, badgeInfo);
}
- badgeInfo.addNotificationKeyIfNotExists(notification.getKey());
+ badgeInfo.addOrUpdateNotificationKey(NotificationKeyData
+ .fromNotification(notification));
}
// Add and remove from updatedBadges so it contains the PackageUserKeys of updated badges.
@@ -146,17 +150,17 @@
* Updates the icons on launcher (workspace, folders, all apps) to refresh their badges.
* @param updatedBadges The packages whose badges should be refreshed (either a notification was
* added or removed, or the badge should show the notification icon).
- * @param addedOrRemoved An optional parameter that will allow us to only refresh badges that
- * updated (not added/removed) that have icons. If a badge updated
- * but it doesn't have an icon, then the badge number doesn't change.
+ * @param shouldRefresh An optional parameter that will allow us to only refresh badges that
+ * have actually changed. If a notification updated its content but not
+ * its count or icon, then the badge doesn't change.
*/
private void updateLauncherIconBadges(Set<PackageUserKey> updatedBadges,
- boolean addedOrRemoved) {
+ boolean shouldRefresh) {
Iterator<PackageUserKey> iterator = updatedBadges.iterator();
while (iterator.hasNext()) {
BadgeInfo badgeInfo = mPackageUserToBadgeInfos.get(iterator.next());
- if (badgeInfo != null && !updateBadgeIcon(badgeInfo) && !addedOrRemoved) {
- // The notification icon isn't used, and the badge wasn't added or removed
+ if (badgeInfo != null && !updateBadgeIcon(badgeInfo) && !shouldRefresh) {
+ // The notification icon isn't used, and the badge hasn't changed
// so there is no update to be made.
iterator.remove();
}
@@ -177,8 +181,9 @@
NotificationInfo notificationInfo = null;
NotificationListener notificationListener = NotificationListener.getInstanceIfConnected();
if (notificationListener != null && badgeInfo.getNotificationKeys().size() == 1) {
+ String onlyNotificationKey = badgeInfo.getNotificationKeys().get(0).notificationKey;
StatusBarNotification[] activeNotifications = notificationListener
- .getActiveNotifications(new String[] {badgeInfo.getNotificationKeys().get(0)});
+ .getActiveNotifications(new String[] {onlyNotificationKey});
if (activeNotifications.length == 1) {
notificationInfo = new NotificationInfo(mLauncher, activeNotifications[0]);
if (!notificationInfo.shouldShowIconInBadge()) {
@@ -216,15 +221,14 @@
return mPackageUserToBadgeInfos.get(PackageUserKey.fromItemInfo(info));
}
- public String[] getNotificationKeysForItem(ItemInfo info) {
+ public @NonNull List<NotificationKeyData> getNotificationKeysForItem(ItemInfo info) {
BadgeInfo badgeInfo = getBadgeInfoForItem(info);
- if (badgeInfo == null) { return new String[0]; }
- List<String> notificationKeys = badgeInfo.getNotificationKeys();
- return notificationKeys.toArray(new String[notificationKeys.size()]);
+ return badgeInfo == null ? Collections.EMPTY_LIST : badgeInfo.getNotificationKeys();
}
/** This makes a potentially expensive binder call and should be run on a background thread. */
- public List<StatusBarNotification> getStatusBarNotificationsForKeys(String[] notificationKeys) {
+ public @NonNull List<StatusBarNotification> getStatusBarNotificationsForKeys(
+ List<NotificationKeyData> notificationKeys) {
NotificationListener notificationListener = NotificationListener.getInstanceIfConnected();
return notificationListener == null ? Collections.EMPTY_LIST
: notificationListener.getNotificationsForKeys(notificationKeys);
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index 39c2db2..9b2141f 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -20,15 +20,18 @@
import android.os.Handler;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.notification.NotificationInfo;
import com.android.launcher3.notification.NotificationItemView;
-import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
@@ -36,6 +39,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Iterator;
import java.util.List;
/**
@@ -58,8 +62,9 @@
}
}
- public static Item[] getItemsToPopulate(List<String> shortcutIds, String[] notificationKeys) {
- boolean hasNotifications = notificationKeys.length > 0;
+ public static @NonNull Item[] getItemsToPopulate(@NonNull List<String> shortcutIds,
+ @NonNull List<NotificationKeyData> notificationKeys) {
+ boolean hasNotifications = notificationKeys.size() > 0;
int numNotificationItems = hasNotifications ? 1 : 0;
int numItems = Math.min(MAX_ITEMS, shortcutIds.size() + numNotificationItems);
Item[] items = new Item[numItems];
@@ -105,10 +110,22 @@
* We want the filter to include both static and dynamic shortcuts, so we always
* include NUM_DYNAMIC dynamic shortcuts, if at least that many are present.
*
+ * @param shortcutIdToRemoveFirst An id that should be filtered out first, if any.
* @return a subset of shortcuts, in sorted order, with size <= MAX_ITEMS.
*/
public static List<ShortcutInfoCompat> sortAndFilterShortcuts(
- List<ShortcutInfoCompat> shortcuts) {
+ List<ShortcutInfoCompat> shortcuts, @Nullable String shortcutIdToRemoveFirst) {
+ // Remove up to one specific shortcut before sorting and doing somewhat fancy filtering.
+ if (shortcutIdToRemoveFirst != null) {
+ Iterator<ShortcutInfoCompat> shortcutIterator = shortcuts.iterator();
+ while (shortcutIterator.hasNext()) {
+ if (shortcutIterator.next().getId().equals(shortcutIdToRemoveFirst)) {
+ shortcutIterator.remove();
+ break;
+ }
+ }
+ }
+
Collections.sort(shortcuts, SHORTCUT_RANK_COMPARATOR);
if (shortcuts.size() <= MAX_ITEMS) {
return shortcuts;
@@ -145,7 +162,8 @@
public static Runnable createUpdateRunnable(final Launcher launcher, ItemInfo originalInfo,
final Handler uiHandler, final PopupContainerWithArrow container,
final List<String> shortcutIds, final List<DeepShortcutView> shortcutViews,
- final String[] notificationKeys, final NotificationItemView notificationView) {
+ final List<NotificationKeyData> notificationKeys,
+ final NotificationItemView notificationView) {
final ComponentName activity = originalInfo.getTargetComponent();
final UserHandle user = originalInfo.user;
return new Runnable() {
@@ -162,9 +180,11 @@
uiHandler.post(new UpdateNotificationChild(notificationView, infos));
}
- final List<ShortcutInfoCompat> shortcuts = PopupPopulator.sortAndFilterShortcuts(
- DeepShortcutManager.getInstance(launcher).queryForShortcutsContainer(
- activity, shortcutIds, user));
+ List<ShortcutInfoCompat> shortcuts = DeepShortcutManager.getInstance(launcher)
+ .queryForShortcutsContainer(activity, shortcutIds, user);
+ String shortcutIdToDeDupe = notificationKeys.isEmpty() ? null
+ : notificationKeys.get(0).shortcutId;
+ shortcuts = PopupPopulator.sortAndFilterShortcuts(shortcuts, shortcutIdToDeDupe);
for (int i = 0; i < shortcuts.size() && i < shortcutViews.size(); i++) {
final ShortcutInfoCompat shortcut = shortcuts.get(i);
ShortcutInfo si = new ShortcutInfo(shortcut, launcher);
diff --git a/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
index dac2160..37047bb 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutInfoCompat.java
@@ -44,15 +44,12 @@
}
@TargetApi(Build.VERSION_CODES.N)
- public Intent makeIntent(Context context) {
- long serialNumber = UserManagerCompat.getInstance(context)
- .getSerialNumberForUser(getUserHandle());
+ public Intent makeIntent() {
return new Intent(Intent.ACTION_MAIN)
.addCategory(INTENT_CATEGORY)
.setComponent(getActivity())
.setPackage(getPackage())
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
- .putExtra(ItemInfo.EXTRA_PROFILE, serialNumber)
.putExtra(EXTRA_SHORTCUT_ID, getId());
}
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
index 85a000c..ce603c4 100644
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -121,7 +121,7 @@
.isQuietModeEnabled(user);
for (int i = 0; i < count; i++) {
LauncherActivityInstallInfo info = apps.get(i);
- AppInfo appInfo = new AppInfo(mContext, info.info, user, quietModeEnabled);
+ AppInfo appInfo = new AppInfo(info.info, user, quietModeEnabled);
mIconCache.getTitleAndIcon(appInfo, info.info, false /* useLowResIcon */);
ShortcutInfo si = appInfo.makeShortcut();
((info.installTime <= folderCreationTime) ? workFolderApps : homescreenApps).add(si);
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 7629f78..e12b2d4 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -76,7 +76,7 @@
public Intent getAppLaunchIntent(String pkg, UserHandle user) {
List<LauncherActivityInfo> activities = mLauncherApps.getActivityList(pkg, user);
return activities.isEmpty() ? null :
- AppInfo.makeLaunchIntent(mContext, activities.get(0), user);
+ AppInfo.makeLaunchIntent(activities.get(0));
}
/**
diff --git a/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java b/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
index 0843d9b..2ad9b35 100644
--- a/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
+++ b/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
@@ -58,11 +58,34 @@
MAX_ITEMS - NUM_DYNAMIC, NUM_DYNAMIC);
}
+ @Test
+ public void testDeDupeShortcutId() {
+ // Successfully remove one of the shortcuts
+ filterShortcutsAndAssertNumStaticAndDynamic(createShortcutsList(3, 0), 2, 0, generateId(true, 1));
+ filterShortcutsAndAssertNumStaticAndDynamic(createShortcutsList(0, 3), 0, 2, generateId(false, 1));
+ filterShortcutsAndAssertNumStaticAndDynamic(createShortcutsList(2, 2), 2, 1, generateId(false, 1));
+ filterShortcutsAndAssertNumStaticAndDynamic(createShortcutsList(2, 2), 1, 2, generateId(true, 1));
+ // Successfully keep all shortcuts when id doesn't exist
+ filterShortcutsAndAssertNumStaticAndDynamic(createShortcutsList(3, 0), 3, 0, generateId(false, 1));
+ filterShortcutsAndAssertNumStaticAndDynamic(createShortcutsList(3, 0), 3, 0, generateId(true, 4));
+ filterShortcutsAndAssertNumStaticAndDynamic(createShortcutsList(2, 2), 2, 2, generateId(false, 4));
+ filterShortcutsAndAssertNumStaticAndDynamic(createShortcutsList(2, 2), 2, 2, generateId(true, 4));
+ }
+
+ private String generateId(boolean isStatic, int rank) {
+ return (isStatic ? "static" : "dynamic") + rank;
+ }
+
private void filterShortcutsAndAssertNumStaticAndDynamic(
List<ShortcutInfoCompat> shortcuts, int expectedStatic, int expectedDynamic) {
+ filterShortcutsAndAssertNumStaticAndDynamic(shortcuts, expectedStatic, expectedDynamic, null);
+ }
+
+ private void filterShortcutsAndAssertNumStaticAndDynamic(List<ShortcutInfoCompat> shortcuts,
+ int expectedStatic, int expectedDynamic, String shortcutIdToRemove) {
Collections.shuffle(shortcuts);
List<ShortcutInfoCompat> filteredShortcuts = PopupPopulator.sortAndFilterShortcuts(
- shortcuts);
+ shortcuts, shortcutIdToRemove);
assertIsSorted(filteredShortcuts);
int numStatic = 0;
@@ -113,6 +136,7 @@
private class Shortcut extends ShortcutInfoCompat {
private boolean mIsStatic;
private int mRank;
+ private String mId;
public Shortcut(ShortcutInfo shortcutInfo) {
super(shortcutInfo);
@@ -122,6 +146,7 @@
this(null);
mIsStatic = isStatic;
mRank = rank;
+ mId = generateId(isStatic, rank);
}
@Override
@@ -138,5 +163,10 @@
public int getRank() {
return mRank;
}
+
+ @Override
+ public String getId() {
+ return mId;
+ }
}
}
\ No newline at end of file