Loading res/values/strings.xml +4 −1 Original line number Diff line number Diff line Loading @@ -8699,7 +8699,10 @@ <string name="notification_log_details_ranking_none">Ranking object doesn\'t contain this key.</string> <!-- [CHAR_LIMIT=NONE] Developer Settings: Title of the setting which turns on emulation of a display cutout. --> <string name="display_cutout_emulation">Emulate a display with a cutout</string> <string name="display_cutout_emulation">Simulate a display with a cutout</string> <!-- [CHAR_LIMIT=NONE] Developer Settings: Label for the option that turns off display cutout emulation. --> <string name="display_cutout_emulation_none">None</string> <!-- [CHAR_LIMIT=60] Label for special access screen --> <string name="special_access">Special app access</string> res/xml/development_settings.xml +1 −1 Original line number Diff line number Diff line Loading @@ -351,7 +351,7 @@ android:key="density" android:title="@string/developer_smallest_width" /> <SwitchPreference <ListPreference android:key="display_cutout_emulation" android:title="@string/display_cutout_emulation" /> Loading src/com/android/settings/development/EmulateDisplayCutoutPreferenceController.java +87 −26 Original line number Diff line number Diff line Loading @@ -16,41 +16,52 @@ package com.android.settings.development; import static android.os.UserHandle.USER_SYSTEM; import android.content.Context; import android.content.om.IOverlayManager; import android.content.om.OverlayInfo; import android.content.pm.PackageManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.support.annotation.VisibleForTesting; import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.TwoStatePreference; import android.text.TextUtils; import com.android.internal.util.ArrayUtils; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.development.DeveloperOptionsPreferenceController; import java.util.List; public class EmulateDisplayCutoutPreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin { private static final String EMULATION_OVERLAY = "com.android.internal.display.cutout.emulation"; public static final String EMULATION_OVERLAY_PREFIX = "com.android.internal.display.cutout.emulation."; private static final String KEY = "display_cutout_emulation"; private final IOverlayManager mOverlayManager; private final boolean mAvailable; private TwoStatePreference mPreference; private ListPreference mPreference; private PackageManager mPackageManager; @VisibleForTesting EmulateDisplayCutoutPreferenceController(Context context, IOverlayManager overlayManager) { EmulateDisplayCutoutPreferenceController(Context context, PackageManager packageManager, IOverlayManager overlayManager) { super(context); mOverlayManager = overlayManager; mAvailable = overlayManager != null && getEmulationOverlayInfo() != null; mPackageManager = packageManager; mAvailable = overlayManager != null && getOverlayInfos().length > 0; } public EmulateDisplayCutoutPreferenceController(Context context) { this(context, IOverlayManager.Stub.asInterface( this(context, context.getPackageManager(), IOverlayManager.Stub.asInterface( ServiceManager.getService(Context.OVERLAY_SERVICE))); } Loading @@ -67,45 +78,95 @@ public class EmulateDisplayCutoutPreferenceController extends @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); setPreference((TwoStatePreference) screen.findPreference(getPreferenceKey())); setPreference((ListPreference) screen.findPreference(getPreferenceKey())); } @VisibleForTesting void setPreference(TwoStatePreference preference) { void setPreference(ListPreference preference) { mPreference = preference; } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { return writeEnabled((boolean) newValue); return setEmulationOverlay((String) newValue); } private boolean setEmulationOverlay(String packageName) { OverlayInfo[] overlays = getOverlayInfos(); CharSequence currentPackageName = null; for (OverlayInfo o : overlays) { if (o.isEnabled()) { currentPackageName = o.packageName; } } private boolean writeEnabled(boolean newValue) { OverlayInfo current = getEmulationOverlayInfo(); if (current == null || current.isEnabled() == newValue) { return false; if (TextUtils.isEmpty(packageName) && TextUtils.isEmpty(currentPackageName) || TextUtils.equals(packageName, currentPackageName)) { // Already set. return true; } for (OverlayInfo o : overlays) { boolean isEnabled = o.isEnabled(); boolean shouldBeEnabled = TextUtils.equals(o.packageName, packageName); if (isEnabled != shouldBeEnabled) { try { return mOverlayManager.setEnabled(EMULATION_OVERLAY, newValue, UserHandle.USER_SYSTEM); mOverlayManager.setEnabled(o.packageName, shouldBeEnabled, USER_SYSTEM); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } updateState(mPreference); return true; } @Override public void updateState(Preference preference) { OverlayInfo overlayInfo = getEmulationOverlayInfo(); mPreference.setChecked(overlayInfo != null && overlayInfo.isEnabled()); OverlayInfo[] overlays = getOverlayInfos(); CharSequence[] pkgs = new CharSequence[overlays.length + 1]; CharSequence[] labels = new CharSequence[pkgs.length]; int current = 0; pkgs[0] = ""; labels[0] = mContext.getString(R.string.display_cutout_emulation_none); for (int i = 0; i < overlays.length; i++) { OverlayInfo o = overlays[i]; pkgs[i+1] = o.packageName; if (o.isEnabled()) { current = i+1; } } for (int i = 1; i < pkgs.length; i++) { try { labels[i] = mPackageManager.getApplicationInfo(pkgs[i].toString(), 0) .loadLabel(mPackageManager); } catch (PackageManager.NameNotFoundException e) { labels[i] = pkgs[i]; } } private OverlayInfo getEmulationOverlayInfo() { OverlayInfo overlayInfo = null; mPreference.setEntries(labels); mPreference.setEntryValues(pkgs); mPreference.setValueIndex(current); mPreference.setSummary(labels[current]); } private OverlayInfo[] getOverlayInfos() { try { overlayInfo = mOverlayManager.getOverlayInfo(EMULATION_OVERLAY, UserHandle.USER_SYSTEM); @SuppressWarnings("unchecked") List<OverlayInfo> overlayInfos = mOverlayManager.getOverlayInfosForTarget("android", USER_SYSTEM); for (int i = overlayInfos.size() - 1; i >= 0; i--) { if (!overlayInfos.get(i).packageName.startsWith(EMULATION_OVERLAY_PREFIX)) { overlayInfos.remove(i); } } return overlayInfos.toArray(new OverlayInfo[overlayInfos.size()]); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return overlayInfo; } @Override Loading @@ -115,8 +176,8 @@ public class EmulateDisplayCutoutPreferenceController extends @Override protected void onDeveloperOptionsSwitchDisabled() { writeEnabled(false); mPreference.setChecked(false); setEmulationOverlay(""); updateState(mPreference); mPreference.setEnabled(false); } } tests/robotests/src/android/content/om/IOverlayManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,15 @@ package android.content.om; import android.os.IBinder; import java.util.ArrayList; import java.util.LinkedList; public interface IOverlayManager { public OverlayInfo getOverlayInfo(String packageName, int userId); public java.util.List getOverlayInfosForTarget(java.lang.String targetPackageName, int userId); public boolean setEnabled(java.lang.String packageName, boolean enable, int userId); public static class Stub { Loading tests/robotests/src/android/content/om/OverlayInfo.java +9 −0 Original line number Diff line number Diff line Loading @@ -14,8 +14,17 @@ package android.content.om; import android.annotation.NonNull; public class OverlayInfo { public final String packageName; public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName, @NonNull String baseCodePath, int state, int userId) { this.packageName = packageName; } public boolean isEnabled() { return false; } Loading Loading
res/values/strings.xml +4 −1 Original line number Diff line number Diff line Loading @@ -8699,7 +8699,10 @@ <string name="notification_log_details_ranking_none">Ranking object doesn\'t contain this key.</string> <!-- [CHAR_LIMIT=NONE] Developer Settings: Title of the setting which turns on emulation of a display cutout. --> <string name="display_cutout_emulation">Emulate a display with a cutout</string> <string name="display_cutout_emulation">Simulate a display with a cutout</string> <!-- [CHAR_LIMIT=NONE] Developer Settings: Label for the option that turns off display cutout emulation. --> <string name="display_cutout_emulation_none">None</string> <!-- [CHAR_LIMIT=60] Label for special access screen --> <string name="special_access">Special app access</string>
res/xml/development_settings.xml +1 −1 Original line number Diff line number Diff line Loading @@ -351,7 +351,7 @@ android:key="density" android:title="@string/developer_smallest_width" /> <SwitchPreference <ListPreference android:key="display_cutout_emulation" android:title="@string/display_cutout_emulation" /> Loading
src/com/android/settings/development/EmulateDisplayCutoutPreferenceController.java +87 −26 Original line number Diff line number Diff line Loading @@ -16,41 +16,52 @@ package com.android.settings.development; import static android.os.UserHandle.USER_SYSTEM; import android.content.Context; import android.content.om.IOverlayManager; import android.content.om.OverlayInfo; import android.content.pm.PackageManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.support.annotation.VisibleForTesting; import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.TwoStatePreference; import android.text.TextUtils; import com.android.internal.util.ArrayUtils; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.development.DeveloperOptionsPreferenceController; import java.util.List; public class EmulateDisplayCutoutPreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin { private static final String EMULATION_OVERLAY = "com.android.internal.display.cutout.emulation"; public static final String EMULATION_OVERLAY_PREFIX = "com.android.internal.display.cutout.emulation."; private static final String KEY = "display_cutout_emulation"; private final IOverlayManager mOverlayManager; private final boolean mAvailable; private TwoStatePreference mPreference; private ListPreference mPreference; private PackageManager mPackageManager; @VisibleForTesting EmulateDisplayCutoutPreferenceController(Context context, IOverlayManager overlayManager) { EmulateDisplayCutoutPreferenceController(Context context, PackageManager packageManager, IOverlayManager overlayManager) { super(context); mOverlayManager = overlayManager; mAvailable = overlayManager != null && getEmulationOverlayInfo() != null; mPackageManager = packageManager; mAvailable = overlayManager != null && getOverlayInfos().length > 0; } public EmulateDisplayCutoutPreferenceController(Context context) { this(context, IOverlayManager.Stub.asInterface( this(context, context.getPackageManager(), IOverlayManager.Stub.asInterface( ServiceManager.getService(Context.OVERLAY_SERVICE))); } Loading @@ -67,45 +78,95 @@ public class EmulateDisplayCutoutPreferenceController extends @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); setPreference((TwoStatePreference) screen.findPreference(getPreferenceKey())); setPreference((ListPreference) screen.findPreference(getPreferenceKey())); } @VisibleForTesting void setPreference(TwoStatePreference preference) { void setPreference(ListPreference preference) { mPreference = preference; } @Override public boolean onPreferenceChange(Preference preference, Object newValue) { return writeEnabled((boolean) newValue); return setEmulationOverlay((String) newValue); } private boolean setEmulationOverlay(String packageName) { OverlayInfo[] overlays = getOverlayInfos(); CharSequence currentPackageName = null; for (OverlayInfo o : overlays) { if (o.isEnabled()) { currentPackageName = o.packageName; } } private boolean writeEnabled(boolean newValue) { OverlayInfo current = getEmulationOverlayInfo(); if (current == null || current.isEnabled() == newValue) { return false; if (TextUtils.isEmpty(packageName) && TextUtils.isEmpty(currentPackageName) || TextUtils.equals(packageName, currentPackageName)) { // Already set. return true; } for (OverlayInfo o : overlays) { boolean isEnabled = o.isEnabled(); boolean shouldBeEnabled = TextUtils.equals(o.packageName, packageName); if (isEnabled != shouldBeEnabled) { try { return mOverlayManager.setEnabled(EMULATION_OVERLAY, newValue, UserHandle.USER_SYSTEM); mOverlayManager.setEnabled(o.packageName, shouldBeEnabled, USER_SYSTEM); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } updateState(mPreference); return true; } @Override public void updateState(Preference preference) { OverlayInfo overlayInfo = getEmulationOverlayInfo(); mPreference.setChecked(overlayInfo != null && overlayInfo.isEnabled()); OverlayInfo[] overlays = getOverlayInfos(); CharSequence[] pkgs = new CharSequence[overlays.length + 1]; CharSequence[] labels = new CharSequence[pkgs.length]; int current = 0; pkgs[0] = ""; labels[0] = mContext.getString(R.string.display_cutout_emulation_none); for (int i = 0; i < overlays.length; i++) { OverlayInfo o = overlays[i]; pkgs[i+1] = o.packageName; if (o.isEnabled()) { current = i+1; } } for (int i = 1; i < pkgs.length; i++) { try { labels[i] = mPackageManager.getApplicationInfo(pkgs[i].toString(), 0) .loadLabel(mPackageManager); } catch (PackageManager.NameNotFoundException e) { labels[i] = pkgs[i]; } } private OverlayInfo getEmulationOverlayInfo() { OverlayInfo overlayInfo = null; mPreference.setEntries(labels); mPreference.setEntryValues(pkgs); mPreference.setValueIndex(current); mPreference.setSummary(labels[current]); } private OverlayInfo[] getOverlayInfos() { try { overlayInfo = mOverlayManager.getOverlayInfo(EMULATION_OVERLAY, UserHandle.USER_SYSTEM); @SuppressWarnings("unchecked") List<OverlayInfo> overlayInfos = mOverlayManager.getOverlayInfosForTarget("android", USER_SYSTEM); for (int i = overlayInfos.size() - 1; i >= 0; i--) { if (!overlayInfos.get(i).packageName.startsWith(EMULATION_OVERLAY_PREFIX)) { overlayInfos.remove(i); } } return overlayInfos.toArray(new OverlayInfo[overlayInfos.size()]); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } return overlayInfo; } @Override Loading @@ -115,8 +176,8 @@ public class EmulateDisplayCutoutPreferenceController extends @Override protected void onDeveloperOptionsSwitchDisabled() { writeEnabled(false); mPreference.setChecked(false); setEmulationOverlay(""); updateState(mPreference); mPreference.setEnabled(false); } }
tests/robotests/src/android/content/om/IOverlayManager.java +5 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,15 @@ package android.content.om; import android.os.IBinder; import java.util.ArrayList; import java.util.LinkedList; public interface IOverlayManager { public OverlayInfo getOverlayInfo(String packageName, int userId); public java.util.List getOverlayInfosForTarget(java.lang.String targetPackageName, int userId); public boolean setEnabled(java.lang.String packageName, boolean enable, int userId); public static class Stub { Loading
tests/robotests/src/android/content/om/OverlayInfo.java +9 −0 Original line number Diff line number Diff line Loading @@ -14,8 +14,17 @@ package android.content.om; import android.annotation.NonNull; public class OverlayInfo { public final String packageName; public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName, @NonNull String baseCodePath, int state, int userId) { this.packageName = packageName; } public boolean isEnabled() { return false; } Loading