Merging from ub-launcher3-qt-qpr1-dev @ build 5834630
Test: manual, presubmit on the source branch http://x20/teams/android-sysui/merge/ub-launcher3-qt-qpr1-dev_5834630.html Change-Id: I39968f831d707800207303e7661193fd74e56124
This commit is contained in:
@@ -25,11 +25,13 @@ import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.MainThreadExecutor;
|
||||
import com.android.launcher3.logging.UserEventDispatcher;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.userevent.nano.LauncherLogProto;
|
||||
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
@@ -162,6 +164,9 @@ public class OverviewCommandHelper {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "RecentsActivityCommand.run");
|
||||
}
|
||||
long elapsedTime = mCreateTime - mLastToggleTime;
|
||||
mLastToggleTime = mCreateTime;
|
||||
|
||||
|
||||
@@ -16,11 +16,6 @@
|
||||
|
||||
package com.android.quickstep.logging;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.stats.launcher.nano.LauncherExtension;
|
||||
import android.stats.launcher.nano.LauncherTarget;
|
||||
|
||||
import static android.stats.launcher.nano.Launcher.ALLAPPS;
|
||||
import static android.stats.launcher.nano.Launcher.HOME;
|
||||
import static android.stats.launcher.nano.Launcher.LAUNCH_APP;
|
||||
@@ -29,6 +24,11 @@ import static android.stats.launcher.nano.Launcher.DISMISS_TASK;
|
||||
import static android.stats.launcher.nano.Launcher.BACKGROUND;
|
||||
import static android.stats.launcher.nano.Launcher.OVERVIEW;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.stats.launcher.nano.Launcher;
|
||||
import android.stats.launcher.nano.LauncherExtension;
|
||||
import android.stats.launcher.nano.LauncherTarget;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.ItemInfo;
|
||||
@@ -39,8 +39,6 @@ import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.systemui.shared.system.StatsLogCompat;
|
||||
import com.google.protobuf.nano.MessageNano;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* This method calls the StatsLog hidden method until they are made available public.
|
||||
*
|
||||
@@ -85,6 +83,17 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||
MessageNano.toByteArray(ext), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logSwipeOnContainer(boolean isSwipingToLeft, int pageId) {
|
||||
LauncherExtension ext = new LauncherExtension();
|
||||
ext.srcTarget = new LauncherTarget[1];
|
||||
int srcState = mStateProvider.getCurrentState();
|
||||
fillInLauncherExtensionWithPageId(ext, pageId);
|
||||
int launcherAction = isSwipingToLeft ? Launcher.SWIPE_LEFT : Launcher.SWIPE_RIGHT;
|
||||
StatsLogCompat.write(launcherAction, srcState, srcState,
|
||||
MessageNano.toByteArray(ext), true);
|
||||
}
|
||||
|
||||
public static boolean fillInLauncherExtension(View v, LauncherExtension extension) {
|
||||
StatsLogUtils.LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v);
|
||||
if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
|
||||
@@ -99,6 +108,13 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean fillInLauncherExtensionWithPageId(LauncherExtension ext, int pageId) {
|
||||
Target target = new Target();
|
||||
target.pageIndex = pageId;
|
||||
copy(target, ext.srcTarget[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void copy(Target src, LauncherTarget dst) {
|
||||
// fill in
|
||||
}
|
||||
|
||||
@@ -34,9 +34,9 @@ import androidx.test.uiautomator.UiDevice;
|
||||
|
||||
import com.android.launcher3.tapl.LauncherInstrumentation;
|
||||
import com.android.launcher3.tapl.TestHelpers;
|
||||
import com.android.launcher3.util.rule.FailureWatcher;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
@@ -79,6 +79,14 @@ public class NavigationModeSwitchRule implements TestRule {
|
||||
description.getAnnotation(NavigationModeSwitch.class) != null) {
|
||||
Mode mode = description.getAnnotation(NavigationModeSwitch.class).mode();
|
||||
return new Statement() {
|
||||
private void assertTrue(String message, boolean condition) {
|
||||
if(!condition) {
|
||||
final AssertionError assertionError = new AssertionError(message);
|
||||
FailureWatcher.onError(mLauncher.getDevice(), description, assertionError);
|
||||
throw assertionError;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
mLauncher.enableDebugTracing();
|
||||
@@ -107,7 +115,8 @@ public class NavigationModeSwitchRule implements TestRule {
|
||||
Log.e(TAG, "Exception", e);
|
||||
throw e;
|
||||
} finally {
|
||||
Assert.assertTrue(setActiveOverlay(prevOverlayPkg, originalMode));
|
||||
assertTrue("Couldn't set overlay",
|
||||
setActiveOverlay(prevOverlayPkg, originalMode));
|
||||
}
|
||||
mLauncher.disableDebugTracing();
|
||||
}
|
||||
@@ -176,7 +185,7 @@ public class NavigationModeSwitchRule implements TestRule {
|
||||
latch.await(10, TimeUnit.SECONDS);
|
||||
targetContext.getMainExecutor().execute(() ->
|
||||
sysUINavigationMode.removeModeChangeListener(listener));
|
||||
Assert.assertTrue("Navigation mode didn't change to " + expectedMode,
|
||||
assertTrue("Navigation mode didn't change to " + expectedMode,
|
||||
currentSysUiNavigationMode() == expectedMode);
|
||||
}
|
||||
|
||||
@@ -184,7 +193,7 @@ public class NavigationModeSwitchRule implements TestRule {
|
||||
if (mLauncher.getNavigationModel() == expectedMode) break;
|
||||
Thread.sleep(100);
|
||||
}
|
||||
Assert.assertTrue("Couldn't switch to " + overlayPackage,
|
||||
assertTrue("Couldn't switch to " + overlayPackage,
|
||||
mLauncher.getNavigationModel() == expectedMode);
|
||||
|
||||
for (int i = 0; i != 100; ++i) {
|
||||
@@ -192,7 +201,7 @@ public class NavigationModeSwitchRule implements TestRule {
|
||||
Thread.sleep(100);
|
||||
}
|
||||
final String error = mLauncher.getNavigationModeMismatchError();
|
||||
Assert.assertTrue("Switching nav mode: " + error, error == null);
|
||||
assertTrue("Switching nav mode: " + error, error == null);
|
||||
|
||||
Thread.sleep(5000);
|
||||
return true;
|
||||
|
||||
@@ -97,6 +97,7 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
@Test
|
||||
@PortraitLandscape
|
||||
public void testOverview() throws Exception {
|
||||
mLauncher.enableDebugTracing();
|
||||
startTestApps();
|
||||
Overview overview = mLauncher.pressHome().switchToOverview();
|
||||
assertTrue("Launcher internal state didn't switch to Overview",
|
||||
@@ -176,6 +177,7 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
|
||||
executeOnLauncher(
|
||||
launcher -> assertEquals("Still have tasks after dismissing all",
|
||||
0, getTaskCount(launcher)));
|
||||
mLauncher.disableDebugTracing();
|
||||
}
|
||||
|
||||
private int getCurrentOverviewPage(Launcher launcher) {
|
||||
|
||||
+2
-1
@@ -29,7 +29,8 @@ public class PackageInstallStateChangedTaskTest extends BaseModelUpdateTaskTestC
|
||||
|
||||
private PackageInstallStateChangedTask newTask(String pkg, int progress) {
|
||||
int state = PackageInstallerCompat.STATUS_INSTALLING;
|
||||
PackageInstallInfo installInfo = new PackageInstallInfo(pkg, state, progress);
|
||||
PackageInstallInfo installInfo = new PackageInstallInfo(pkg, state, progress,
|
||||
android.os.Process.myUserHandle());
|
||||
return new PackageInstallStateChangedTask(installInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ public class AllAppsList {
|
||||
public void addPromiseApp(Context context,
|
||||
PackageInstallerCompat.PackageInstallInfo installInfo) {
|
||||
ApplicationInfo applicationInfo = LauncherAppsCompat.getInstance(context)
|
||||
.getApplicationInfo(installInfo.packageName, 0, Process.myUserHandle());
|
||||
.getApplicationInfo(installInfo.packageName, 0, installInfo.user);
|
||||
// only if not yet installed
|
||||
if (applicationInfo == null) {
|
||||
PromiseAppInfo info = new PromiseAppInfo(installInfo);
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.launcher3;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
@@ -29,7 +30,6 @@ import android.content.pm.ShortcutInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
@@ -141,7 +141,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
|
||||
String pkg = getIntentPackage(info.launchIntent);
|
||||
if (!TextUtils.isEmpty(pkg)
|
||||
&& !launcherApps.isPackageEnabledForProfile(pkg, info.user)) {
|
||||
&& !launcherApps.isPackageEnabledForProfile(pkg, info.user)
|
||||
&& !info.isActivity) {
|
||||
if (DBG) Log.d(TAG, "Ignoring shortcut for absent package: "
|
||||
+ info.launchIntent);
|
||||
continue;
|
||||
@@ -250,7 +251,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
}
|
||||
|
||||
public static WorkspaceItemInfo fromActivityInfo(LauncherActivityInfo info, Context context) {
|
||||
return (WorkspaceItemInfo) (new PendingInstallShortcutInfo(info, context).getItemInfo().first);
|
||||
return (WorkspaceItemInfo)
|
||||
new PendingInstallShortcutInfo(info, context).getItemInfo().first;
|
||||
}
|
||||
|
||||
public static void queueShortcut(ShortcutInfo info, Context context) {
|
||||
@@ -261,8 +263,9 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
queuePendingShortcutInfo(new PendingInstallShortcutInfo(info, widgetId, context), context);
|
||||
}
|
||||
|
||||
public static void queueActivityInfo(LauncherActivityInfo activity, Context context) {
|
||||
queuePendingShortcutInfo(new PendingInstallShortcutInfo(activity, context), context);
|
||||
public static void queueApplication(Intent data, UserHandle user, Context context) {
|
||||
queuePendingShortcutInfo(new PendingInstallShortcutInfo(data, context, user),
|
||||
context);
|
||||
}
|
||||
|
||||
public static HashSet<ShortcutKey> getPendingShortcuts(Context context) {
|
||||
@@ -326,7 +329,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
|
||||
private static class PendingInstallShortcutInfo {
|
||||
|
||||
final LauncherActivityInfo activityInfo;
|
||||
final boolean isActivity;
|
||||
final ShortcutInfo shortcutInfo;
|
||||
final AppWidgetProviderInfo providerInfo;
|
||||
|
||||
@@ -340,7 +343,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
* Initializes a PendingInstallShortcutInfo received from a different app.
|
||||
*/
|
||||
public PendingInstallShortcutInfo(Intent data, UserHandle user, Context context) {
|
||||
activityInfo = null;
|
||||
isActivity = false;
|
||||
shortcutInfo = null;
|
||||
providerInfo = null;
|
||||
|
||||
@@ -350,14 +353,13 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
|
||||
launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
|
||||
label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a PendingInstallShortcutInfo to represent a launcher target.
|
||||
*/
|
||||
public PendingInstallShortcutInfo(LauncherActivityInfo info, Context context) {
|
||||
activityInfo = info;
|
||||
isActivity = true;
|
||||
shortcutInfo = null;
|
||||
providerInfo = null;
|
||||
|
||||
@@ -369,11 +371,27 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
label = info.getLabel().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a PendingInstallShortcutInfo to represent a launcher target.
|
||||
*/
|
||||
public PendingInstallShortcutInfo(Intent data, Context context, UserHandle user) {
|
||||
isActivity = true;
|
||||
shortcutInfo = null;
|
||||
providerInfo = null;
|
||||
|
||||
this.data = data;
|
||||
this.user = user;
|
||||
mContext = context;
|
||||
|
||||
launchIntent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
|
||||
label = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a PendingInstallShortcutInfo to represent a launcher target.
|
||||
*/
|
||||
public PendingInstallShortcutInfo(ShortcutInfo info, Context context) {
|
||||
activityInfo = null;
|
||||
isActivity = false;
|
||||
shortcutInfo = info;
|
||||
providerInfo = null;
|
||||
|
||||
@@ -390,7 +408,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
*/
|
||||
public PendingInstallShortcutInfo(
|
||||
AppWidgetProviderInfo info, int widgetId, Context context) {
|
||||
activityInfo = null;
|
||||
isActivity = false;
|
||||
shortcutInfo = null;
|
||||
providerInfo = info;
|
||||
|
||||
@@ -405,17 +423,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
|
||||
public String encodeToString() {
|
||||
try {
|
||||
if (activityInfo != null) {
|
||||
// If it a launcher target, we only need component name, and user to
|
||||
// recreate this.
|
||||
return new JSONStringer()
|
||||
.object()
|
||||
.key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
|
||||
.key(APP_SHORTCUT_TYPE_KEY).value(true)
|
||||
.key(USER_HANDLE_KEY).value(UserManagerCompat.getInstance(mContext)
|
||||
.getSerialNumberForUser(user))
|
||||
.endObject().toString();
|
||||
} else if (shortcutInfo != null) {
|
||||
if (shortcutInfo != null) {
|
||||
// If it a launcher target, we only need component name, and user to
|
||||
// recreate this.
|
||||
return new JSONStringer()
|
||||
@@ -457,7 +465,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
JSONStringer json = new JSONStringer()
|
||||
.object()
|
||||
.key(LAUNCH_INTENT_KEY).value(launchIntent.toUri(0))
|
||||
.key(NAME_KEY).value(name);
|
||||
.key(NAME_KEY).value(name)
|
||||
.key(APP_SHORTCUT_TYPE_KEY).value(isActivity);
|
||||
if (icon != null) {
|
||||
byte[] iconByteArray = GraphicsUtils.flattenBitmap(icon);
|
||||
json = json.key(ICON_KEY).value(
|
||||
@@ -477,29 +486,18 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
}
|
||||
|
||||
public Pair<ItemInfo, Object> getItemInfo() {
|
||||
if (activityInfo != null) {
|
||||
AppInfo appInfo = new AppInfo(mContext, activityInfo, user);
|
||||
final LauncherAppState app = LauncherAppState.getInstance(mContext);
|
||||
// Set default values until proper values is loaded.
|
||||
appInfo.title = "";
|
||||
appInfo.applyFrom(app.getIconCache().getDefaultIcon(user));
|
||||
final WorkspaceItemInfo si = appInfo.makeWorkspaceItem();
|
||||
if (Looper.myLooper() == LauncherModel.getWorkerLooper()) {
|
||||
app.getIconCache().getTitleAndIcon(si, activityInfo, false /* useLowResIcon */);
|
||||
} else {
|
||||
app.getModel().updateAndBindWorkspaceItem(() -> {
|
||||
app.getIconCache().getTitleAndIcon(
|
||||
si, activityInfo, false /* useLowResIcon */);
|
||||
return si;
|
||||
});
|
||||
}
|
||||
return Pair.create((ItemInfo) si, (Object) activityInfo);
|
||||
if (isActivity) {
|
||||
WorkspaceItemInfo si = createWorkspaceItemInfo(data,
|
||||
LauncherAppState.getInstance(mContext));
|
||||
si.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
si.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON;
|
||||
return Pair.create(si, null);
|
||||
} else if (shortcutInfo != null) {
|
||||
WorkspaceItemInfo si = new WorkspaceItemInfo(shortcutInfo, mContext);
|
||||
WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(shortcutInfo, mContext);
|
||||
LauncherIcons li = LauncherIcons.obtain(mContext);
|
||||
si.applyFrom(li.createShortcutIcon(shortcutInfo));
|
||||
itemInfo.applyFrom(li.createShortcutIcon(shortcutInfo));
|
||||
li.recycle();
|
||||
return Pair.create((ItemInfo) si, (Object) shortcutInfo);
|
||||
return Pair.create(itemInfo, shortcutInfo);
|
||||
} else if (providerInfo != null) {
|
||||
LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo
|
||||
.fromProviderInfo(mContext, providerInfo);
|
||||
@@ -511,15 +509,16 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
widgetInfo.minSpanY = info.minSpanY;
|
||||
widgetInfo.spanX = Math.min(info.spanX, idp.numColumns);
|
||||
widgetInfo.spanY = Math.min(info.spanY, idp.numRows);
|
||||
return Pair.create((ItemInfo) widgetInfo, (Object) providerInfo);
|
||||
return Pair.create(widgetInfo, providerInfo);
|
||||
} else {
|
||||
WorkspaceItemInfo si = createWorkspaceItemInfo(data, LauncherAppState.getInstance(mContext));
|
||||
return Pair.create((ItemInfo) si, null);
|
||||
WorkspaceItemInfo itemInfo =
|
||||
createWorkspaceItemInfo(data, LauncherAppState.getInstance(mContext));
|
||||
return Pair.create(itemInfo, null);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLauncherActivity() {
|
||||
return activityInfo != null;
|
||||
return isActivity;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,7 +533,9 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
if (decoder.optBoolean(APP_SHORTCUT_TYPE_KEY)) {
|
||||
LauncherActivityInfo info = LauncherAppsCompat.getInstance(context)
|
||||
.resolveActivity(decoder.launcherIntent, decoder.user);
|
||||
return info == null ? null : new PendingInstallShortcutInfo(info, context);
|
||||
if (info != null) {
|
||||
return new PendingInstallShortcutInfo(info, context);
|
||||
}
|
||||
} else if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
|
||||
DeepShortcutManager sm = DeepShortcutManager.getInstance(context);
|
||||
List<ShortcutInfo> si = sm.queryForFullDetails(
|
||||
@@ -578,7 +579,11 @@ public class InstallShortcutReceiver extends BroadcastReceiver {
|
||||
data.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconResource);
|
||||
}
|
||||
|
||||
return new PendingInstallShortcutInfo(data, decoder.user, context);
|
||||
if (decoder.optBoolean(APP_SHORTCUT_TYPE_KEY)) {
|
||||
return new PendingInstallShortcutInfo(data, context, decoder.user);
|
||||
} else {
|
||||
return new PendingInstallShortcutInfo(data, decoder.user, context);
|
||||
}
|
||||
} catch (JSONException | URISyntaxException e) {
|
||||
Log.d(TAG, "Exception reading shortcut to add: " + e);
|
||||
}
|
||||
|
||||
@@ -227,6 +227,10 @@ public class LauncherStateManager {
|
||||
|
||||
private void goToState(LauncherState state, boolean animated, long delay,
|
||||
final Runnable onCompleteRunnable) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "goToState: " + state + " @ " +
|
||||
Log.getStackTraceString(new Throwable()));
|
||||
}
|
||||
animated &= Utilities.areAnimationsEnabled(mLauncher);
|
||||
if (mLauncher.isInState(state)) {
|
||||
if (mConfig.mCurrentAnimation == null) {
|
||||
@@ -426,6 +430,9 @@ public class LauncherStateManager {
|
||||
if (state != mCurrentStableState) {
|
||||
mLastStableState = state.getHistoryForState(mCurrentStableState);
|
||||
mCurrentStableState = state;
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.ALL_APPS_UPON_RECENTS, "onStateTransitionEnd: " + state);
|
||||
}
|
||||
}
|
||||
|
||||
state.onStateTransitionEnd(mLauncher);
|
||||
|
||||
@@ -18,28 +18,33 @@ package com.android.launcher3;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageInstaller.SessionInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
import com.android.launcher3.compat.PackageInstallerCompat;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.android.launcher3.compat.PackageInstallerCompat.getUserHandle;
|
||||
|
||||
/**
|
||||
* BroadcastReceiver to handle session commit intent.
|
||||
*/
|
||||
@@ -66,15 +71,29 @@ public class SessionCommitReceiver extends BroadcastReceiver {
|
||||
|
||||
SessionInfo info = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
|
||||
UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
|
||||
PackageInstallerCompat packageInstallerCompat = PackageInstallerCompat.getInstance(context);
|
||||
|
||||
if (TextUtils.isEmpty(info.getAppPackageName()) ||
|
||||
info.getInstallReason() != PackageManager.INSTALL_REASON_USER) {
|
||||
if (TextUtils.isEmpty(info.getAppPackageName())
|
||||
|| info.getInstallReason() != PackageManager.INSTALL_REASON_USER
|
||||
|| packageInstallerCompat.promiseIconAddedForId(info.getSessionId())) {
|
||||
packageInstallerCompat.removePromiseIconId(info.getSessionId());
|
||||
return;
|
||||
}
|
||||
|
||||
queueAppIconAddition(context, info.getAppPackageName(), user);
|
||||
}
|
||||
|
||||
public static void queuePromiseAppIconAddition(Context context, SessionInfo sessionInfo) {
|
||||
String packageName = sessionInfo.getAppPackageName();
|
||||
List<LauncherActivityInfo> activities = LauncherAppsCompat.getInstance(context)
|
||||
.getActivityList(packageName, getUserHandle(sessionInfo));
|
||||
if (activities == null || activities.isEmpty()) {
|
||||
// Ensure application isn't already installed.
|
||||
queueAppIconAddition(context, packageName, sessionInfo.getAppLabel(),
|
||||
sessionInfo.getAppIcon(), getUserHandle(sessionInfo));
|
||||
}
|
||||
}
|
||||
|
||||
public static void queueAppIconAddition(Context context, String packageName, UserHandle user) {
|
||||
List<LauncherActivityInfo> activities = LauncherAppsCompat.getInstance(context)
|
||||
.getActivityList(packageName, user);
|
||||
@@ -82,7 +101,18 @@ public class SessionCommitReceiver extends BroadcastReceiver {
|
||||
// no activity found
|
||||
return;
|
||||
}
|
||||
InstallShortcutReceiver.queueActivityInfo(activities.get(0), context);
|
||||
queueAppIconAddition(context, packageName, activities.get(0).getLabel(), null, user);
|
||||
}
|
||||
|
||||
private static void queueAppIconAddition(Context context, String packageName,
|
||||
CharSequence label, Bitmap icon, UserHandle user) {
|
||||
Intent data = new Intent();
|
||||
data.putExtra(Intent.EXTRA_SHORTCUT_INTENT, new Intent().setComponent(
|
||||
new ComponentName(packageName, "")).setPackage(packageName));
|
||||
data.putExtra(Intent.EXTRA_SHORTCUT_NAME, label);
|
||||
data.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon);
|
||||
|
||||
InstallShortcutReceiver.queueApplication(data, user, context);
|
||||
}
|
||||
|
||||
public static boolean isEnabled(Context context) {
|
||||
|
||||
@@ -1052,6 +1052,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
if (!mOverlayShown) {
|
||||
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
|
||||
Action.Direction.LEFT, ContainerType.WORKSPACE, 0);
|
||||
mLauncher.getStatsLogManager().logSwipeOnContainer(true, 0);
|
||||
}
|
||||
mOverlayShown = true;
|
||||
// Not announcing the overlay page for accessibility since it announces itself.
|
||||
@@ -1061,6 +1062,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
if (!ued.isPreviousHomeGesture()) {
|
||||
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
|
||||
Action.Direction.RIGHT, ContainerType.WORKSPACE, -1);
|
||||
mLauncher.getStatsLogManager().logSwipeOnContainer(false, -1);
|
||||
}
|
||||
} else if (Float.compare(mOverlayTranslation, 0f) != 0) {
|
||||
// When arriving to 0 overscroll from non-zero overscroll, announce page for
|
||||
|
||||
@@ -50,24 +50,26 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon {
|
||||
* The icon was added as an auto-install app, and is not ready to be used. This flag can't
|
||||
* be present along with {@link #FLAG_RESTORED_ICON}, and is set during default layout
|
||||
* parsing.
|
||||
*
|
||||
* OR this icon was added due to it being an active install session created by the user.
|
||||
*/
|
||||
public static final int FLAG_AUTOINSTALL_ICON = 2; //0B10;
|
||||
public static final int FLAG_AUTOINSTALL_ICON = 1 << 1;
|
||||
|
||||
/**
|
||||
* The icon is being installed. If {@link #FLAG_RESTORED_ICON} or {@link #FLAG_AUTOINSTALL_ICON}
|
||||
* is set, then the icon is either being installed or is in a broken state.
|
||||
*/
|
||||
public static final int FLAG_INSTALL_SESSION_ACTIVE = 4; // 0B100;
|
||||
public static final int FLAG_INSTALL_SESSION_ACTIVE = 1 << 2;
|
||||
|
||||
/**
|
||||
* Indicates that the widget restore has started.
|
||||
*/
|
||||
public static final int FLAG_RESTORE_STARTED = 8; //0B1000;
|
||||
public static final int FLAG_RESTORE_STARTED = 1 << 3;
|
||||
|
||||
/**
|
||||
* Web UI supported.
|
||||
*/
|
||||
public static final int FLAG_SUPPORTS_WEB_UI = 16; //0B10000;
|
||||
public static final int FLAG_SUPPORTS_WEB_UI = 1 << 4;
|
||||
|
||||
/**
|
||||
* The intent used to start the application.
|
||||
@@ -210,7 +212,7 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon {
|
||||
public ComponentName getTargetComponent() {
|
||||
ComponentName cn = super.getTargetComponent();
|
||||
if (cn == null && (itemType == Favorites.ITEM_TYPE_SHORTCUT
|
||||
|| hasStatusFlag(FLAG_SUPPORTS_WEB_UI))) {
|
||||
|| hasStatusFlag(FLAG_SUPPORTS_WEB_UI | FLAG_AUTOINSTALL_ICON))) {
|
||||
// Legacy shortcuts and promise icons with web UI may not have a componentName but just
|
||||
// a packageName. In that case create a dummy componentName instead of adding additional
|
||||
// check everywhere.
|
||||
|
||||
@@ -628,20 +628,4 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
|
||||
return super.performAccessibilityAction(action, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
final boolean result = super.dispatchTouchEvent(ev);
|
||||
switch (ev.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (result) mAllAppsStore.enableDeferUpdates(
|
||||
AllAppsStore.DEFER_UPDATES_USER_INTERACTION);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mAllAppsStore.disableDeferUpdates(AllAppsStore.DEFER_UPDATES_USER_INTERACTION);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,8 @@ public class AllAppsStore {
|
||||
|
||||
// Defer updates flag used to defer all apps updates to the next draw.
|
||||
public static final int DEFER_UPDATES_NEXT_DRAW = 1 << 0;
|
||||
// Defer updates flag used to defer all apps updates while the user interacts with all apps.
|
||||
public static final int DEFER_UPDATES_USER_INTERACTION = 1 << 1;
|
||||
// Defer updates flag used to defer all apps updates by a test's request.
|
||||
public static final int DEFER_UPDATES_TEST = 1 << 2;
|
||||
public static final int DEFER_UPDATES_TEST = 1 << 1;
|
||||
|
||||
private PackageUserKey mTempKey = new PackageUserKey(null, null);
|
||||
private final HashMap<ComponentKey, AppInfo> mComponentToAppMap = new HashMap<>();
|
||||
|
||||
@@ -31,11 +31,14 @@ import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVL;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -167,6 +170,10 @@ public class LauncherAppsCompatVL extends LauncherAppsCompat {
|
||||
|
||||
@Override
|
||||
public void onPackagesSuspended(String[] packageNames, UserHandle user) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.APP_NOT_DISABLED, "onPackagesSuspended: " +
|
||||
Arrays.toString(packageNames));
|
||||
}
|
||||
mCallback.onPackagesSuspended(packageNames, user);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,15 +19,23 @@ package com.android.launcher3.compat;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
public abstract class PackageInstallerCompat {
|
||||
|
||||
// Set<String> of session ids of promise icons that have been added to the home screen
|
||||
// as FLAG_PROMISE_NEW_INSTALLS.
|
||||
protected static final String PROMISE_ICON_IDS = "promise_icon_ids";
|
||||
|
||||
public static final int STATUS_INSTALLED = 0;
|
||||
public static final int STATUS_INSTALLING = 1;
|
||||
public static final int STATUS_FAILED = 2;
|
||||
@@ -44,6 +52,10 @@ public abstract class PackageInstallerCompat {
|
||||
}
|
||||
}
|
||||
|
||||
public static UserHandle getUserHandle(PackageInstaller.SessionInfo info) {
|
||||
return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a map of active installs to their progress
|
||||
*/
|
||||
@@ -61,30 +73,44 @@ public abstract class PackageInstallerCompat {
|
||||
public final String packageName;
|
||||
public final int state;
|
||||
public final int progress;
|
||||
public final UserHandle user;
|
||||
|
||||
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);
|
||||
this.user = getUserHandle(info);
|
||||
}
|
||||
|
||||
public PackageInstallInfo(String packageName, int state, int progress) {
|
||||
public PackageInstallInfo(String packageName, int state, int progress, UserHandle user) {
|
||||
this.state = state;
|
||||
this.packageName = packageName;
|
||||
this.componentName = new ComponentName(packageName, "");
|
||||
this.progress = progress;
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
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 static PackageInstallInfo fromState(int state, String packageName, UserHandle user) {
|
||||
return new PackageInstallInfo(packageName, state, 0 /* progress */, user);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract List<PackageInstaller.SessionInfo> getAllVerifiedSessions();
|
||||
|
||||
/**
|
||||
* Returns true if a promise icon was already added to the home screen for {@param sessionId}.
|
||||
* Applicable only for icons with flag FLAG_PROMISE_NEW_INSTALLS.
|
||||
*/
|
||||
public abstract boolean promiseIconAddedForId(int sessionId);
|
||||
|
||||
/**
|
||||
* Applicable only for icons with flag FLAG_PROMISE_NEW_INSTALLS.
|
||||
*/
|
||||
public abstract void removePromiseIconId(int sessionId);
|
||||
}
|
||||
|
||||
@@ -21,17 +21,21 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInstaller;
|
||||
import android.content.pm.PackageInstaller.SessionCallback;
|
||||
import android.content.pm.PackageInstaller.SessionInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.launcher3.SessionCommitReceiver;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherModel;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -39,11 +43,13 @@ import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static com.android.launcher3.Utilities.getPrefs;
|
||||
|
||||
public class PackageInstallerCompatVL extends PackageInstallerCompat {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
@Thunk final SparseArray<String> mActiveSessions = new SparseArray<>();
|
||||
@Thunk final SparseArray<PackageUserKey> mActiveSessions = new SparseArray<>();
|
||||
|
||||
@Thunk final PackageInstaller mInstaller;
|
||||
private final IconCache mCache;
|
||||
@@ -51,6 +57,7 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
|
||||
private final Context mAppContext;
|
||||
private final HashMap<String,Boolean> mSessionVerifiedMap = new HashMap<>();
|
||||
private final LauncherAppsCompat mLauncherApps;
|
||||
private final IntSet mPromiseIconIds;
|
||||
|
||||
PackageInstallerCompatVL(Context context) {
|
||||
mAppContext = context.getApplicationContext();
|
||||
@@ -59,17 +66,38 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
|
||||
mWorker = new Handler(LauncherModel.getWorkerLooper());
|
||||
mInstaller.registerSessionCallback(mCallback, mWorker);
|
||||
mLauncherApps = LauncherAppsCompat.getInstance(context);
|
||||
mPromiseIconIds = IntSet.wrap(IntArray.wrap(Utilities.getIntArrayFromString(
|
||||
getPrefs(context).getString(PROMISE_ICON_IDS, ""))));
|
||||
|
||||
cleanUpPromiseIconIds();
|
||||
}
|
||||
|
||||
private void cleanUpPromiseIconIds() {
|
||||
IntArray existingIds = new IntArray();
|
||||
for (SessionInfo info : updateAndGetActiveSessionCache().values()) {
|
||||
existingIds.add(info.getSessionId());
|
||||
}
|
||||
IntArray idsToRemove = new IntArray();
|
||||
|
||||
for (int i = mPromiseIconIds.size() - 1; i >= 0; --i) {
|
||||
if (!existingIds.contains(mPromiseIconIds.getArray().get(i))) {
|
||||
idsToRemove.add(mPromiseIconIds.getArray().get(i));
|
||||
}
|
||||
}
|
||||
for (int i = idsToRemove.size() - 1; i >= 0; --i) {
|
||||
mPromiseIconIds.getArray().removeValue(idsToRemove.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, SessionInfo> updateAndGetActiveSessionCache() {
|
||||
HashMap<String, SessionInfo> activePackages = new HashMap<>();
|
||||
UserHandle primaryUser = Process.myUserHandle();
|
||||
for (SessionInfo info : getAllVerifiedSessions()) {
|
||||
addSessionInfoToCache(info, Utilities.ATLEAST_Q ? info.getUser() : primaryUser);
|
||||
addSessionInfoToCache(info, getUserHandle(info));
|
||||
if (info.getAppPackageName() != null) {
|
||||
activePackages.put(info.getAppPackageName(), info);
|
||||
mActiveSessions.put(info.getSessionId(), info.getAppPackageName());
|
||||
mActiveSessions.put(info.getSessionId(),
|
||||
new PackageUserKey(info.getAppPackageName(), getUserHandle(info)));
|
||||
}
|
||||
}
|
||||
return activePackages;
|
||||
@@ -78,7 +106,7 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
|
||||
public SessionInfo getActiveSessionInfo(UserHandle user, String pkg) {
|
||||
for (SessionInfo info : getAllVerifiedSessions()) {
|
||||
boolean match = pkg.equals(info.getAppPackageName());
|
||||
if (Utilities.ATLEAST_Q && !user.equals(info.getUser())) {
|
||||
if (Utilities.ATLEAST_Q && !user.equals(getUserHandle(info))) {
|
||||
match = false;
|
||||
}
|
||||
if (match) {
|
||||
@@ -120,19 +148,38 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
|
||||
PackageInstallInfo.fromInstallingState(sessionInfo));
|
||||
}
|
||||
}
|
||||
|
||||
if (Utilities.ATLEAST_OREO && FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get()
|
||||
&& SessionCommitReceiver.isEnabled(mAppContext)
|
||||
&& sessionInfo != null
|
||||
&& sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER) {
|
||||
SessionCommitReceiver.queuePromiseAppIconAddition(mAppContext, sessionInfo);
|
||||
if (!mPromiseIconIds.contains(sessionInfo.getSessionId())) {
|
||||
mPromiseIconIds.add(sessionInfo.getSessionId());
|
||||
updatePromiseIconPrefs();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinished(int sessionId, boolean success) {
|
||||
// For a finished session, we can't get the session info. So use the
|
||||
// packageName from our local cache.
|
||||
String packageName = mActiveSessions.get(sessionId);
|
||||
PackageUserKey key = mActiveSessions.get(sessionId);
|
||||
mActiveSessions.remove(sessionId);
|
||||
|
||||
if (packageName != null) {
|
||||
sendUpdate(PackageInstallInfo.fromState(
|
||||
success ? STATUS_INSTALLED : STATUS_FAILED,
|
||||
packageName));
|
||||
if (key != null && key.mPackageName != null) {
|
||||
String packageName = key.mPackageName;
|
||||
sendUpdate(PackageInstallInfo.fromState(success ? STATUS_INSTALLED : STATUS_FAILED,
|
||||
packageName, key.mUser));
|
||||
|
||||
if (!success && FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get()) {
|
||||
LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
|
||||
if (appState != null) {
|
||||
LauncherModel model = appState.getModel();
|
||||
model.onPackageRemoved(packageName, key.mUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,8 +202,9 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
|
||||
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());
|
||||
mActiveSessions.put(session.getSessionId(),
|
||||
new PackageUserKey(session.getAppPackageName(), getUserHandle(session)));
|
||||
addSessionInfoToCache(session, getUserHandle(session));
|
||||
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
|
||||
if (app != null) {
|
||||
app.getModel().updateSessionDisplayInfo(session.getAppPackageName());
|
||||
@@ -178,7 +226,7 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
|
||||
if (!mSessionVerifiedMap.containsKey(pkg)) {
|
||||
LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mAppContext);
|
||||
boolean hasSystemFlag = launcherApps.getApplicationInfo(pkg,
|
||||
ApplicationInfo.FLAG_SYSTEM, Process.myUserHandle()) != null;
|
||||
ApplicationInfo.FLAG_SYSTEM, getUserHandle(sessionInfo)) != null;
|
||||
mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag);
|
||||
}
|
||||
}
|
||||
@@ -198,4 +246,23 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean promiseIconAddedForId(int sessionId) {
|
||||
return mPromiseIconIds.contains(sessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePromiseIconId(int sessionId) {
|
||||
if (mPromiseIconIds.contains(sessionId)) {
|
||||
mPromiseIconIds.getArray().removeValue(sessionId);
|
||||
updatePromiseIconPrefs();
|
||||
}
|
||||
}
|
||||
|
||||
private void updatePromiseIconPrefs() {
|
||||
getPrefs(mAppContext).edit()
|
||||
.putString(PROMISE_ICON_IDS, mPromiseIconIds.getArray().toConcatString())
|
||||
.apply();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +60,11 @@ public abstract class BaseFlags {
|
||||
// When enabled the promise icon is visible in all apps while installation an app.
|
||||
public static final boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false;
|
||||
|
||||
// When enabled a promise icon is added to the home screen when install session is active.
|
||||
public static final TogglableFlag PROMISE_APPS_NEW_INSTALLS =
|
||||
new TogglableFlag("PROMISE_APPS_NEW_INSTALLS", true,
|
||||
"Adds a promise icon to the home screen for new install sessions.");
|
||||
|
||||
// Enable moving the QSB on the 0th screen of the workspace
|
||||
public static final boolean QSB_ON_FIRST_SCREEN = true;
|
||||
|
||||
|
||||
@@ -41,5 +41,6 @@ public class StatsLogManager implements ResourceBasedOverride {
|
||||
public void logAppLaunch(View v, Intent intent) { }
|
||||
public void logTaskLaunch(View v, ComponentKey key) { }
|
||||
public void logTaskDismiss(View v, ComponentKey key) { }
|
||||
public void logSwipeOnContainer(boolean isSwipingToLeft, int pageId) { }
|
||||
public void verify() {} // TODO: should move into robo tests
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
package com.android.launcher3.model;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.LauncherActivityInfo;
|
||||
import android.content.pm.PackageInstaller.SessionInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.Pair;
|
||||
@@ -32,6 +34,8 @@ import com.android.launcher3.LauncherModel.Callbacks;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.WorkspaceItemInfo;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.compat.LauncherAppsCompat;
|
||||
import com.android.launcher3.compat.PackageInstallerCompat;
|
||||
import com.android.launcher3.util.GridOccupancy;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
|
||||
@@ -85,6 +89,10 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
|
||||
}
|
||||
}
|
||||
|
||||
PackageInstallerCompat packageInstaller =
|
||||
PackageInstallerCompat.getInstance(app.getContext());
|
||||
LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(app.getContext());
|
||||
|
||||
for (ItemInfo item : filteredItems) {
|
||||
// Find appropriate space for the item.
|
||||
int[] coords = findSpaceForItem(app, dataModel, workspaceScreens,
|
||||
@@ -101,6 +109,36 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
|
||||
throw new RuntimeException("Unexpected info type");
|
||||
}
|
||||
|
||||
if (item instanceof WorkspaceItemInfo && ((WorkspaceItemInfo) item).isPromise()) {
|
||||
WorkspaceItemInfo workspaceInfo = (WorkspaceItemInfo) item;
|
||||
String packageName = item.getTargetComponent() != null
|
||||
? item.getTargetComponent().getPackageName() : null;
|
||||
if (packageName == null) {
|
||||
continue;
|
||||
}
|
||||
SessionInfo sessionInfo = packageInstaller.getActiveSessionInfo(item.user,
|
||||
packageName);
|
||||
if (sessionInfo == null) {
|
||||
List<LauncherActivityInfo> activities = launcherApps
|
||||
.getActivityList(packageName, item.user);
|
||||
if (activities != null && !activities.isEmpty()) {
|
||||
// App was installed while launcher was in the background.
|
||||
itemInfo = new AppInfo(app.getContext(), activities.get(0), item.user)
|
||||
.makeWorkspaceItem();
|
||||
WorkspaceItemInfo wii = (WorkspaceItemInfo) itemInfo;
|
||||
wii.title = "";
|
||||
wii.applyFrom(app.getIconCache().getDefaultIcon(item.user));
|
||||
app.getIconCache().getTitleAndIcon(wii,
|
||||
((WorkspaceItemInfo) itemInfo).usingLowResIcon());
|
||||
} else {
|
||||
// Session was cancelled, do not add.
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
workspaceInfo.setInstallProgress((int) sessionInfo.getProgress());
|
||||
}
|
||||
}
|
||||
|
||||
// Add the shortcut to the db
|
||||
getModelWriter().addItemToDatabase(itemInfo,
|
||||
LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId,
|
||||
|
||||
@@ -227,7 +227,7 @@ public class LoaderCursor extends CursorWrapper {
|
||||
if (!TextUtils.isEmpty(title)) {
|
||||
info.title = Utilities.trim(title);
|
||||
}
|
||||
} else if (hasRestoreFlag(WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON)) {
|
||||
} else if (hasRestoreFlag(WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON)) {
|
||||
if (TextUtils.isEmpty(info.title)) {
|
||||
info.title = getTitle();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.launcher3.model;
|
||||
import android.content.ComponentName;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Process;
|
||||
|
||||
import com.android.launcher3.AllAppsList;
|
||||
import com.android.launcher3.AppInfo;
|
||||
@@ -56,7 +55,7 @@ public class PackageInstallStateChangedTask extends BaseModelUpdateTask {
|
||||
ApplicationInfo ai = app.getContext()
|
||||
.getPackageManager().getApplicationInfo(mInstallInfo.packageName, 0);
|
||||
if (InstantAppResolver.newInstance(app.getContext()).isInstantApp(ai)) {
|
||||
app.getModel().onPackageAdded(ai.packageName, Process.myUserHandle());
|
||||
app.getModel().onPackageAdded(ai.packageName, mInstallInfo.user);
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// Ignore
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.android.launcher3.icons.BitmapInfo;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutManager;
|
||||
import com.android.launcher3.testing.TestProtocol;
|
||||
import com.android.launcher3.util.FlagOp;
|
||||
import com.android.launcher3.util.IntSparseArrayMap;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
@@ -55,6 +56,8 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static com.android.launcher3.WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON;
|
||||
|
||||
/**
|
||||
* Handles updates due to changes in package manager (app installed/updated/removed)
|
||||
* or when a user availability changes.
|
||||
@@ -85,6 +88,10 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
|
||||
|
||||
@Override
|
||||
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
|
||||
if (TestProtocol.sDebugTracing) {
|
||||
Log.d(TestProtocol.APP_NOT_DISABLED, "PackageUpdatedTask: " + mOp + ", " +
|
||||
Arrays.toString(mPackages));
|
||||
}
|
||||
final Context context = app.getContext();
|
||||
final IconCache iconCache = app.getIconCache();
|
||||
|
||||
@@ -99,7 +106,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
|
||||
if (DEBUG) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]);
|
||||
iconCache.updateIconsForPkg(packages[i], mUser);
|
||||
if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) {
|
||||
appsList.removePackage(packages[i], Process.myUserHandle());
|
||||
appsList.removePackage(packages[i], mUser);
|
||||
}
|
||||
appsList.addPackage(context, packages[i], mUser);
|
||||
|
||||
@@ -227,8 +234,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
|
||||
isTargetValid = LauncherAppsCompat.getInstance(context)
|
||||
.isActivityEnabledForProfile(cn, mUser);
|
||||
}
|
||||
if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON)
|
||||
&& !isTargetValid) {
|
||||
if (si.hasStatusFlag(FLAG_AUTOINSTALL_ICON)) {
|
||||
if (updateWorkspaceItemIntent(context, si, packageName)) {
|
||||
infoUpdated = true;
|
||||
} else if (si.hasPromiseIconUi()) {
|
||||
|
||||
@@ -81,4 +81,6 @@ public final class TestProtocol {
|
||||
|
||||
public static final String NO_BACKGROUND_TO_OVERVIEW_TAG = "b/138251824";
|
||||
public static final String NO_DRAG_TO_WORKSPACE = "b/138729456";
|
||||
public static final String APP_NOT_DISABLED = "b/139891609";
|
||||
public static final String ALL_APPS_UPON_RECENTS = "b/139941530";
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ public class FailureWatcher extends TestWatcher {
|
||||
mDevice = device;
|
||||
}
|
||||
|
||||
private void dumpViewHierarchy() {
|
||||
private static void dumpViewHierarchy(UiDevice device) {
|
||||
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
try {
|
||||
mDevice.dumpWindowHierarchy(stream);
|
||||
device.dumpWindowHierarchy(stream);
|
||||
stream.flush();
|
||||
stream.close();
|
||||
for (String line : stream.toString().split("\\r?\\n")) {
|
||||
@@ -37,7 +37,11 @@ public class FailureWatcher extends TestWatcher {
|
||||
|
||||
@Override
|
||||
protected void failed(Throwable e, Description description) {
|
||||
if (mDevice == null) return;
|
||||
onError(mDevice, description, e);
|
||||
}
|
||||
|
||||
public static void onError(UiDevice device, Description description, Throwable e) {
|
||||
if (device == null) return;
|
||||
final String pathname = getInstrumentation().getTargetContext().
|
||||
getFilesDir().getPath() + "/TestScreenshot-" + description.getMethodName()
|
||||
+ ".png";
|
||||
@@ -45,15 +49,15 @@ public class FailureWatcher extends TestWatcher {
|
||||
", screenshot will be saved to " + pathname +
|
||||
", track trace is below, UI object dump is further below:\n" +
|
||||
Log.getStackTraceString(e));
|
||||
dumpViewHierarchy();
|
||||
dumpViewHierarchy(device);
|
||||
|
||||
try {
|
||||
final String dumpsysResult = mDevice.executeShellCommand(
|
||||
final String dumpsysResult = device.executeShellCommand(
|
||||
"dumpsys activity service TouchInteractionService");
|
||||
Log.d(TAG, "TouchInteractionService: " + dumpsysResult);
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
|
||||
mDevice.takeScreenshot(new File(pathname));
|
||||
device.takeScreenshot(new File(pathname));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user