summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--proguard.flags7
-rw-r--r--src/com/android/launcher3/AllAppsList.java19
-rw-r--r--src/com/android/launcher3/AppInfo.java15
-rw-r--r--src/com/android/launcher3/BubbleTextView.java16
-rw-r--r--src/com/android/launcher3/ItemInfo.java7
-rw-r--r--src/com/android/launcher3/Launcher.java14
-rw-r--r--src/com/android/launcher3/LauncherModel.java41
-rw-r--r--src/com/android/launcher3/ShortcutInfo.java11
-rw-r--r--src/com/android/launcher3/compat/LauncherActivityInfoCompat.java2
-rw-r--r--src/com/android/launcher3/compat/LauncherAppsCompat.java9
-rw-r--r--src/com/android/launcher3/compat/LauncherAppsCompatV16.java4
-rw-r--r--src/com/android/launcher3/compat/LauncherAppsCompatVL.java14
-rw-r--r--src/com/android/launcher3/compat/LauncherAppsCompatVN.java57
13 files changed, 199 insertions, 17 deletions
diff --git a/proguard.flags b/proguard.flags
index 05963f7bc..19d2f0c50 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -70,3 +70,10 @@
public float getBackgroundAlpha();
public void setBackgroundAlpha(float);
}
+
+# Proguard will strip new callbacks in LauncherApps.Callback from
+# WrappedCallback if compiled against an older SDK. Don't let this happen.
+-keep class com.android.launcher3.compat.** {
+ *;
+}
+
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index 3b25dca34..f76c18512 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -118,6 +118,25 @@ class AllAppsList {
}
}
+ /**
+ * Suspend the apps for the given apk identified by packageName.
+ */
+ public void suspendPackage(String packageName, UserHandleCompat user, boolean suspend) {
+ final List<AppInfo> data = this.data;
+ for (int i = data.size() - 1; i >= 0; i--) {
+ AppInfo info = data.get(i);
+ final ComponentName component = info.intent.getComponent();
+ if (info.user.equals(user) && packageName.equals(component.getPackageName())) {
+ if (suspend) {
+ info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ } else {
+ info.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ }
+ modified.add(info);
+ }
+ }
+ }
+
public void updateIconsAndLabels(HashSet<String> packages, UserHandleCompat user,
ArrayList<AppInfo> outUpdates) {
for (AppInfo info : data) {
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index 1923df76a..32be12f01 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -56,6 +56,11 @@ public class AppInfo extends ItemInfo {
int flags = 0;
+ /**
+ * {@see ShortcutInfo#isDisabled}
+ */
+ int isDisabled = ShortcutInfo.DEFAULT;
+
AppInfo() {
itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
}
@@ -75,8 +80,10 @@ public class AppInfo extends ItemInfo {
IconCache iconCache) {
this.componentName = info.getComponentName();
this.container = ItemInfo.NO_ID;
-
flags = initFlags(info);
+ if ((info.getApplicationInfo().flags & LauncherActivityInfoCompat.FLAG_SUSPENDED) != 0) {
+ isDisabled |= ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ }
iconCache.getTitleAndIcon(this, info, true /* useLowResIcon */);
intent = makeLaunchIntent(context, info, user);
this.user = user;
@@ -101,6 +108,7 @@ public class AppInfo extends ItemInfo {
title = Utilities.trim(info.title);
intent = new Intent(info.intent);
flags = info.flags;
+ isDisabled = info.isDisabled;
iconBitmap = info.iconBitmap;
}
@@ -140,4 +148,9 @@ public class AppInfo extends ItemInfo {
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
.putExtra(EXTRA_PROFILE, serialNumber);
}
+
+ @Override
+ public boolean isDisabled() {
+ return isDisabled != 0;
+ }
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index ce7e39252..8842d5cdd 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -150,7 +150,7 @@ public class BubbleTextView extends TextView
Bitmap b = info.getIcon(iconCache);
FastBitmapDrawable iconDrawable = mLauncher.createIconDrawable(b);
- if (info.isDisabled != 0) {
+ if (info.isDisabled()) {
iconDrawable.setState(FastBitmapDrawable.State.DISABLED);
}
setIcon(iconDrawable, mIconSize);
@@ -166,7 +166,11 @@ public class BubbleTextView extends TextView
}
public void applyFromApplicationInfo(AppInfo info) {
- setIcon(mLauncher.createIconDrawable(info.iconBitmap), mIconSize);
+ FastBitmapDrawable iconDrawable = mLauncher.createIconDrawable(info.iconBitmap);
+ if (info.isDisabled()) {
+ iconDrawable.setState(FastBitmapDrawable.State.DISABLED);
+ }
+ setIcon(iconDrawable, mIconSize);
setText(info.title);
if (info.contentDescription != null) {
setContentDescription(info.contentDescription);
@@ -250,11 +254,11 @@ public class BubbleTextView extends TextView
private void updateIconState() {
if (mIcon instanceof FastBitmapDrawable) {
FastBitmapDrawable d = (FastBitmapDrawable) mIcon;
- if (isPressed() || mStayPressed) {
- d.animateState(FastBitmapDrawable.State.PRESSED);
- } else if (getTag() instanceof ShortcutInfo
- && ((ShortcutInfo) getTag()).isDisabled != 0) {
+ if (getTag() instanceof ItemInfo
+ && ((ItemInfo) getTag()).isDisabled()) {
d.animateState(FastBitmapDrawable.State.DISABLED);
+ } else if (isPressed() || mStayPressed) {
+ d.animateState(FastBitmapDrawable.State.PRESSED);
} else {
d.animateState(FastBitmapDrawable.State.NORMAL);
}
diff --git a/src/com/android/launcher3/ItemInfo.java b/src/com/android/launcher3/ItemInfo.java
index aa5a18d3c..1ba09e1eb 100644
--- a/src/com/android/launcher3/ItemInfo.java
+++ b/src/com/android/launcher3/ItemInfo.java
@@ -198,4 +198,11 @@ public class ItemInfo {
+ " screen=" + screenId + " cellX=" + cellX + " cellY=" + cellY + " spanX=" + spanX
+ " spanY=" + spanY + " user=" + user + ")";
}
+
+ /**
+ * Whether this item is disabled.
+ */
+ public boolean isDisabled() {
+ return false;
+ }
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0df30841d..6a548c38d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2652,12 +2652,16 @@ public class Launcher extends Activity
final ShortcutInfo shortcut = (ShortcutInfo) tag;
if (shortcut.isDisabled != 0) {
- int error = R.string.activity_not_available;
- if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_SAFEMODE) != 0) {
- error = R.string.safemode_shortcut_error;
+ if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_SUSPENDED) != 0) {
+ // Launch activity anyway, framework will tell the user why the app is suspended.
+ } else {
+ int error = R.string.activity_not_available;
+ if ((shortcut.isDisabled & ShortcutInfo.FLAG_DISABLED_SAFEMODE) != 0) {
+ error = R.string.safemode_shortcut_error;
+ }
+ Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
+ return;
}
- Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
- return;
}
// Check for abandoned promise
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 92ef3eae7..52d2dca65 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -1198,6 +1198,20 @@ public class LauncherModel extends BroadcastReceiver
}
}
+ @Override
+ public void onPackagesSuspended(String[] packageNames, UserHandleCompat user) {
+ enqueuePackageUpdated(new PackageUpdatedTask(
+ PackageUpdatedTask.OP_SUSPEND, packageNames,
+ user));
+ }
+
+ @Override
+ public void onPackagesUnsuspended(String[] packageNames, UserHandleCompat user) {
+ enqueuePackageUpdated(new PackageUpdatedTask(
+ PackageUpdatedTask.OP_UNSUSPEND, packageNames,
+ user));
+ }
+
/**
* Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and
* ACTION_PACKAGE_CHANGED.
@@ -1777,6 +1791,11 @@ public class LauncherModel extends BroadcastReceiver
restoredRows.add(id);
restored = false;
}
+ boolean isSuspended = launcherApps.isPackageSuspendedForProfile(
+ cn.getPackageName(), user);
+ if (isSuspended) {
+ disabledState = ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ }
} else if (validPkg) {
intent = null;
if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {
@@ -2892,6 +2911,8 @@ public class LauncherModel extends BroadcastReceiver
public static final int OP_UPDATE = 2;
public static final int OP_REMOVE = 3; // uninstlled
public static final int OP_UNAVAILABLE = 4; // external media unmounted
+ public static final int OP_SUSPEND = 5; // package suspended
+ public static final int OP_UNSUSPEND = 6; // package unsuspended
public PackageUpdatedTask(int op, String[] packages, UserHandleCompat user) {
@@ -2949,6 +2970,15 @@ public class LauncherModel extends BroadcastReceiver
mApp.getWidgetCache().removePackage(packages[i], mUser);
}
break;
+ case OP_SUSPEND:
+ case OP_UNSUSPEND:
+ boolean suspend = mOp == OP_SUSPEND;
+ for (int i=0; i<N; i++) {
+ if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.suspendPackage "
+ + suspend + " " + packages[i]);
+ mBgAllAppsList.suspendPackage(packages[i], mUser, suspend);
+ }
+ break;
}
ArrayList<AppInfo> added = null;
@@ -3001,7 +3031,7 @@ public class LauncherModel extends BroadcastReceiver
}
// Update shortcut infos
- if (mOp == OP_ADD || mOp == OP_UPDATE) {
+ if (mOp == OP_ADD || mOp == OP_UPDATE || mOp == OP_UNSUSPEND) {
final ArrayList<ShortcutInfo> updatedShortcuts = new ArrayList<ShortcutInfo>();
final ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<ShortcutInfo>();
final ArrayList<LauncherAppWidgetInfo> widgets = new ArrayList<LauncherAppWidgetInfo>();
@@ -3014,6 +3044,11 @@ public class LauncherModel extends BroadcastReceiver
boolean infoUpdated = false;
boolean shortcutUpdated = false;
+ if (mOp == OP_UNSUSPEND) {
+ si.isDisabled &= ~ ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ infoUpdated = true;
+ }
+
// Update shortcuts which use iconResource.
if ((si.iconResource != null)
&& packageSet.contains(si.iconResource.packageName)) {
@@ -3139,7 +3174,7 @@ public class LauncherModel extends BroadcastReceiver
final ArrayList<String> removedPackageNames =
new ArrayList<String>();
- if (mOp == OP_REMOVE || mOp == OP_UNAVAILABLE) {
+ if (mOp == OP_REMOVE || mOp == OP_UNAVAILABLE || mOp == OP_SUSPEND) {
// Mark all packages in the broadcast to be removed
removedPackageNames.addAll(Arrays.asList(packages));
} else if (mOp == OP_UPDATE) {
@@ -3155,6 +3190,8 @@ public class LauncherModel extends BroadcastReceiver
final int removeReason;
if (mOp == OP_UNAVAILABLE) {
removeReason = ShortcutInfo.FLAG_DISABLED_NOT_AVAILABLE;
+ } else if (mOp == OP_SUSPEND) {
+ removeReason = ShortcutInfo.FLAG_DISABLED_SUSPENDED;
} else {
// Remove all the components associated with this package
for (String pn : removedPackageNames) {
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index baa3cd02c..0d6708bfc 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -112,6 +112,11 @@ public class ShortcutInfo extends ItemInfo {
public static final int FLAG_DISABLED_NOT_AVAILABLE = 2;
/**
+ * Indicates that the icon is disabled as the app is suspended
+ */
+ public static final int FLAG_DISABLED_SUSPENDED = 4;
+
+ /**
* Could be disabled, if the the app is installed but unavailable (eg. in safe mode or when
* sd-card is not available).
*/
@@ -177,6 +182,7 @@ public class ShortcutInfo extends ItemInfo {
intent = new Intent(info.intent);
customIcon = false;
flags = info.flags;
+ isDisabled = info.isDisabled;
}
public void setIcon(Bitmap b) {
@@ -278,5 +284,10 @@ public class ShortcutInfo extends ItemInfo {
shortcut.flags = AppInfo.initFlags(info);
return shortcut;
}
+
+ @Override
+ public boolean isDisabled() {
+ return isDisabled != 0;
+ }
}
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
index 0bc9588aa..aaf756eda 100644
--- a/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
+++ b/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
@@ -24,6 +24,8 @@ import android.graphics.drawable.Drawable;
public abstract class LauncherActivityInfoCompat {
+ public static final int FLAG_SUSPENDED = 1<<30;
+
LauncherActivityInfoCompat() {
}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index 95e3ba902..da3eb8fee 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -42,6 +42,8 @@ public abstract class LauncherAppsCompat {
void onPackageChanged(String packageName, UserHandleCompat user);
void onPackagesAvailable(String[] packageNames, UserHandleCompat user, boolean replacing);
void onPackagesUnavailable(String[] packageNames, UserHandleCompat user, boolean replacing);
+ void onPackagesSuspended(String[] packageNames, UserHandleCompat user);
+ void onPackagesUnsuspended(String[] packageNames, UserHandleCompat user);
}
protected LauncherAppsCompat() {
@@ -53,7 +55,9 @@ public abstract class LauncherAppsCompat {
public static LauncherAppsCompat getInstance(Context context) {
synchronized (sInstanceLock) {
if (sInstance == null) {
- if (Utilities.ATLEAST_LOLLIPOP) {
+ if (Utilities.isNycOrAbove()) {
+ sInstance = new LauncherAppsCompatVN(context.getApplicationContext());
+ } else if (Utilities.ATLEAST_LOLLIPOP) {
sInstance = new LauncherAppsCompatVL(context.getApplicationContext());
} else {
sInstance = new LauncherAppsCompatV16(context.getApplicationContext());
@@ -75,6 +79,7 @@ public abstract class LauncherAppsCompat {
public abstract boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user);
public abstract boolean isActivityEnabledForProfile(ComponentName component,
UserHandleCompat user);
+ public abstract boolean isPackageSuspendedForProfile(String packageName, UserHandleCompat user);
public boolean isAppEnabled(PackageManager pm, String packageName, int flags) {
try {
@@ -84,4 +89,4 @@ public abstract class LauncherAppsCompat {
return false;
}
}
-} \ No newline at end of file
+}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
index 339c457e1..2d0778d30 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java
@@ -126,6 +126,10 @@ public class LauncherAppsCompatV16 extends LauncherAppsCompat {
}
}
+ public boolean isPackageSuspendedForProfile(String packageName, UserHandleCompat user) {
+ return false;
+ }
+
private void unregisterForPackageIntents() {
mContext.unregisterReceiver(mPackageMonitor);
}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
index fbf91b548..7270d023b 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -36,7 +36,7 @@ import java.util.Map;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class LauncherAppsCompatVL extends LauncherAppsCompat {
- private LauncherApps mLauncherApps;
+ protected LauncherApps mLauncherApps;
private Map<OnAppsChangedCallbackCompat, WrappedCallback> mCallbacks
= new HashMap<OnAppsChangedCallbackCompat, WrappedCallback>();
@@ -106,6 +106,10 @@ public class LauncherAppsCompatVL extends LauncherAppsCompat {
return mLauncherApps.isActivityEnabled(component, user.getUser());
}
+ public boolean isPackageSuspendedForProfile(String packageName, UserHandleCompat user) {
+ return false;
+ }
+
private static class WrappedCallback extends LauncherApps.Callback {
private LauncherAppsCompat.OnAppsChangedCallbackCompat mCallback;
@@ -134,6 +138,14 @@ public class LauncherAppsCompatVL extends LauncherAppsCompat {
mCallback.onPackagesUnavailable(packageNames, UserHandleCompat.fromUser(user),
replacing);
}
+
+ public void onPackagesSuspended(String[] packageNames, UserHandle user) {
+ mCallback.onPackagesSuspended(packageNames, UserHandleCompat.fromUser(user));
+ }
+
+ public void onPackagesUnsuspended(String[] packageNames, UserHandle user) {
+ mCallback.onPackagesUnsuspended(packageNames, UserHandleCompat.fromUser(user));
+ }
}
}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVN.java b/src/com/android/launcher3/compat/LauncherAppsCompatVN.java
new file mode 100644
index 000000000..0d883b6fd
--- /dev/null
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVN.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 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.compat;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+//TODO: Once gogole3 SDK is updated to N, add @TargetApi(Build.VERSION_CODES.N)
+public class LauncherAppsCompatVN extends LauncherAppsCompatVL {
+
+ private static final String TAG = "LauncherAppsCompatVN";
+
+ LauncherAppsCompatVN(Context context) {
+ super(context);
+ }
+
+ @Override
+ public boolean isPackageSuspendedForProfile(String packageName, UserHandleCompat user) {
+ if (user != null && packageName != null) {
+ try {
+ //TODO: Replace with proper API call once google3 SDK is updated.
+ Method getApplicationInfoMethod = LauncherApps.class.getMethod("getApplicationInfo",
+ String.class, int.class, UserHandle.class);
+
+ ApplicationInfo info = (ApplicationInfo) getApplicationInfoMethod.invoke(
+ mLauncherApps, packageName, 0, user.getUser());
+ if (info != null) {
+ return (info.flags & LauncherActivityInfoCompat.FLAG_SUSPENDED) != 0;
+ }
+ } catch (NoSuchMethodError | NoSuchMethodException | IllegalAccessException
+ | IllegalArgumentException | InvocationTargetException e) {
+ Log.e(TAG, "Running on N without getApplicationInfo", e);
+ }
+ }
+ return false;
+ }
+}