|
|
|
|
@@ -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;
|
|
|
|
|
@@ -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;
|
|
|
|
|
@@ -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 {
|
|
|
|
|
@@ -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<>();
|
|
|
|
|
@@ -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 (DEBUG) {
|
|
|
|
|
Log.e(TAG, "ACTION_OVERLAY_CHANGED: mode=" + mMode
|
|
|
|
|
+ " contextUser=" + context.getUserId());
|
|
|
|
|
dumpAssetPaths(context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < mListeners.size(); i++) {
|
|
|
|
|
mListeners.get(i).onNavigationModeChanged(mode);
|
|
|
|
|
if (intent.getAction().equals(ACTION_OVERLAY_CHANGED)) {
|
|
|
|
|
if (DEBUG) {
|
|
|
|
|
Log.d(TAG, "ACTION_OVERLAY_CHANGED");
|
|
|
|
|
}
|
|
|
|
|
updateCurrentInteractionMode(true /* notify */);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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 */);
|
|
|
|
|
|
|
|
|
|
mMode = getCurrentInteractionMode(getCurrentUserContext());
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (notify) {
|
|
|
|
|
for (int i = 0; i < mListeners.size(); i++) {
|
|
|
|
|
mListeners.get(i).onNavigationModeChanged(mode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int addListener(ModeChangedListener listener) {
|
|
|
|
|
@@ -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());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|