Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c160fa4c authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Give VoiceInteractionService access to shortcuts.

The shortcut manager now has a set of additional packages that
have access, which the voice interaction system service feeds in
to.

Bug: 68760723
Test: CtsVoiceInteractionTestCases
Change-Id: I2a69f83569eb350f405bdd548998570ceef9ea7e
parent ad5570f5
Loading
Loading
Loading
Loading
+6 −2
Original line number Original line Diff line number Diff line
@@ -671,9 +671,13 @@ public class LauncherApps {
    }
    }


    /**
    /**
     * Returns whether the caller can access the shortcut information.
     * Returns whether the caller can access the shortcut information.  Access is currently
     * available to:
     *
     *
     * <p>Only the default launcher can access the shortcut information.
     * <ul>
     *     <li>The current launcher (or default launcher if there is no set current launcher).</li>
     *     <li>The currently active voice interaction service.</li>
     * </ul>
     *
     *
     * <p>Note when this method returns {@code false}, it may be a temporary situation because
     * <p>Note when this method returns {@code false}, it may be a temporary situation because
     * the user is trying a new launcher application.  The user may decide to change the default
     * the user is trying a new launcher application.  The user may decide to change the default
+3 −0
Original line number Original line Diff line number Diff line
@@ -73,6 +73,9 @@ public abstract class ShortcutServiceInternal {
    public abstract boolean hasShortcutHostPermission(int launcherUserId,
    public abstract boolean hasShortcutHostPermission(int launcherUserId,
            @NonNull String callingPackage, int callingPid, int callingUid);
            @NonNull String callingPackage, int callingPid, int callingUid);


    public abstract void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
            int userId);

    public abstract boolean requestPinAppWidget(@NonNull String callingPackage,
    public abstract boolean requestPinAppWidget(@NonNull String callingPackage,
            @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
            @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
            @Nullable IntentSender resultIntent, int userId);
            @Nullable IntentSender resultIntent, int userId);
+20 −0
Original line number Original line Diff line number Diff line
@@ -2262,6 +2262,10 @@ public class ShortcutService extends IShortcutService.Stub {


            final ShortcutUser user = getUserShortcutsLocked(userId);
            final ShortcutUser user = getUserShortcutsLocked(userId);


            if (user.hasHostPackage(packageName)) {
                return true;
            }

            // Always trust the cached component.
            // Always trust the cached component.
            final ComponentName cached = user.getCachedLauncher();
            final ComponentName cached = user.getCachedLauncher();
            if (cached != null) {
            if (cached != null) {
@@ -2361,6 +2365,16 @@ public class ShortcutService extends IShortcutService.Stub {
        }
        }
    }
    }


    public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
            int userId) {
        synchronized (mLock) {
            throwIfUserLockedL(userId);

            final ShortcutUser user = getUserShortcutsLocked(userId);
            user.setShortcutHostPackage(type, packageName);
        }
    }

    // === House keeping ===
    // === House keeping ===


    private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId,
    private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId,
@@ -2696,6 +2710,12 @@ public class ShortcutService extends IShortcutService.Stub {
                    callingPid, callingUid);
                    callingPid, callingUid);
        }
        }


        @Override
        public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
                int userId) {
            ShortcutService.this.setShortcutHostPackage(type, packageName, userId);
        }

        @Override
        @Override
        public boolean requestPinAppWidget(@NonNull String callingPackage,
        public boolean requestPinAppWidget(@NonNull String callingPackage,
                @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
                @NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
+44 −0
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.pm.ShortcutManager;
import android.text.TextUtils;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.text.format.Formatter;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;


@@ -123,6 +124,20 @@ class ShortcutUser {
    /** In-memory-cached default launcher. */
    /** In-memory-cached default launcher. */
    private ComponentName mCachedLauncher;
    private ComponentName mCachedLauncher;


    /**
     * Keep track of additional packages that other parts of the system have said are
     * allowed to access shortcuts.  The key is the part of the system it came from,
     * the value is the package name that has access.  We don't persist these because
     * at boot all relevant system services will push this data back to us they do their
     * normal evaluation of the state of the world.
     */
    private final ArrayMap<String, String> mHostPackages = new ArrayMap<>();

    /**
     * Set of package name values from above.
     */
    private final ArraySet<String> mHostPackageSet = new ArraySet<>();

    private String mKnownLocales;
    private String mKnownLocales;


    private long mLastAppScanTime;
    private long mLastAppScanTime;
@@ -467,6 +482,23 @@ class ShortcutUser {
        return mCachedLauncher;
        return mCachedLauncher;
    }
    }


    public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName) {
        if (packageName != null) {
            mHostPackages.put(type, packageName);
        } else {
            mHostPackages.remove(type);
        }

        mHostPackageSet.clear();
        for (int i = 0; i < mHostPackages.size(); i++) {
            mHostPackageSet.add(mHostPackages.valueAt(i));
        }
    }

    public boolean hasHostPackage(@NonNull String packageName) {
        return mHostPackageSet.contains(packageName);
    }

    public void resetThrottling() {
    public void resetThrottling() {
        for (int i = mPackages.size() - 1; i >= 0; i--) {
        for (int i = mPackages.size() - 1; i >= 0; i--) {
            mPackages.valueAt(i).resetThrottling();
            mPackages.valueAt(i).resetThrottling();
@@ -555,6 +587,18 @@ class ShortcutUser {
            pw.print("Last known launcher: ");
            pw.print("Last known launcher: ");
            pw.print(mLastKnownLauncher);
            pw.print(mLastKnownLauncher);
            pw.println();
            pw.println();

            if (mHostPackages.size() > 0) {
                pw.print(prefix);
                pw.println("Host packages:");
                for (int i = 0; i < mHostPackages.size(); i++) {
                    pw.print(prefix);
                    pw.print("  ");
                    pw.print(mHostPackages.keyAt(i));
                    pw.print(": ");
                    pw.println(mHostPackages.valueAt(i));
                }
            }
        }
        }


        for (int i = 0; i < mLaunchers.size(); i++) {
        for (int i = 0; i < mLaunchers.size(); i++) {
+32 −7
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.res.Resources;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.ContentObserver;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
@@ -44,6 +45,7 @@ import android.os.Parcel;
import android.os.RemoteCallbackList;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
import android.service.voice.IVoiceInteractionSession;
@@ -53,6 +55,7 @@ import android.service.voice.VoiceInteractionServiceInfo;
import android.service.voice.VoiceInteractionSession;
import android.service.voice.VoiceInteractionSession;
import android.speech.RecognitionService;
import android.speech.RecognitionService;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;


@@ -63,6 +66,7 @@ import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.PackageMonitor;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.SystemService;
import com.android.server.UiThread;
import com.android.server.UiThread;
@@ -84,7 +88,9 @@ public class VoiceInteractionManagerService extends SystemService {
    final ContentResolver mResolver;
    final ContentResolver mResolver;
    final DatabaseHelper mDbHelper;
    final DatabaseHelper mDbHelper;
    final ActivityManagerInternal mAmInternal;
    final ActivityManagerInternal mAmInternal;
    final TreeSet<Integer> mLoadedKeyphraseIds;
    final UserManager mUserManager;
    final ArraySet<Integer> mLoadedKeyphraseIds = new ArraySet<>();
    ShortcutServiceInternal mShortcutServiceInternal;
    SoundTriggerInternal mSoundTriggerInternal;
    SoundTriggerInternal mSoundTriggerInternal;


    private final RemoteCallbackList<IVoiceInteractionSessionListener>
    private final RemoteCallbackList<IVoiceInteractionSessionListener>
@@ -96,8 +102,10 @@ public class VoiceInteractionManagerService extends SystemService {
        mResolver = context.getContentResolver();
        mResolver = context.getContentResolver();
        mDbHelper = new DatabaseHelper(context);
        mDbHelper = new DatabaseHelper(context);
        mServiceStub = new VoiceInteractionManagerServiceStub();
        mServiceStub = new VoiceInteractionManagerServiceStub();
        mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
        mAmInternal = Preconditions.checkNotNull(
        mLoadedKeyphraseIds = new TreeSet<Integer>();
                LocalServices.getService(ActivityManagerInternal.class));
        mUserManager = Preconditions.checkNotNull(
                context.getSystemService(UserManager.class));


        PackageManagerInternal packageManagerInternal = LocalServices.getService(
        PackageManagerInternal packageManagerInternal = LocalServices.getService(
                PackageManagerInternal.class);
                PackageManagerInternal.class);
@@ -124,6 +132,8 @@ public class VoiceInteractionManagerService extends SystemService {
    @Override
    @Override
    public void onBootPhase(int phase) {
    public void onBootPhase(int phase) {
        if (PHASE_SYSTEM_SERVICES_READY == phase) {
        if (PHASE_SYSTEM_SERVICES_READY == phase) {
            mShortcutServiceInternal = Preconditions.checkNotNull(
                    LocalServices.getService(ShortcutServiceInternal.class));
            mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
            mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
        } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
        } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
            mServiceStub.systemRunning(isSafeMode());
            mServiceStub.systemRunning(isSafeMode());
@@ -180,6 +190,7 @@ public class VoiceInteractionManagerService extends SystemService {


        private boolean mSafeMode;
        private boolean mSafeMode;
        private int mCurUser;
        private int mCurUser;
        private boolean mCurUserUnlocked;
        private final boolean mEnableService;
        private final boolean mEnableService;


        VoiceInteractionManagerServiceStub() {
        VoiceInteractionManagerServiceStub() {
@@ -381,6 +392,7 @@ public class VoiceInteractionManagerService extends SystemService {
        public void switchUser(int userHandle) {
        public void switchUser(int userHandle) {
            synchronized (this) {
            synchronized (this) {
                mCurUser = userHandle;
                mCurUser = userHandle;
                mCurUserUnlocked = false;
                switchImplementationIfNeededLocked(false);
                switchImplementationIfNeededLocked(false);
            }
            }
        }
        }
@@ -409,13 +421,24 @@ public class VoiceInteractionManagerService extends SystemService {
                    }
                    }
                }
                }


                final boolean hasComponent = serviceComponent != null && serviceInfo != null;

                if (mUserManager.isUserUnlockingOrUnlocked(mCurUser)) {
                    if (hasComponent) {
                        mShortcutServiceInternal.setShortcutHostPackage(TAG,
                                serviceComponent.getPackageName(), mCurUser);
                    } else {
                        mShortcutServiceInternal.setShortcutHostPackage(TAG, null, mCurUser);
                    }
                }

                if (force || mImpl == null || mImpl.mUser != mCurUser
                if (force || mImpl == null || mImpl.mUser != mCurUser
                        || !mImpl.mComponent.equals(serviceComponent)) {
                        || !mImpl.mComponent.equals(serviceComponent)) {
                    unloadAllKeyphraseModels();
                    unloadAllKeyphraseModels();
                    if (mImpl != null) {
                    if (mImpl != null) {
                        mImpl.shutdownLocked();
                        mImpl.shutdownLocked();
                    }
                    }
                    if (serviceComponent != null && serviceInfo != null) {
                    if (hasComponent) {
                        mImpl = new VoiceInteractionManagerServiceImpl(mContext,
                        mImpl = new VoiceInteractionManagerServiceImpl(mContext,
                                UiThread.getHandler(), this, mCurUser, serviceComponent);
                                UiThread.getHandler(), this, mCurUser, serviceComponent);
                        mImpl.startLocked();
                        mImpl.startLocked();
@@ -953,12 +976,14 @@ public class VoiceInteractionManagerService extends SystemService {
        }
        }


        private synchronized void unloadAllKeyphraseModels() {
        private synchronized void unloadAllKeyphraseModels() {
            for (int keyphraseId : mLoadedKeyphraseIds) {
            for (int i = 0; i < mLoadedKeyphraseIds.size(); i++) {
                final long caller = Binder.clearCallingIdentity();
                final long caller = Binder.clearCallingIdentity();
                try {
                try {
                    int status = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
                    int status = mSoundTriggerInternal.unloadKeyphraseModel(
                            mLoadedKeyphraseIds.valueAt(i));
                    if (status != SoundTriggerInternal.STATUS_OK) {
                    if (status != SoundTriggerInternal.STATUS_OK) {
                        Slog.w(TAG, "Failed to unload keyphrase " + keyphraseId + ":" + status);
                        Slog.w(TAG, "Failed to unload keyphrase " + mLoadedKeyphraseIds.valueAt(i)
                                + ":" + status);
                    }
                    }
                } finally {
                } finally {
                    Binder.restoreCallingIdentity(caller);
                    Binder.restoreCallingIdentity(caller);