Loading core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +6 −0 Original line number Diff line number Diff line Loading @@ -483,6 +483,12 @@ public final class SystemUiDeviceConfigFlags { public static final String HOME_BUTTON_LONG_PRESS_DURATION_MS = "home_button_long_press_duration_ms"; /** * (boolean) Whether shortcut integration over app search service is enabled. */ public static final String SHORTCUT_APPSEARCH_INTEGRATION = "shortcut_appsearch_integration"; private SystemUiDeviceConfigFlags() { } } services/core/java/com/android/server/pm/ShortcutPackage.java +68 −15 Original line number Diff line number Diff line Loading @@ -219,10 +219,12 @@ class ShortcutPackage extends ShortcutPackageItem { getPackageName(), getPackageUserId()); } private boolean isAppSearchEnabled() { return mShortcutUser.mService.isAppSearchEnabled(); } public int getShortcutCount() { final int[] count = new int[1]; forEachShortcut(si -> count[0]++); return count[0]; return mShortcuts.size(); } @Override Loading Loading @@ -442,15 +444,18 @@ class ShortcutPackage extends ShortcutPackageItem { } forceReplaceShortcutInner(newShortcut); if (isAppSearchEnabled()) { mShortcutUser.mService.injectPostToHandler(() -> awaitInAppSearch("reportUsage", session -> { final AndroidFuture<Boolean> future = new AndroidFuture<>(); session.reportUsage( new ReportUsageRequest.Builder(getPackageName()) .setUri(newShortcut.getId()).build(), mShortcutUser.mExecutor, result -> future.complete(result.isSuccess())); mShortcutUser.mExecutor, result -> future.complete(result.isSuccess())); return future; })); } return deleted; } Loading Loading @@ -960,7 +965,7 @@ class ShortcutPackage extends ShortcutPackageItem { * the app's Xml resource. */ int getSharingShortcutCount() { if (getShortcutCount() == 0 || mShareTargets.isEmpty()) { if (mShareTargets.isEmpty()) { return 0; } Loading Loading @@ -1700,7 +1705,7 @@ class ShortcutPackage extends ShortcutPackageItem { final int size = mShortcuts.size(); final int shareTargetSize = mShareTargets.size(); if (size == 0 && shareTargetSize == 0 && mApiCallCount == 0 && getShortcutCount() == 0) { if (size == 0 && shareTargetSize == 0 && mApiCallCount == 0) { return; // nothing to write. } Loading Loading @@ -2254,6 +2259,9 @@ class ShortcutPackage extends ShortcutPackageItem { } void updateVisibility(String packageName, byte[] certificate, boolean visible) { if (!isAppSearchEnabled()) { return; } if (visible) { mPackageIdentifiers.put(packageName, new PackageIdentifier(packageName, certificate)); } else { Loading Loading @@ -2287,6 +2295,14 @@ class ShortcutPackage extends ShortcutPackageItem { private void saveShortcut(@NonNull final Collection<ShortcutInfo> shortcuts) { Objects.requireNonNull(shortcuts); if (!isAppSearchEnabled()) { // If AppSearch isn't enabled, save it in memory and we are done. for (ShortcutInfo si : shortcuts) { mShortcuts.put(si.getId(), si); } return; } // Otherwise, save pinned shortcuts in memory. shortcuts.forEach(si -> { if (si.isPinned()) { mShortcuts.put(si.getId(), si); Loading @@ -2294,12 +2310,13 @@ class ShortcutPackage extends ShortcutPackageItem { mShortcuts.remove(si.getId()); } }); // Then proceed to app search. saveToAppSearch(shortcuts); } private void saveToAppSearch(@NonNull final Collection<ShortcutInfo> shortcuts) { Objects.requireNonNull(shortcuts); if (shortcuts.isEmpty()) { if (!isAppSearchEnabled() || shortcuts.isEmpty()) { // No need to invoke AppSearch when there's nothing to save. return; } Loading Loading @@ -2335,6 +2352,9 @@ class ShortcutPackage extends ShortcutPackageItem { * Removes shortcuts from AppSearch. */ void removeShortcuts() { if (!isAppSearchEnabled()) { return; } awaitInAppSearch("Removing all shortcuts from " + getPackageName(), session -> { final AndroidFuture<Boolean> future = new AndroidFuture<>(); session.remove("", getSearchSpec(), mShortcutUser.mExecutor, result -> { Loading @@ -2352,6 +2372,9 @@ class ShortcutPackage extends ShortcutPackageItem { private void removeShortcut(@NonNull final String id) { Objects.requireNonNull(id); mShortcuts.remove(id); if (!isAppSearchEnabled()) { return; } awaitInAppSearch("Removing shortcut with id=" + id, session -> { final AndroidFuture<Boolean> future = new AndroidFuture<>(); session.remove(new RemoveByUriRequest.Builder(getPackageName()).addUris(id).build(), Loading Loading @@ -2381,6 +2404,16 @@ class ShortcutPackage extends ShortcutPackageItem { shortcutIds.add(id); } } if (!isAppSearchEnabled()) { final List<ShortcutInfo> ret = new ArrayList<>(1); for (int i = mShortcuts.size() - 1; i >= 0; i--) { ShortcutInfo si = mShortcuts.valueAt(i); if (shortcutIds.contains(si.getId())) { ret.add(si); } } return ret; } if (ShortcutService.DEBUG_REBOOT) { Slog.d(TAG, "Getting shortcuts for user=" + mShortcutUser.getUserId() + " pkg=" + getPackageName() + " ids: [" + String.join(",", ids) + "]"); Loading Loading @@ -2429,6 +2462,13 @@ class ShortcutPackage extends ShortcutPackageItem { private void forEachShortcutMutateIf(@NonNull final String query, @NonNull final Function<ShortcutInfo, Boolean> cb) { if (!isAppSearchEnabled()) { for (int i = mShortcuts.size() - 1; i >= 0; i--) { ShortcutInfo si = mShortcuts.valueAt(i); cb.apply(si); } return; } if (ShortcutService.DEBUG_REBOOT) { Slog.d(TAG, "Changing shortcuts for user=" + mShortcutUser.getUserId() + " pkg=" + getPackageName()); Loading @@ -2454,6 +2494,15 @@ class ShortcutPackage extends ShortcutPackageItem { private void forEachShortcutStopWhen( @NonNull final String query, @NonNull final Function<ShortcutInfo, Boolean> cb) { if (!isAppSearchEnabled()) { for (int i = mShortcuts.size() - 1; i >= 0; i--) { final ShortcutInfo si = mShortcuts.valueAt(i); if (cb.apply(si)) { return; } } return; } if (ShortcutService.DEBUG_REBOOT) { Slog.d(TAG, "Iterating shortcuts for user=" + mShortcutUser.getUserId() + " pkg=" + getPackageName()); Loading Loading @@ -2517,6 +2566,10 @@ class ShortcutPackage extends ShortcutPackageItem { final boolean forceReset, @NonNull final String description, @NonNull final Function<AppSearchSession, CompletableFuture<T>> cb) { if (!isAppSearchEnabled()) { throw new IllegalStateException( "awaitInAppSearch called when app search integration is disabled"); } synchronized (mLock) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); final long callingIdentity = Binder.clearCallingIdentity(); Loading services/core/java/com/android/server/pm/ShortcutService.java +12 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package com.android.server.pm; import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; import android.Manifest.permission; import android.annotation.IntDef; import android.annotation.NonNull; Loading Loading @@ -85,6 +87,7 @@ import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; import android.os.UserHandle; import android.provider.DeviceConfig; import android.text.TextUtils; import android.text.format.TimeMigrationUtils; import android.util.ArraySet; Loading @@ -104,6 +107,7 @@ import android.view.IWindowManager; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.infra.AndroidFuture; import com.android.internal.logging.MetricsLogger; import com.android.internal.os.BackgroundThread; Loading Loading @@ -447,6 +451,8 @@ public class ShortcutService extends IShortcutService.Stub { @GuardedBy("mLock") private final MetricsLogger mMetricsLogger = new MetricsLogger(); private final boolean mIsAppSearchEnabled; static class InvalidFileFormatException extends Exception { public InvalidFileFormatException(String message, Throwable cause) { super(message, cause); Loading Loading @@ -481,6 +487,8 @@ public class ShortcutService extends IShortcutService.Stub { mShortcutRequestPinProcessor = new ShortcutRequestPinProcessor(this, mLock); mShortcutBitmapSaver = new ShortcutBitmapSaver(this); mShortcutDumpFiles = new ShortcutDumpFiles(this); mIsAppSearchEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.SHORTCUT_APPSEARCH_INTEGRATION, false); if (onlyForPackageManagerApis) { return; // Don't do anything further. For unit tests only. Loading Loading @@ -518,6 +526,10 @@ public class ShortcutService extends IShortcutService.Stub { injectRegisterRoleHoldersListener(mOnRoleHoldersChangedListener); } boolean isAppSearchEnabled() { return mIsAppSearchEnabled; } long getStatStartTime() { return mStatLogger.getTime(); } Loading services/tests/servicestests/res/xml/shortcut_5.xml +1 −1 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ android:action="action" android:data="http://www/" android:targetPackage="abc" android:targetClass=".xyz" android:targetClass="abc.xyz" android:mimeType="foo/bar" > <categories android:name="cat1" /> Loading services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java +11 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package com.android.server.pm; import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list; import android.app.PendingIntent; Loading @@ -22,6 +24,9 @@ import android.app.appsearch.PackageIdentifier; import android.content.pm.AppSearchShortcutInfo; import android.os.RemoteException; import android.os.UserHandle; import android.provider.DeviceConfig; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import java.util.Random; Loading @@ -33,7 +38,12 @@ import java.util.Random; public class ShortcutManagerTest12 extends BaseShortcutManagerTest { public void testUpdateShortcutVisibility_updatesShortcutSchema() { if (!DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED, false)) { // no-op if app-search integration is disabled. return; } final byte[] cert = new byte[20]; new Random().nextBytes(cert); Loading Loading
core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +6 −0 Original line number Diff line number Diff line Loading @@ -483,6 +483,12 @@ public final class SystemUiDeviceConfigFlags { public static final String HOME_BUTTON_LONG_PRESS_DURATION_MS = "home_button_long_press_duration_ms"; /** * (boolean) Whether shortcut integration over app search service is enabled. */ public static final String SHORTCUT_APPSEARCH_INTEGRATION = "shortcut_appsearch_integration"; private SystemUiDeviceConfigFlags() { } }
services/core/java/com/android/server/pm/ShortcutPackage.java +68 −15 Original line number Diff line number Diff line Loading @@ -219,10 +219,12 @@ class ShortcutPackage extends ShortcutPackageItem { getPackageName(), getPackageUserId()); } private boolean isAppSearchEnabled() { return mShortcutUser.mService.isAppSearchEnabled(); } public int getShortcutCount() { final int[] count = new int[1]; forEachShortcut(si -> count[0]++); return count[0]; return mShortcuts.size(); } @Override Loading Loading @@ -442,15 +444,18 @@ class ShortcutPackage extends ShortcutPackageItem { } forceReplaceShortcutInner(newShortcut); if (isAppSearchEnabled()) { mShortcutUser.mService.injectPostToHandler(() -> awaitInAppSearch("reportUsage", session -> { final AndroidFuture<Boolean> future = new AndroidFuture<>(); session.reportUsage( new ReportUsageRequest.Builder(getPackageName()) .setUri(newShortcut.getId()).build(), mShortcutUser.mExecutor, result -> future.complete(result.isSuccess())); mShortcutUser.mExecutor, result -> future.complete(result.isSuccess())); return future; })); } return deleted; } Loading Loading @@ -960,7 +965,7 @@ class ShortcutPackage extends ShortcutPackageItem { * the app's Xml resource. */ int getSharingShortcutCount() { if (getShortcutCount() == 0 || mShareTargets.isEmpty()) { if (mShareTargets.isEmpty()) { return 0; } Loading Loading @@ -1700,7 +1705,7 @@ class ShortcutPackage extends ShortcutPackageItem { final int size = mShortcuts.size(); final int shareTargetSize = mShareTargets.size(); if (size == 0 && shareTargetSize == 0 && mApiCallCount == 0 && getShortcutCount() == 0) { if (size == 0 && shareTargetSize == 0 && mApiCallCount == 0) { return; // nothing to write. } Loading Loading @@ -2254,6 +2259,9 @@ class ShortcutPackage extends ShortcutPackageItem { } void updateVisibility(String packageName, byte[] certificate, boolean visible) { if (!isAppSearchEnabled()) { return; } if (visible) { mPackageIdentifiers.put(packageName, new PackageIdentifier(packageName, certificate)); } else { Loading Loading @@ -2287,6 +2295,14 @@ class ShortcutPackage extends ShortcutPackageItem { private void saveShortcut(@NonNull final Collection<ShortcutInfo> shortcuts) { Objects.requireNonNull(shortcuts); if (!isAppSearchEnabled()) { // If AppSearch isn't enabled, save it in memory and we are done. for (ShortcutInfo si : shortcuts) { mShortcuts.put(si.getId(), si); } return; } // Otherwise, save pinned shortcuts in memory. shortcuts.forEach(si -> { if (si.isPinned()) { mShortcuts.put(si.getId(), si); Loading @@ -2294,12 +2310,13 @@ class ShortcutPackage extends ShortcutPackageItem { mShortcuts.remove(si.getId()); } }); // Then proceed to app search. saveToAppSearch(shortcuts); } private void saveToAppSearch(@NonNull final Collection<ShortcutInfo> shortcuts) { Objects.requireNonNull(shortcuts); if (shortcuts.isEmpty()) { if (!isAppSearchEnabled() || shortcuts.isEmpty()) { // No need to invoke AppSearch when there's nothing to save. return; } Loading Loading @@ -2335,6 +2352,9 @@ class ShortcutPackage extends ShortcutPackageItem { * Removes shortcuts from AppSearch. */ void removeShortcuts() { if (!isAppSearchEnabled()) { return; } awaitInAppSearch("Removing all shortcuts from " + getPackageName(), session -> { final AndroidFuture<Boolean> future = new AndroidFuture<>(); session.remove("", getSearchSpec(), mShortcutUser.mExecutor, result -> { Loading @@ -2352,6 +2372,9 @@ class ShortcutPackage extends ShortcutPackageItem { private void removeShortcut(@NonNull final String id) { Objects.requireNonNull(id); mShortcuts.remove(id); if (!isAppSearchEnabled()) { return; } awaitInAppSearch("Removing shortcut with id=" + id, session -> { final AndroidFuture<Boolean> future = new AndroidFuture<>(); session.remove(new RemoveByUriRequest.Builder(getPackageName()).addUris(id).build(), Loading Loading @@ -2381,6 +2404,16 @@ class ShortcutPackage extends ShortcutPackageItem { shortcutIds.add(id); } } if (!isAppSearchEnabled()) { final List<ShortcutInfo> ret = new ArrayList<>(1); for (int i = mShortcuts.size() - 1; i >= 0; i--) { ShortcutInfo si = mShortcuts.valueAt(i); if (shortcutIds.contains(si.getId())) { ret.add(si); } } return ret; } if (ShortcutService.DEBUG_REBOOT) { Slog.d(TAG, "Getting shortcuts for user=" + mShortcutUser.getUserId() + " pkg=" + getPackageName() + " ids: [" + String.join(",", ids) + "]"); Loading Loading @@ -2429,6 +2462,13 @@ class ShortcutPackage extends ShortcutPackageItem { private void forEachShortcutMutateIf(@NonNull final String query, @NonNull final Function<ShortcutInfo, Boolean> cb) { if (!isAppSearchEnabled()) { for (int i = mShortcuts.size() - 1; i >= 0; i--) { ShortcutInfo si = mShortcuts.valueAt(i); cb.apply(si); } return; } if (ShortcutService.DEBUG_REBOOT) { Slog.d(TAG, "Changing shortcuts for user=" + mShortcutUser.getUserId() + " pkg=" + getPackageName()); Loading @@ -2454,6 +2494,15 @@ class ShortcutPackage extends ShortcutPackageItem { private void forEachShortcutStopWhen( @NonNull final String query, @NonNull final Function<ShortcutInfo, Boolean> cb) { if (!isAppSearchEnabled()) { for (int i = mShortcuts.size() - 1; i >= 0; i--) { final ShortcutInfo si = mShortcuts.valueAt(i); if (cb.apply(si)) { return; } } return; } if (ShortcutService.DEBUG_REBOOT) { Slog.d(TAG, "Iterating shortcuts for user=" + mShortcutUser.getUserId() + " pkg=" + getPackageName()); Loading Loading @@ -2517,6 +2566,10 @@ class ShortcutPackage extends ShortcutPackageItem { final boolean forceReset, @NonNull final String description, @NonNull final Function<AppSearchSession, CompletableFuture<T>> cb) { if (!isAppSearchEnabled()) { throw new IllegalStateException( "awaitInAppSearch called when app search integration is disabled"); } synchronized (mLock) { final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy(); final long callingIdentity = Binder.clearCallingIdentity(); Loading
services/core/java/com/android/server/pm/ShortcutService.java +12 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package com.android.server.pm; import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; import android.Manifest.permission; import android.annotation.IntDef; import android.annotation.NonNull; Loading Loading @@ -85,6 +87,7 @@ import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; import android.os.UserHandle; import android.provider.DeviceConfig; import android.text.TextUtils; import android.text.format.TimeMigrationUtils; import android.util.ArraySet; Loading @@ -104,6 +107,7 @@ import android.view.IWindowManager; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.infra.AndroidFuture; import com.android.internal.logging.MetricsLogger; import com.android.internal.os.BackgroundThread; Loading Loading @@ -447,6 +451,8 @@ public class ShortcutService extends IShortcutService.Stub { @GuardedBy("mLock") private final MetricsLogger mMetricsLogger = new MetricsLogger(); private final boolean mIsAppSearchEnabled; static class InvalidFileFormatException extends Exception { public InvalidFileFormatException(String message, Throwable cause) { super(message, cause); Loading Loading @@ -481,6 +487,8 @@ public class ShortcutService extends IShortcutService.Stub { mShortcutRequestPinProcessor = new ShortcutRequestPinProcessor(this, mLock); mShortcutBitmapSaver = new ShortcutBitmapSaver(this); mShortcutDumpFiles = new ShortcutDumpFiles(this); mIsAppSearchEnabled = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.SHORTCUT_APPSEARCH_INTEGRATION, false); if (onlyForPackageManagerApis) { return; // Don't do anything further. For unit tests only. Loading Loading @@ -518,6 +526,10 @@ public class ShortcutService extends IShortcutService.Stub { injectRegisterRoleHoldersListener(mOnRoleHoldersChangedListener); } boolean isAppSearchEnabled() { return mIsAppSearchEnabled; } long getStatStartTime() { return mStatLogger.getTime(); } Loading
services/tests/servicestests/res/xml/shortcut_5.xml +1 −1 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ android:action="action" android:data="http://www/" android:targetPackage="abc" android:targetClass=".xyz" android:targetClass="abc.xyz" android:mimeType="foo/bar" > <categories android:name="cat1" /> Loading
services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest12.java +11 −1 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ */ package com.android.server.pm; import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list; import android.app.PendingIntent; Loading @@ -22,6 +24,9 @@ import android.app.appsearch.PackageIdentifier; import android.content.pm.AppSearchShortcutInfo; import android.os.RemoteException; import android.os.UserHandle; import android.provider.DeviceConfig; import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import java.util.Random; Loading @@ -33,7 +38,12 @@ import java.util.Random; public class ShortcutManagerTest12 extends BaseShortcutManagerTest { public void testUpdateShortcutVisibility_updatesShortcutSchema() { if (!DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, SystemUiDeviceConfigFlags.DARK_LAUNCH_REMOTE_PREDICTION_SERVICE_ENABLED, false)) { // no-op if app-search integration is disabled. return; } final byte[] cert = new byte[20]; new Random().nextBytes(cert); Loading