summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3
diff options
context:
space:
mode:
authorMario Bertschler <bmario@google.com>2017-03-15 11:56:47 -0700
committerMario Bertschler <bmario@google.com>2017-03-17 09:21:35 -0700
commit817afa34472dba49b1dee0489da11f410ff09fcd (patch)
tree5fae380bbe02dc661eb1e071f87d9426c14e7da3 /src/com/android/launcher3
parent04030d5a449cb251fb8db2f74d054c4f3a4a608b (diff)
downloadandroid_packages_apps_Trebuchet-817afa34472dba49b1dee0489da11f410ff09fcd.tar.gz
android_packages_apps_Trebuchet-817afa34472dba49b1dee0489da11f410ff09fcd.tar.bz2
android_packages_apps_Trebuchet-817afa34472dba49b1dee0489da11f410ff09fcd.zip
Show promise app icon in All Apps while installation process.
This CL only modifies the model and is behind a feature flag which per default is set to false. The app icon will appear as a promise icon, it reacts on icon or label changes and the icon will be remove on finishing the installation process. With this CL the progress of the installation process is not visible. Bug: 23952570 Change-Id: I510825d0b0b1b01eb14f7e50f0a2358b0d8b99b5
Diffstat (limited to 'src/com/android/launcher3')
-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
7 files changed, 238 insertions, 44 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;