summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMario Bertschler <bmario@google.com>2017-03-17 18:41:20 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2017-03-17 18:41:20 +0000
commitf71bb700aa436d0e8c8c9056627e3999e1f667d6 (patch)
treeea8a0f38e7ffc1f8b4651846fa9f55b90baea4f8
parent477d2cbfd8eb4d4bf5e48ae6515a2234bd0bde35 (diff)
parent817afa34472dba49b1dee0489da11f410ff09fcd (diff)
downloadandroid_packages_apps_Trebuchet-f71bb700aa436d0e8c8c9056627e3999e1f667d6.tar.gz
android_packages_apps_Trebuchet-f71bb700aa436d0e8c8c9056627e3999e1f667d6.tar.bz2
android_packages_apps_Trebuchet-f71bb700aa436d0e8c8c9056627e3999e1f667d6.zip
Merge "Show promise app icon in All Apps while installation process." into ub-launcher3-master
-rw-r--r--src/com/android/launcher3/AllAppsList.java56
-rw-r--r--src/com/android/launcher3/IconCache.java3
-rw-r--r--src/com/android/launcher3/LauncherModel.java32
-rw-r--r--src/com/android/launcher3/PromiseAppInfo.java47
-rw-r--r--src/com/android/launcher3/compat/PackageInstallerCompat.java31
-rw-r--r--src/com/android/launcher3/compat/PackageInstallerCompatVL.java69
-rw-r--r--src/com/android/launcher3/model/PackageInstallStateChangedTask.java44
-rw-r--r--src_flags/com/android/launcher3/config/FeatureFlags.java3
-rw-r--r--tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java5
9 files changed, 242 insertions, 48 deletions
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index 5b42cad96..d7f0180fa 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -18,10 +18,15 @@ package com.android.launcher3;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
+import android.os.Process;
import android.os.UserHandle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -69,7 +74,7 @@ public class AllAppsList {
if (!mAppFilter.shouldShowApp(info.componentName)) {
return;
}
- if (findActivity(data, info.componentName, info.user)) {
+ if (findAppInfo(info.componentName, info.user) != null) {
return;
}
mIconCache.getTitleAndIcon(info, activityInfo, true /* useLowResIcon */);
@@ -78,6 +83,25 @@ public class AllAppsList {
added.add(info);
}
+ public void addPromiseApp(Context context,
+ PackageInstallerCompat.PackageInstallInfo installInfo) {
+ ApplicationInfo applicationInfo = LauncherAppsCompat.getInstance(context)
+ .getApplicationInfo(installInfo.packageName, 0, Process.myUserHandle());
+ // only if not yet installed
+ if (applicationInfo == null) {
+ PromiseAppInfo info = new PromiseAppInfo(installInfo);
+ mIconCache.getTitleAndIcon(info, info.usingLowResIcon);
+ data.add(info);
+ added.add(info);
+ }
+ }
+
+ public void removePromiseApp(AppInfo appInfo) {
+ // the <em>removed</em> list is handled by the caller
+ // so not adding it here
+ data.remove(appInfo);
+ }
+
public void clear() {
data.clear();
// TODO: do we clear these too?
@@ -169,9 +193,7 @@ public class AllAppsList {
// Find enabled activities and add them to the adapter
// Also updates existing activities with new labels/icons
for (final LauncherActivityInfo info : matches) {
- AppInfo applicationInfo = findApplicationInfoLocked(
- info.getComponentName().getPackageName(), user,
- info.getComponentName().getClassName());
+ AppInfo applicationInfo = findAppInfo(info.getComponentName(), user);
if (applicationInfo == null) {
add(new AppInfo(context, info, user), info);
} else {
@@ -208,28 +230,14 @@ public class AllAppsList {
}
/**
- * Returns whether <em>apps</em> contains <em>component</em>.
- */
- private static boolean findActivity(ArrayList<AppInfo> apps, ComponentName component,
- UserHandle user) {
- final int N = apps.size();
- for (int i = 0; i < N; i++) {
- final AppInfo info = apps.get(i);
- if (info.user.equals(user) && info.componentName.equals(component)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Find an ApplicationInfo object for the given packageName and className.
+ * Find an AppInfo object for the given componentName
+ *
+ * @return the corresponding AppInfo or null
*/
- private AppInfo findApplicationInfoLocked(String packageName, UserHandle user,
- String className) {
+ private @Nullable AppInfo findAppInfo(@NonNull ComponentName componentName,
+ @NonNull UserHandle user) {
for (AppInfo info: data) {
- if (user.equals(info.user) && packageName.equals(info.componentName.getPackageName())
- && className.equals(info.componentName.getClassName())) {
+ if (componentName.equals(info.componentName) && user.equals(info.user)) {
return info;
}
}
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index 1f473a26f..a5552aafd 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -437,9 +437,10 @@ public class IconCache {
* Updates {@param application} only if a valid entry is found.
*/
public synchronized void updateTitleAndIcon(AppInfo application) {
+ boolean usePackageIcon = application instanceof PromiseAppInfo;
CacheEntry entry = cacheLocked(application.componentName,
Provider.<LauncherActivityInfo>of(null),
- application.user, false, application.usingLowResIcon);
+ application.user, usePackageIcon, application.usingLowResIcon);
if (entry.icon != null && !isDefaultIcon(entry.icon, application.user)) {
applyCacheEntry(entry, application);
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 35811d38a..707ec8642 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -25,7 +25,9 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
+import android.content.pm.PackageInstaller;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
@@ -573,6 +575,25 @@ public class LauncherModel extends BroadcastReceiver
screensUri, null, null, null, LauncherSettings.WorkspaceScreens.SCREEN_RANK));
}
+ public void onInstallSessionCreated(final PackageInstallInfo sessionInfo) {
+ enqueueModelUpdateTask(new ExtendedModelTask() {
+ @Override
+ public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
+ apps.addPromiseApp(app.getContext(), sessionInfo);
+ if (!apps.added.isEmpty()) {
+ final ArrayList<AppInfo> arrayList = new ArrayList<>(apps.added);
+ apps.added.clear();
+ scheduleCallbackTask(new CallbackTask() {
+ @Override
+ public void execute(Callbacks callbacks) {
+ callbacks.bindAppsAdded(null, null, null, arrayList);
+ }
+ });
+ }
+ }
+ });
+ }
+
/**
* Runnable for the thread that loads the contents of the launcher:
* - workspace icons
@@ -1691,10 +1712,21 @@ public class LauncherModel extends BroadcastReceiver
});
}
}
+
+ if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
+ // get all active sessions and add them to the all apps list
+ PackageInstallerCompat installer = PackageInstallerCompat.getInstance(mContext);
+ for (PackageInstaller.SessionInfo info : installer.getAllVerifiedSessions()) {
+ mBgAllAppsList.addPromiseApp(mContext,
+ PackageInstallInfo.fromInstallingState(info));
+ }
+ }
+
// Huh? Shouldn't this be inside the Runnable below?
final ArrayList<AppInfo> added = mBgAllAppsList.added;
mBgAllAppsList.added = new ArrayList<AppInfo>();
+
// Post callback on main thread
mUiExecutor.execute(new Runnable() {
public void run() {
diff --git a/src/com/android/launcher3/PromiseAppInfo.java b/src/com/android/launcher3/PromiseAppInfo.java
new file mode 100644
index 000000000..04ba1d366
--- /dev/null
+++ b/src/com/android/launcher3/PromiseAppInfo.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+import android.content.Intent;
+import android.support.annotation.NonNull;
+
+import com.android.launcher3.compat.PackageInstallerCompat;
+
+public class PromiseAppInfo extends AppInfo {
+
+ public int level = 0;
+
+ public PromiseAppInfo(@NonNull PackageInstallerCompat.PackageInstallInfo installInfo) {
+ componentName = installInfo.componentName;
+ intent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setComponent(componentName)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ }
+
+ @Override
+ public ShortcutInfo makeShortcut() {
+ ShortcutInfo shortcut = new ShortcutInfo(this);
+ shortcut.setInstallProgress(level);
+ // We need to update the component name when the apk is installed
+ shortcut.status |= ShortcutInfo.FLAG_AUTOINTALL_ICON;
+ // Since the user is manually placing it on homescreen, it should not be auto-removed later
+ shortcut.status |= ShortcutInfo.FLAG_RESTORE_STARTED;
+ return shortcut;
+ }
+}
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java
index c7fe0cec8..112cca540 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompat.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java
@@ -16,9 +16,13 @@
package com.android.launcher3.compat;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageInstaller;
+import android.support.annotation.NonNull;
import java.util.HashMap;
+import java.util.List;
public abstract class PackageInstallerCompat {
@@ -46,19 +50,34 @@ public abstract class PackageInstallerCompat {
public abstract void onStop();
public static final class PackageInstallInfo {
+ public final ComponentName componentName;
public final String packageName;
+ public final int state;
+ public final int progress;
- public int state;
- public int progress;
-
- public PackageInstallInfo(String packageName) {
- this.packageName = packageName;
+ private PackageInstallInfo(@NonNull PackageInstaller.SessionInfo info) {
+ this.state = STATUS_INSTALLING;
+ this.packageName = info.getAppPackageName();
+ this.componentName = new ComponentName(packageName, "");
+ this.progress = (int) (info.getProgress() * 100f);
}
public PackageInstallInfo(String packageName, int state, int progress) {
- this.packageName = packageName;
this.state = state;
+ this.packageName = packageName;
+ this.componentName = new ComponentName(packageName, "");
this.progress = progress;
}
+
+ public static PackageInstallInfo fromInstallingState(PackageInstaller.SessionInfo info) {
+ return new PackageInstallInfo(info);
+ }
+
+ public static PackageInstallInfo fromState(int state, String packageName) {
+ return new PackageInstallInfo(packageName, state, 0 /* progress */);
+ }
+
}
+
+ public abstract List<PackageInstaller.SessionInfo> getAllVerifiedSessions();
}
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index b87582f55..d7cd032f7 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -17,6 +17,7 @@
package com.android.launcher3.compat;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionCallback;
import android.content.pm.PackageInstaller.SessionInfo;
@@ -28,23 +29,31 @@ import android.util.SparseArray;
import com.android.launcher3.IconCache;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.Thunk;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
public class PackageInstallerCompatVL extends PackageInstallerCompat {
+ private static final boolean DEBUG = false;
+
@Thunk final SparseArray<String> mActiveSessions = new SparseArray<>();
@Thunk final PackageInstaller mInstaller;
private final IconCache mCache;
private final Handler mWorker;
+ private final Context mAppContext;
+ private final HashMap<String,Boolean> mSessionVerifiedMap = new HashMap<>();
PackageInstallerCompatVL(Context context) {
+ mAppContext = context.getApplicationContext();
mInstaller = context.getPackageManager().getPackageInstaller();
mCache = LauncherAppState.getInstance(context).getIconCache();
mWorker = new Handler(LauncherModel.getWorkerLooper());
-
mInstaller.registerSessionCallback(mCallback, mWorker);
}
@@ -52,7 +61,7 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
public HashMap<String, Integer> updateAndGetActiveSessionCache() {
HashMap<String, Integer> activePackages = new HashMap<>();
UserHandle user = Process.myUserHandle();
- for (SessionInfo info : mInstaller.getAllSessions()) {
+ for (SessionInfo info : getAllVerifiedSessions()) {
addSessionInfoToCache(info, user);
if (info.getAppPackageName() != null) {
activePackages.put(info.getAppPackageName(), (int) (info.getProgress() * 100));
@@ -86,7 +95,14 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
@Override
public void onCreated(int sessionId) {
- pushSessionDisplayToLauncher(sessionId);
+ SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId);
+ if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS && sessionInfo != null) {
+ LauncherAppState app = LauncherAppState.getInstanceNoCreate();
+ if (app != null) {
+ app.getModel().onInstallSessionCreated(
+ PackageInstallInfo.fromInstallingState(sessionInfo));
+ }
+ }
}
@Override
@@ -97,18 +113,17 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
mActiveSessions.remove(sessionId);
if (packageName != null) {
- sendUpdate(new PackageInstallInfo(packageName,
- success ? STATUS_INSTALLED : STATUS_FAILED, 0));
+ sendUpdate(PackageInstallInfo.fromState(
+ success ? STATUS_INSTALLED : STATUS_FAILED,
+ packageName));
}
}
@Override
public void onProgressChanged(int sessionId, float progress) {
- SessionInfo session = mInstaller.getSessionInfo(sessionId);
+ SessionInfo session = verify(mInstaller.getSessionInfo(sessionId));
if (session != null && session.getAppPackageName() != null) {
- sendUpdate(new PackageInstallInfo(session.getAppPackageName(),
- STATUS_INSTALLING,
- (int) (session.getProgress() * 100)));
+ sendUpdate(PackageInstallInfo.fromInstallingState(session));
}
}
@@ -120,16 +135,46 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
pushSessionDisplayToLauncher(sessionId);
}
- private void pushSessionDisplayToLauncher(int sessionId) {
- SessionInfo session = mInstaller.getSessionInfo(sessionId);
+ private SessionInfo pushSessionDisplayToLauncher(int sessionId) {
+ SessionInfo session = verify(mInstaller.getSessionInfo(sessionId));
if (session != null && session.getAppPackageName() != null) {
+ mActiveSessions.put(sessionId, session.getAppPackageName());
addSessionInfoToCache(session, Process.myUserHandle());
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
-
if (app != null) {
app.getModel().updateSessionDisplayInfo(session.getAppPackageName());
}
+ return session;
}
+ return null;
}
};
+
+ private PackageInstaller.SessionInfo verify(PackageInstaller.SessionInfo sessionInfo) {
+ if (sessionInfo == null || sessionInfo.getInstallerPackageName() == null) {
+ return null;
+ }
+ String pkg = sessionInfo.getAppPackageName();
+ synchronized (mSessionVerifiedMap) {
+ if (!mSessionVerifiedMap.containsKey(pkg)) {
+ LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mAppContext);
+ boolean hasSystemFlag = launcherApps.getApplicationInfo(pkg,
+ ApplicationInfo.FLAG_SYSTEM, Process.myUserHandle()) != null;
+ mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag);
+ }
+ }
+ return mSessionVerifiedMap.get(pkg) ? sessionInfo : null;
+ }
+
+ @Override
+ public List<SessionInfo> getAllVerifiedSessions() {
+ List<SessionInfo> list = new ArrayList<>(mInstaller.getAllSessions());
+ Iterator<SessionInfo> it = list.iterator();
+ while (it.hasNext()) {
+ if (verify(it.next()) == null) {
+ it.remove();
+ }
+ }
+ return list;
+ }
}
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index 5d04325e8..9c5f18917 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -18,15 +18,18 @@ package com.android.launcher3.model;
import android.content.ComponentName;
import com.android.launcher3.AllAppsList;
+import com.android.launcher3.AppInfo;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherModel.CallbackTask;
import com.android.launcher3.LauncherModel.Callbacks;
+import com.android.launcher3.PromiseAppInfo;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
+import java.util.ArrayList;
import java.util.HashSet;
/**
@@ -47,6 +50,46 @@ public class PackageInstallStateChangedTask extends ExtendedModelTask {
return;
}
+ synchronized (apps) {
+ final ArrayList<AppInfo> updated = new ArrayList<>();
+ final ArrayList<AppInfo> removed = new ArrayList<>();
+ for (int i=0; i < apps.size(); i++) {
+ final AppInfo appInfo = apps.get(i);
+ final ComponentName tgtComp = appInfo.getTargetComponent();
+ if (tgtComp != null && tgtComp.getPackageName().equals(mInstallInfo.packageName)) {
+ if (appInfo instanceof PromiseAppInfo) {
+ final PromiseAppInfo promiseAppInfo = (PromiseAppInfo) appInfo;
+ if (mInstallInfo.state == PackageInstallerCompat.STATUS_INSTALLING) {
+ promiseAppInfo.level = mInstallInfo.progress;
+ updated.add(appInfo);
+ } else if (mInstallInfo.state == PackageInstallerCompat.STATUS_FAILED
+ || mInstallInfo.state == PackageInstallerCompat.STATUS_INSTALLED) {
+ apps.removePromiseApp(appInfo);
+ removed.add(appInfo);
+ }
+ }
+ }
+ }
+ if (!updated.isEmpty()) {
+ scheduleCallbackTask(new CallbackTask() {
+ @Override
+ public void execute(Callbacks callbacks) {
+ // TODO: this currently causes unnecessary relayouts
+ // we need to introduce a new bindPromiseAppsChanged
+ callbacks.bindAppsUpdated(updated);
+ }
+ });
+ }
+ if (!removed.isEmpty()) {
+ scheduleCallbackTask(new CallbackTask() {
+ @Override
+ public void execute(Callbacks callbacks) {
+ callbacks.bindAppInfosRemoved(removed);
+ }
+ });
+ }
+ }
+
synchronized (dataModel) {
final HashSet<ItemInfo> updates = new HashSet<>();
for (ItemInfo info : dataModel.itemsIdMap) {
@@ -56,7 +99,6 @@ public class PackageInstallStateChangedTask extends ExtendedModelTask {
if (si.isPromise() && (cn != null)
&& mInstallInfo.packageName.equals(cn.getPackageName())) {
si.setInstallProgress(mInstallInfo.progress);
-
if (mInstallInfo.state == PackageInstallerCompat.STATUS_FAILED) {
// Mark this info as broken.
si.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
diff --git a/src_flags/com/android/launcher3/config/FeatureFlags.java b/src_flags/com/android/launcher3/config/FeatureFlags.java
index 87e987162..9e2074812 100644
--- a/src_flags/com/android/launcher3/config/FeatureFlags.java
+++ b/src_flags/com/android/launcher3/config/FeatureFlags.java
@@ -36,7 +36,8 @@ public final class FeatureFlags {
public static boolean LAUNCHER3_DIRECT_SCROLL = true;
// When enabled while all-apps open, the soft input will be set to adjust resize .
public static boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = false;
-
+ // When enabled the promise icon is visible in all apps while installation an app.
+ public static boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false;
// Feature flag to enable moving the QSB on the 0th screen of the workspace.
public static final boolean QSB_ON_FIRST_SCREEN = true;
diff --git a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
index d6555620c..ed893c42e 100644
--- a/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
@@ -21,9 +21,8 @@ public class PackageInstallStateChangedTaskTest extends BaseModelUpdateTaskTestC
}
private PackageInstallStateChangedTask newTask(String pkg, int progress) {
- PackageInstallInfo installInfo = new PackageInstallInfo(pkg);
- installInfo.progress = progress;
- installInfo.state = PackageInstallerCompat.STATUS_INSTALLING;
+ int state = PackageInstallerCompat.STATUS_INSTALLING;
+ PackageInstallInfo installInfo = new PackageInstallInfo(pkg, state, progress);
return new PackageInstallStateChangedTask(installInfo);
}