Loading core/java/android/content/om/IOverlayManager.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -152,4 +152,9 @@ interface IOverlayManager { * @param userId The user for which to change the overlay. */ boolean setLowestPriority(in String packageName, in int userId); /** * Returns the list of default overlay packages, or an empty array if there are none. */ String[] getDefaultOverlayPackages(); } packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java +1 −1 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ import com.android.systemui.util.NotificationChannels; */ public class PipNotification { private static final String TAG = "PipNotification"; private static final String NOTIFICATION_TAG = PipNotification.class.getName(); private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName(); private static final boolean DEBUG = PipManager.DEBUG; private static final String ACTION_MENU = "PipNotification.menu"; Loading packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java +1 −1 Original line number Diff line number Diff line Loading @@ -53,7 +53,7 @@ import javax.inject.Singleton; @Singleton public class NavigationBarController implements Callbacks { private static final String TAG = NavigationBarController.class.getName(); private static final String TAG = NavigationBarController.class.getSimpleName(); private final Context mContext; private final Handler mHandler; Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java +149 −17 Original line number Diff line number Diff line Loading @@ -17,8 +17,10 @@ package com.android.systemui.statusbar.phone; import static android.content.Intent.ACTION_OVERLAY_CHANGED; import static android.content.Intent.ACTION_USER_SWITCHED; import static android.os.UserHandle.USER_CURRENT; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; import android.content.BroadcastReceiver; import android.content.Context; Loading @@ -28,16 +30,21 @@ import android.content.om.IOverlayManager; import android.content.pm.PackageManager; import android.content.res.ApkAssets; import android.os.PatternMatcher; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.util.Log; import android.util.SparseBooleanArray; import com.android.systemui.Dumpable; import com.android.systemui.UiOffloadThread; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import javax.inject.Inject; import javax.inject.Singleton; Loading @@ -48,7 +55,7 @@ import javax.inject.Singleton; @Singleton public class NavigationModeController implements Dumpable { private static final String TAG = NavigationModeController.class.getName(); private static final String TAG = NavigationModeController.class.getSimpleName(); private static final boolean DEBUG = true; public interface ModeChangedListener { Loading @@ -57,6 +64,10 @@ public class NavigationModeController implements Dumpable { private final Context mContext; private final IOverlayManager mOverlayManager; private final DeviceProvisionedController mDeviceProvisionedController; private final UiOffloadThread mUiOffloadThread; private SparseBooleanArray mRestoreGesturalNavBarMode = new SparseBooleanArray(); private int mMode = NAV_BAR_MODE_3BUTTON; private ArrayList<ModeChangedListener> mListeners = new ArrayList<>(); Loading @@ -64,36 +75,90 @@ public class NavigationModeController implements Dumpable { private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { context = getCurrentUserContext(); int mode = getCurrentInteractionMode(context); mMode = mode; if (intent.getAction().equals(ACTION_OVERLAY_CHANGED)) { if (DEBUG) { Log.e(TAG, "ACTION_OVERLAY_CHANGED: mode=" + mMode + " contextUser=" + context.getUserId()); dumpAssetPaths(context); Log.d(TAG, "ACTION_OVERLAY_CHANGED"); } updateCurrentInteractionMode(true /* notify */); } } }; for (int i = 0; i < mListeners.size(); i++) { mListeners.get(i).onNavigationModeChanged(mode); private final DeviceProvisionedController.DeviceProvisionedListener mDeviceProvisionedCallback = new DeviceProvisionedController.DeviceProvisionedListener() { @Override public void onDeviceProvisionedChanged() { if (DEBUG) { Log.d(TAG, "onDeviceProvisionedChanged: " + mDeviceProvisionedController.isDeviceProvisioned()); } // Once the device has been provisioned, check if we can restore gestural nav restoreGesturalNavOverlayIfNecessary(); } @Override public void onUserSetupChanged() { if (DEBUG) { Log.d(TAG, "onUserSetupChanged: " + mDeviceProvisionedController.isCurrentUserSetup()); } // Once the user has been setup, check if we can restore gestural nav restoreGesturalNavOverlayIfNecessary(); } @Override public void onUserSwitched() { if (DEBUG) { Log.d(TAG, "onUserSwitched: " + ActivityManagerWrapper.getInstance().getCurrentUserId()); } // Update the nav mode for the current user updateCurrentInteractionMode(true /* notify */); // When switching users, defer enabling the gestural nav overlay until the user // is all set up deferGesturalNavOverlayIfNecessary(); } }; @Inject public NavigationModeController(Context context) { public NavigationModeController(Context context, DeviceProvisionedController deviceProvisionedController, UiOffloadThread uiOffloadThread) { mContext = context; mOverlayManager = IOverlayManager.Stub.asInterface( ServiceManager.getService(Context.OVERLAY_SERVICE)); mUiOffloadThread = uiOffloadThread; mDeviceProvisionedController = deviceProvisionedController; mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback); IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED); overlayFilter.addDataScheme("package"); overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL); mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null); IntentFilter userFilter = new IntentFilter(ACTION_USER_SWITCHED); mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, userFilter, null, null); updateCurrentInteractionMode(false /* notify */); // Check if we need to defer enabling gestural nav deferGesturalNavOverlayIfNecessary(); } public void updateCurrentInteractionMode(boolean notify) { Context context = getCurrentUserContext(); int mode = getCurrentInteractionMode(context); mMode = mode; if (DEBUG) { Log.e(TAG, "updateCurrentInteractionMode: mode=" + mMode + " contextUser=" + context.getUserId()); dumpAssetPaths(context); } mMode = getCurrentInteractionMode(getCurrentUserContext()); if (notify) { for (int i = 0; i < mListeners.size(); i++) { mListeners.get(i).onNavigationModeChanged(mode); } } } public int addListener(ModeChangedListener listener) { Loading Loading @@ -129,10 +194,77 @@ public class NavigationModeController implements Dumpable { } } private void deferGesturalNavOverlayIfNecessary() { final int userId = mDeviceProvisionedController.getCurrentUser(); mRestoreGesturalNavBarMode.put(userId, false); if (mDeviceProvisionedController.isDeviceProvisioned() && mDeviceProvisionedController.isCurrentUserSetup()) { // User is already setup and device is provisioned, nothing to do if (DEBUG) { Log.d(TAG, "deferGesturalNavOverlayIfNecessary: device is provisioned and user is " + "setup"); } return; } ArrayList<String> defaultOverlays = new ArrayList<>(); try { defaultOverlays.addAll(Arrays.asList(mOverlayManager.getDefaultOverlayPackages())); } catch (RemoteException e) { Log.e(TAG, "deferGesturalNavOverlayIfNecessary: failed to fetch default overlays"); } if (!defaultOverlays.contains(NAV_BAR_MODE_GESTURAL_OVERLAY)) { // No default gesture nav overlay if (DEBUG) { Log.d(TAG, "deferGesturalNavOverlayIfNecessary: no default gestural overlay, " + "default=" + defaultOverlays); } return; } // If the default is gestural, force-enable three button mode until the device is // provisioned setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT); mRestoreGesturalNavBarMode.put(userId, true); if (DEBUG) { Log.d(TAG, "deferGesturalNavOverlayIfNecessary: setting to 3 button mode"); } } private void restoreGesturalNavOverlayIfNecessary() { if (DEBUG) { Log.d(TAG, "restoreGesturalNavOverlayIfNecessary: needs restore=" + mRestoreGesturalNavBarMode); } final int userId = mDeviceProvisionedController.getCurrentUser(); if (mRestoreGesturalNavBarMode.get(userId)) { // Restore the gestural state if necessary setModeOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT); mRestoreGesturalNavBarMode.put(userId, false); } } public void setModeOverlay(String overlayPkg, int userId) { mUiOffloadThread.submit(() -> { try { mOverlayManager.setEnabledExclusiveInCategory(overlayPkg, userId); } catch (RemoteException e) { Log.e(TAG, "Failed to enable overlay " + overlayPkg + " for user " + userId); } }); } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("NavigationModeController:"); pw.println(" mode=" + mMode); String defaultOverlays = ""; try { defaultOverlays = String.join(", ", mOverlayManager.getDefaultOverlayPackages()); } catch (RemoteException e) { defaultOverlays = "failed_to_fetch"; } pw.println(" defaultOverlays=" + defaultOverlays); dumpAssetPaths(getCurrentUserContext()); } Loading services/core/java/com/android/server/om/OverlayManagerService.java +20 −0 Original line number Diff line number Diff line Loading @@ -719,6 +719,26 @@ public final class OverlayManagerService extends SystemService { } } @Override public String[] getDefaultOverlayPackages() throws RemoteException { try { traceBegin(TRACE_TAG_RRO, "OMS#getDefaultOverlayPackages"); getContext().enforceCallingOrSelfPermission( android.Manifest.permission.MODIFY_THEME_OVERLAY, null); final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { return mImpl.getDefaultOverlayPackages(); } } finally { Binder.restoreCallingIdentity(ident); } } finally { traceEnd(TRACE_TAG_RRO); } } @Override public void onShellCommand(@NonNull final FileDescriptor in, @NonNull final FileDescriptor out, @NonNull final FileDescriptor err, Loading Loading
core/java/android/content/om/IOverlayManager.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -152,4 +152,9 @@ interface IOverlayManager { * @param userId The user for which to change the overlay. */ boolean setLowestPriority(in String packageName, in int userId); /** * Returns the list of default overlay packages, or an empty array if there are none. */ String[] getDefaultOverlayPackages(); }
packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java +1 −1 Original line number Diff line number Diff line Loading @@ -43,7 +43,7 @@ import com.android.systemui.util.NotificationChannels; */ public class PipNotification { private static final String TAG = "PipNotification"; private static final String NOTIFICATION_TAG = PipNotification.class.getName(); private static final String NOTIFICATION_TAG = PipNotification.class.getSimpleName(); private static final boolean DEBUG = PipManager.DEBUG; private static final String ACTION_MENU = "PipNotification.menu"; Loading
packages/SystemUI/src/com/android/systemui/statusbar/NavigationBarController.java +1 −1 Original line number Diff line number Diff line Loading @@ -53,7 +53,7 @@ import javax.inject.Singleton; @Singleton public class NavigationBarController implements Callbacks { private static final String TAG = NavigationBarController.class.getName(); private static final String TAG = NavigationBarController.class.getSimpleName(); private final Context mContext; private final Handler mHandler; Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java +149 −17 Original line number Diff line number Diff line Loading @@ -17,8 +17,10 @@ package com.android.systemui.statusbar.phone; import static android.content.Intent.ACTION_OVERLAY_CHANGED; import static android.content.Intent.ACTION_USER_SWITCHED; import static android.os.UserHandle.USER_CURRENT; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; import android.content.BroadcastReceiver; import android.content.Context; Loading @@ -28,16 +30,21 @@ import android.content.om.IOverlayManager; import android.content.pm.PackageManager; import android.content.res.ApkAssets; import android.os.PatternMatcher; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.util.Log; import android.util.SparseBooleanArray; import com.android.systemui.Dumpable; import com.android.systemui.UiOffloadThread; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import javax.inject.Inject; import javax.inject.Singleton; Loading @@ -48,7 +55,7 @@ import javax.inject.Singleton; @Singleton public class NavigationModeController implements Dumpable { private static final String TAG = NavigationModeController.class.getName(); private static final String TAG = NavigationModeController.class.getSimpleName(); private static final boolean DEBUG = true; public interface ModeChangedListener { Loading @@ -57,6 +64,10 @@ public class NavigationModeController implements Dumpable { private final Context mContext; private final IOverlayManager mOverlayManager; private final DeviceProvisionedController mDeviceProvisionedController; private final UiOffloadThread mUiOffloadThread; private SparseBooleanArray mRestoreGesturalNavBarMode = new SparseBooleanArray(); private int mMode = NAV_BAR_MODE_3BUTTON; private ArrayList<ModeChangedListener> mListeners = new ArrayList<>(); Loading @@ -64,36 +75,90 @@ public class NavigationModeController implements Dumpable { private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { context = getCurrentUserContext(); int mode = getCurrentInteractionMode(context); mMode = mode; if (intent.getAction().equals(ACTION_OVERLAY_CHANGED)) { if (DEBUG) { Log.e(TAG, "ACTION_OVERLAY_CHANGED: mode=" + mMode + " contextUser=" + context.getUserId()); dumpAssetPaths(context); Log.d(TAG, "ACTION_OVERLAY_CHANGED"); } updateCurrentInteractionMode(true /* notify */); } } }; for (int i = 0; i < mListeners.size(); i++) { mListeners.get(i).onNavigationModeChanged(mode); private final DeviceProvisionedController.DeviceProvisionedListener mDeviceProvisionedCallback = new DeviceProvisionedController.DeviceProvisionedListener() { @Override public void onDeviceProvisionedChanged() { if (DEBUG) { Log.d(TAG, "onDeviceProvisionedChanged: " + mDeviceProvisionedController.isDeviceProvisioned()); } // Once the device has been provisioned, check if we can restore gestural nav restoreGesturalNavOverlayIfNecessary(); } @Override public void onUserSetupChanged() { if (DEBUG) { Log.d(TAG, "onUserSetupChanged: " + mDeviceProvisionedController.isCurrentUserSetup()); } // Once the user has been setup, check if we can restore gestural nav restoreGesturalNavOverlayIfNecessary(); } @Override public void onUserSwitched() { if (DEBUG) { Log.d(TAG, "onUserSwitched: " + ActivityManagerWrapper.getInstance().getCurrentUserId()); } // Update the nav mode for the current user updateCurrentInteractionMode(true /* notify */); // When switching users, defer enabling the gestural nav overlay until the user // is all set up deferGesturalNavOverlayIfNecessary(); } }; @Inject public NavigationModeController(Context context) { public NavigationModeController(Context context, DeviceProvisionedController deviceProvisionedController, UiOffloadThread uiOffloadThread) { mContext = context; mOverlayManager = IOverlayManager.Stub.asInterface( ServiceManager.getService(Context.OVERLAY_SERVICE)); mUiOffloadThread = uiOffloadThread; mDeviceProvisionedController = deviceProvisionedController; mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback); IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED); overlayFilter.addDataScheme("package"); overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL); mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null); IntentFilter userFilter = new IntentFilter(ACTION_USER_SWITCHED); mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, userFilter, null, null); updateCurrentInteractionMode(false /* notify */); // Check if we need to defer enabling gestural nav deferGesturalNavOverlayIfNecessary(); } public void updateCurrentInteractionMode(boolean notify) { Context context = getCurrentUserContext(); int mode = getCurrentInteractionMode(context); mMode = mode; if (DEBUG) { Log.e(TAG, "updateCurrentInteractionMode: mode=" + mMode + " contextUser=" + context.getUserId()); dumpAssetPaths(context); } mMode = getCurrentInteractionMode(getCurrentUserContext()); if (notify) { for (int i = 0; i < mListeners.size(); i++) { mListeners.get(i).onNavigationModeChanged(mode); } } } public int addListener(ModeChangedListener listener) { Loading Loading @@ -129,10 +194,77 @@ public class NavigationModeController implements Dumpable { } } private void deferGesturalNavOverlayIfNecessary() { final int userId = mDeviceProvisionedController.getCurrentUser(); mRestoreGesturalNavBarMode.put(userId, false); if (mDeviceProvisionedController.isDeviceProvisioned() && mDeviceProvisionedController.isCurrentUserSetup()) { // User is already setup and device is provisioned, nothing to do if (DEBUG) { Log.d(TAG, "deferGesturalNavOverlayIfNecessary: device is provisioned and user is " + "setup"); } return; } ArrayList<String> defaultOverlays = new ArrayList<>(); try { defaultOverlays.addAll(Arrays.asList(mOverlayManager.getDefaultOverlayPackages())); } catch (RemoteException e) { Log.e(TAG, "deferGesturalNavOverlayIfNecessary: failed to fetch default overlays"); } if (!defaultOverlays.contains(NAV_BAR_MODE_GESTURAL_OVERLAY)) { // No default gesture nav overlay if (DEBUG) { Log.d(TAG, "deferGesturalNavOverlayIfNecessary: no default gestural overlay, " + "default=" + defaultOverlays); } return; } // If the default is gestural, force-enable three button mode until the device is // provisioned setModeOverlay(NAV_BAR_MODE_3BUTTON_OVERLAY, USER_CURRENT); mRestoreGesturalNavBarMode.put(userId, true); if (DEBUG) { Log.d(TAG, "deferGesturalNavOverlayIfNecessary: setting to 3 button mode"); } } private void restoreGesturalNavOverlayIfNecessary() { if (DEBUG) { Log.d(TAG, "restoreGesturalNavOverlayIfNecessary: needs restore=" + mRestoreGesturalNavBarMode); } final int userId = mDeviceProvisionedController.getCurrentUser(); if (mRestoreGesturalNavBarMode.get(userId)) { // Restore the gestural state if necessary setModeOverlay(NAV_BAR_MODE_GESTURAL_OVERLAY, USER_CURRENT); mRestoreGesturalNavBarMode.put(userId, false); } } public void setModeOverlay(String overlayPkg, int userId) { mUiOffloadThread.submit(() -> { try { mOverlayManager.setEnabledExclusiveInCategory(overlayPkg, userId); } catch (RemoteException e) { Log.e(TAG, "Failed to enable overlay " + overlayPkg + " for user " + userId); } }); } @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("NavigationModeController:"); pw.println(" mode=" + mMode); String defaultOverlays = ""; try { defaultOverlays = String.join(", ", mOverlayManager.getDefaultOverlayPackages()); } catch (RemoteException e) { defaultOverlays = "failed_to_fetch"; } pw.println(" defaultOverlays=" + defaultOverlays); dumpAssetPaths(getCurrentUserContext()); } Loading
services/core/java/com/android/server/om/OverlayManagerService.java +20 −0 Original line number Diff line number Diff line Loading @@ -719,6 +719,26 @@ public final class OverlayManagerService extends SystemService { } } @Override public String[] getDefaultOverlayPackages() throws RemoteException { try { traceBegin(TRACE_TAG_RRO, "OMS#getDefaultOverlayPackages"); getContext().enforceCallingOrSelfPermission( android.Manifest.permission.MODIFY_THEME_OVERLAY, null); final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { return mImpl.getDefaultOverlayPackages(); } } finally { Binder.restoreCallingIdentity(ident); } } finally { traceEnd(TRACE_TAG_RRO); } } @Override public void onShellCommand(@NonNull final FileDescriptor in, @NonNull final FileDescriptor out, @NonNull final FileDescriptor err, Loading