Merge "Introduce Message.USER_LOCAL and added logic to map person to user id"
diff --git a/Android.bp b/Android.bp
index 7e038ce8..a80a5d3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -92,6 +92,7 @@
"core/java/android/app/IWallpaperManagerCallback.aidl",
"core/java/android/app/admin/IDeviceAdminService.aidl",
"core/java/android/app/admin/IDevicePolicyManager.aidl",
+ "core/java/android/app/admin/StartInstallingUpdateCallback.aidl",
"core/java/android/app/trust/IStrongAuthTracker.aidl",
"core/java/android/app/trust/ITrustManager.aidl",
"core/java/android/app/trust/ITrustListener.aidl",
@@ -347,6 +348,7 @@
"core/java/android/view/accessibility/IAccessibilityManagerClient.aidl",
"core/java/android/view/autofill/IAutoFillManager.aidl",
"core/java/android/view/autofill/IAutoFillManagerClient.aidl",
+ "core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl",
"core/java/android/view/autofill/IAutofillWindowPresenter.aidl",
"core/java/android/view/intelligence/IIntelligenceManager.aidl",
"core/java/android/view/IApplicationToken.aidl",
diff --git a/api/current.txt b/api/current.txt
index b719c46..7315056 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1319,6 +1319,7 @@
field public static final int supportsAssist = 16844016; // 0x10104f0
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
field public static final int supportsLocalInteraction = 16844047; // 0x101050f
+ field public static final int supportsMultipleDisplays = 16844183; // 0x1010597
field public static final int supportsPictureInPicture = 16844023; // 0x10104f7
field public static final int supportsRtl = 16843695; // 0x10103af
field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
@@ -5229,6 +5230,7 @@
ctor public Notification(android.os.Parcel);
method public android.app.Notification clone();
method public int describeContents();
+ method public boolean getAllowSystemGeneratedContextualActions();
method public android.app.PendingIntent getAppOverlayIntent();
method public int getBadgeIconType();
method public java.lang.String getChannelId();
@@ -5460,6 +5462,7 @@
method public android.app.Notification.Style getStyle();
method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
+ method public android.app.Notification.Builder setAllowSystemGeneratedContextualActions(boolean);
method public android.app.Notification.Builder setAppOverlayIntent(android.app.PendingIntent);
method public android.app.Notification.Builder setAutoCancel(boolean);
method public android.app.Notification.Builder setBadgeIconType(int);
@@ -6352,6 +6355,7 @@
method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
method public android.graphics.drawable.Drawable loadThumbnail(android.content.pm.PackageManager);
method public boolean supportsAmbientMode();
+ method public boolean supportsMultipleDisplays();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.WallpaperInfo> CREATOR;
}
@@ -6598,6 +6602,7 @@
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean);
method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, int);
+ method public void installSystemUpdate(android.content.ComponentName, android.net.Uri, java.util.concurrent.Executor, android.app.admin.DevicePolicyManager.InstallUpdateCallback);
method public boolean isActivePasswordSufficient();
method public boolean isAdminActive(android.content.ComponentName);
method public boolean isAffiliatedUser();
@@ -6840,6 +6845,16 @@
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
}
+ public static abstract class DevicePolicyManager.InstallUpdateCallback {
+ ctor public DevicePolicyManager.InstallUpdateCallback();
+ method public void onInstallUpdateError(int, java.lang.String);
+ field public static final int UPDATE_ERROR_BATTERY_LOW = 5; // 0x5
+ field public static final int UPDATE_ERROR_FILE_NOT_FOUND = 4; // 0x4
+ field public static final int UPDATE_ERROR_INCORRECT_OS_VERSION = 2; // 0x2
+ field public static final int UPDATE_ERROR_UNKNOWN = 1; // 0x1
+ field public static final int UPDATE_ERROR_UPDATE_FILE_INVALID = 3; // 0x3
+ }
+
public static abstract interface DevicePolicyManager.OnClearApplicationUserDataListener {
method public abstract void onApplicationUserDataCleared(java.lang.String, boolean);
}
@@ -10118,6 +10133,7 @@
field public static final java.lang.String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED";
field public static final java.lang.String ACTION_TIME_CHANGED = "android.intent.action.TIME_SET";
field public static final java.lang.String ACTION_TIME_TICK = "android.intent.action.TIME_TICK";
+ field public static final java.lang.String ACTION_TRANSLATE = "android.intent.action.TRANSLATE";
field public static final java.lang.String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED";
field public static final deprecated java.lang.String ACTION_UMS_CONNECTED = "android.intent.action.UMS_CONNECTED";
field public static final deprecated java.lang.String ACTION_UMS_DISCONNECTED = "android.intent.action.UMS_DISCONNECTED";
@@ -22628,7 +22644,7 @@
method public abstract void onLocationChanged(android.location.Location);
method public abstract void onProviderDisabled(java.lang.String);
method public abstract void onProviderEnabled(java.lang.String);
- method public abstract void onStatusChanged(java.lang.String, int, android.os.Bundle);
+ method public abstract deprecated void onStatusChanged(java.lang.String, int, android.os.Bundle);
}
public class LocationManager {
@@ -22640,7 +22656,7 @@
method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
method public void clearTestProviderEnabled(java.lang.String);
method public void clearTestProviderLocation(java.lang.String);
- method public void clearTestProviderStatus(java.lang.String);
+ method public deprecated void clearTestProviderStatus(java.lang.String);
method public java.util.List<java.lang.String> getAllProviders();
method public java.lang.String getBestProvider(android.location.Criteria, boolean);
method public java.lang.String getGnssHardwareModelName();
@@ -22677,7 +22693,7 @@
method public boolean sendExtraCommand(java.lang.String, java.lang.String, android.os.Bundle);
method public void setTestProviderEnabled(java.lang.String, boolean);
method public void setTestProviderLocation(java.lang.String, android.location.Location);
- method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
+ method public deprecated void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessage.Callback);
method public void unregisterGnssStatusCallback(android.location.GnssStatus.Callback);
@@ -22685,7 +22701,7 @@
field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
field public static final java.lang.String KEY_PROXIMITY_ENTERING = "entering";
- field public static final java.lang.String KEY_STATUS_CHANGED = "status";
+ field public static final deprecated java.lang.String KEY_STATUS_CHANGED = "status";
field public static final java.lang.String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
field public static final java.lang.String NETWORK_PROVIDER = "network";
field public static final java.lang.String PASSIVE_PROVIDER = "passive";
@@ -22704,9 +22720,9 @@
method public boolean supportsAltitude();
method public boolean supportsBearing();
method public boolean supportsSpeed();
- field public static final int AVAILABLE = 2; // 0x2
- field public static final int OUT_OF_SERVICE = 0; // 0x0
- field public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
+ field public static final deprecated int AVAILABLE = 2; // 0x2
+ field public static final deprecated int OUT_OF_SERVICE = 0; // 0x0
+ field public static final deprecated int TEMPORARILY_UNAVAILABLE = 1; // 0x1
}
public abstract interface OnNmeaMessageListener {
@@ -22935,7 +22951,7 @@
method public void adjustSuggestedStreamVolume(int, int, int);
method public void adjustVolume(int, int);
method public void dispatchMediaKeyEvent(android.view.KeyEvent);
- method public static int generateAudioSessionId();
+ method public int generateAudioSessionId();
method public java.util.List<android.media.AudioPlaybackConfiguration> getActivePlaybackConfigurations();
method public java.util.List<android.media.AudioRecordingConfiguration> getActiveRecordingConfigurations();
method public android.media.AudioDeviceInfo[] getDevices(int);
@@ -24575,6 +24591,7 @@
field public static final java.lang.String KEY_WIDTH = "width";
field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
field public static final java.lang.String MIMETYPE_AUDIO_AC3 = "audio/ac3";
+ field public static final java.lang.String MIMETYPE_AUDIO_AC4 = "audio/ac4";
field public static final java.lang.String MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
field public static final java.lang.String MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
field public static final java.lang.String MIMETYPE_AUDIO_EAC3 = "audio/eac3";
@@ -29117,15 +29134,18 @@
method public android.net.wifi.WifiNetworkSuggestion buildNetworkSuggestion();
method public android.net.wifi.WifiNetworkConfigBuilder setBssid(android.net.MacAddress);
method public android.net.wifi.WifiNetworkConfigBuilder setBssidPattern(android.net.MacAddress, android.net.MacAddress);
- method public android.net.wifi.WifiNetworkConfigBuilder setEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
method public android.net.wifi.WifiNetworkConfigBuilder setIsAppInteractionRequired();
+ method public android.net.wifi.WifiNetworkConfigBuilder setIsEnhancedOpen();
method public android.net.wifi.WifiNetworkConfigBuilder setIsHiddenSsid();
method public android.net.wifi.WifiNetworkConfigBuilder setIsMetered();
method public android.net.wifi.WifiNetworkConfigBuilder setIsUserInteractionRequired();
method public android.net.wifi.WifiNetworkConfigBuilder setPriority(int);
- method public android.net.wifi.WifiNetworkConfigBuilder setPskPassphrase(java.lang.String);
method public android.net.wifi.WifiNetworkConfigBuilder setSsid(java.lang.String);
method public android.net.wifi.WifiNetworkConfigBuilder setSsidPattern(android.os.PatternMatcher);
+ method public android.net.wifi.WifiNetworkConfigBuilder setWpa2EnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
+ method public android.net.wifi.WifiNetworkConfigBuilder setWpa2Passphrase(java.lang.String);
+ method public android.net.wifi.WifiNetworkConfigBuilder setWpa3EnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
+ method public android.net.wifi.WifiNetworkConfigBuilder setWpa3Passphrase(java.lang.String);
}
public final class WifiNetworkSuggestion implements android.os.Parcelable {
@@ -42871,6 +42891,7 @@
field public static final java.lang.String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool";
field public static final java.lang.String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool";
+ field public static final java.lang.String KEY_HIDE_PRESET_APN_DETAILS_BOOL = "hide_preset_apn_details_bool";
field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool";
field public static final java.lang.String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
field public static final java.lang.String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
@@ -43218,9 +43239,9 @@
public class MbmsGroupCallSession implements java.lang.AutoCloseable {
method public void close();
- method public static android.telephony.MbmsGroupCallSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsGroupCallSessionCallback);
+ method public static android.telephony.MbmsGroupCallSession create(android.content.Context, int, java.util.concurrent.Executor, android.telephony.mbms.MbmsGroupCallSessionCallback);
method public static android.telephony.MbmsGroupCallSession create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsGroupCallSessionCallback);
- method public android.telephony.mbms.GroupCall startGroupCall(java.util.concurrent.Executor, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+ method public android.telephony.mbms.GroupCall startGroupCall(long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, java.util.concurrent.Executor, android.telephony.mbms.GroupCallCallback);
}
public class MbmsStreamingSession implements java.lang.AutoCloseable {
@@ -44225,7 +44246,7 @@
public class GroupCall implements java.lang.AutoCloseable {
method public void close();
method public long getTmgi();
- method public void updateGroupCall(int[], int[]);
+ method public void updateGroupCall(java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>);
field public static final int REASON_BY_USER_REQUEST = 1; // 0x1
field public static final int REASON_FREQUENCY_CONFLICT = 3; // 0x3
field public static final int REASON_LEFT_MBMS_BROADCAST_AREA = 6; // 0x6
@@ -44237,11 +44258,10 @@
field public static final int STATE_STOPPED = 1; // 0x1
}
- public class GroupCallCallback {
- ctor public GroupCallCallback();
- method public void onBroadcastSignalStrengthUpdated(int);
- method public void onError(int, java.lang.String);
- method public void onGroupCallStateChanged(int, int);
+ public abstract interface GroupCallCallback {
+ method public abstract void onBroadcastSignalStrengthUpdated(int);
+ method public abstract void onError(int, java.lang.String);
+ method public abstract void onGroupCallStateChanged(int, int);
field public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1; // 0xffffffff
}
@@ -44281,6 +44301,11 @@
field public static final int ERROR_UNABLE_TO_READ_SIM = 206; // 0xce
}
+ public static class MbmsErrors.GroupCallErrors {
+ field public static final int ERROR_DUPLICATE_START_GROUP_CALL = 502; // 0x1f6
+ field public static final int ERROR_UNABLE_TO_START_SERVICE = 501; // 0x1f5
+ }
+
public static class MbmsErrors.InitializationErrors {
field public static final int ERROR_APP_PERMISSIONS_NOT_GRANTED = 102; // 0x66
field public static final int ERROR_DUPLICATE_INITIALIZE = 101; // 0x65
@@ -44293,12 +44318,11 @@
field public static final int ERROR_UNABLE_TO_START_SERVICE = 302; // 0x12e
}
- public class MbmsGroupCallSessionCallback {
- ctor public MbmsGroupCallSessionCallback();
- method public void onAvailableSaisUpdated(java.util.List<java.lang.Integer>, java.util.List<java.util.List<java.lang.Integer>>);
- method public void onError(int, java.lang.String);
- method public void onMiddlewareReady();
- method public void onServiceInterfaceAvailable(java.lang.String, int);
+ public abstract interface MbmsGroupCallSessionCallback {
+ method public abstract void onAvailableSaisUpdated(java.util.List<java.lang.Integer>, java.util.List<java.util.List<java.lang.Integer>>);
+ method public abstract void onError(int, java.lang.String);
+ method public abstract void onMiddlewareReady();
+ method public abstract void onServiceInterfaceAvailable(java.lang.String, int);
}
public class MbmsStreamingSessionCallback {
@@ -49088,7 +49112,7 @@
method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
method public void onProvideAutofillStructure(android.view.ViewStructure, int);
method public void onProvideAutofillVirtualStructure(android.view.ViewStructure, int);
- method public boolean onProvideContentCaptureStructure(android.view.ViewStructure, int);
+ method public void onProvideContentCaptureStructure(android.view.ViewStructure, int);
method public void onProvideStructure(android.view.ViewStructure);
method public void onProvideVirtualStructure(android.view.ViewStructure);
method public android.view.PointerIcon onResolvePointerIcon(android.view.MotionEvent, int);
@@ -49304,6 +49328,8 @@
method public final boolean startDragAndDrop(android.content.ClipData, android.view.View.DragShadowBuilder, java.lang.Object, int);
method public boolean startNestedScroll(int);
method public void stopNestedScroll();
+ method public void transformMatrixToGlobal(android.graphics.Matrix);
+ method public void transformMatrixToLocal(android.graphics.Matrix);
method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
method public void unscheduleDrawable(android.graphics.drawable.Drawable);
method public final void updateDragShadow(android.view.View.DragShadowBuilder);
diff --git a/api/system-current.txt b/api/system-current.txt
index 7bd9ad5..f963c10 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1225,6 +1225,7 @@
method public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
method public abstract int getIntentVerificationStatusAsUser(java.lang.String, int);
+ method public android.content.pm.PackageInfo getPackageInfoAsUser(java.lang.String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public abstract int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -3938,6 +3939,7 @@
public final class ConfigUpdate {
field public static final java.lang.String ACTION_UPDATE_CARRIER_ID_DB = "android.os.action.UPDATE_CARRIER_ID_DB";
field public static final java.lang.String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
+ field public static final java.lang.String ACTION_UPDATE_CONVERSATION_ACTIONS = "android.intent.action.UPDATE_CONVERSATION_ACTIONS";
field public static final java.lang.String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
field public static final java.lang.String ACTION_UPDATE_INTENT_FIREWALL = "android.intent.action.UPDATE_INTENT_FIREWALL";
field public static final java.lang.String ACTION_UPDATE_LANG_ID = "android.intent.action.UPDATE_LANG_ID";
@@ -4936,12 +4938,47 @@
package android.service.intelligence {
+ public final class FillCallback {
+ method public void onSuccess(android.service.intelligence.FillResponse);
+ }
+
+ public final class FillController {
+ method public void autofill(java.util.List<android.util.Pair<android.view.autofill.AutofillId, android.view.autofill.AutofillValue>>);
+ }
+
+ public final class FillRequest {
+ method public android.view.autofill.AutofillId getFocusedId();
+ method public android.service.intelligence.PresentationParams getPresentationParams();
+ method public android.service.intelligence.InteractionSessionId getSessionId();
+ }
+
+ public final class FillResponse implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.intelligence.FillResponse> CREATOR;
+ }
+
+ public static class FillResponse.Builder {
+ ctor public FillResponse.Builder();
+ method public android.service.intelligence.FillResponse build();
+ method public android.service.intelligence.FillResponse.Builder setFillWindow(android.service.intelligence.FillWindow);
+ method public android.service.intelligence.FillResponse.Builder setIgnoredIds(java.util.List<android.view.autofill.AutofillId>);
+ }
+
+ public final class FillWindow {
+ ctor public FillWindow();
+ method public void destroy();
+ method public boolean update(android.service.intelligence.PresentationParams.Area, android.view.View, long);
+ field public static final long FLAG_METADATA_ADDRESS = 1L; // 0x1L
+ }
+
public abstract class IntelligenceService extends android.app.Service {
ctor public IntelligenceService();
method public void onActivitySnapshot(android.service.intelligence.InteractionSessionId, android.service.intelligence.SnapshotData);
method public abstract void onContentCaptureEvent(android.service.intelligence.InteractionSessionId, java.util.List<android.view.intelligence.ContentCaptureEvent>);
method public void onCreateInteractionSession(android.service.intelligence.InteractionContext, android.service.intelligence.InteractionSessionId);
method public void onDestroyInteractionSession(android.service.intelligence.InteractionSessionId);
+ method public void onFillRequest(android.service.intelligence.InteractionSessionId, android.service.intelligence.FillRequest, android.os.CancellationSignal, android.service.intelligence.FillController, android.service.intelligence.FillCallback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.intelligence.IntelligenceService";
}
@@ -4963,6 +5000,23 @@
field public static final android.os.Parcelable.Creator<android.service.intelligence.InteractionSessionId> CREATOR;
}
+ public abstract class PresentationParams {
+ method public int getFlags();
+ method public android.service.intelligence.PresentationParams.Area getFullArea();
+ method public android.service.intelligence.PresentationParams.Area getSuggestionArea();
+ field public static final int FLAG_HINT_GRAVITY_BOTTOM = 2; // 0x2
+ field public static final int FLAG_HINT_GRAVITY_LEFT = 4; // 0x4
+ field public static final int FLAG_HINT_GRAVITY_RIGHT = 8; // 0x8
+ field public static final int FLAG_HINT_GRAVITY_TOP = 1; // 0x1
+ field public static final int FLAG_HOST_IME = 16; // 0x10
+ field public static final int FLAG_HOST_SYSTEM = 32; // 0x20
+ }
+
+ public static abstract class PresentationParams.Area {
+ method public android.graphics.Rect getBounds();
+ method public android.service.intelligence.PresentationParams.Area getSubArea(android.graphics.Rect);
+ }
+
public final class SnapshotData implements android.os.Parcelable {
method public int describeContents();
method public android.app.assist.AssistContent getAssistContent();
@@ -5022,8 +5076,10 @@
method public final void adjustNotification(android.service.notification.Adjustment);
method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
method public final android.os.IBinder onBind(android.content.Intent);
+ method public void onNotificationDirectReply(java.lang.String);
method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel);
+ method public void onNotificationExpansionChanged(java.lang.String, boolean, boolean);
method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, android.service.notification.NotificationStats, int);
method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
method public void onNotificationsSeen(java.util.List<java.lang.String>);
@@ -7021,9 +7077,9 @@
method public int initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException;
method public void onAppCallbackDied(int, int);
method public android.os.IBinder onBind(android.content.Intent);
- method public int startGroupCall(int, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+ method public int startGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, android.telephony.mbms.GroupCallCallback);
method public void stopGroupCall(int, long);
- method public void updateGroupCall(int, long, int[], int[]);
+ method public void updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>);
}
public class MbmsStreamingServiceBase extends android.os.Binder {
@@ -7515,7 +7571,7 @@
method public default void onMovedToDisplay(int, android.content.res.Configuration);
method public abstract void onOverScrolled(int, int, boolean, boolean);
method public default void onProvideAutofillVirtualStructure(android.view.ViewStructure, int);
- method public default boolean onProvideContentCaptureStructure(android.view.ViewStructure, int);
+ method public default void onProvideContentCaptureStructure(android.view.ViewStructure, int);
method public abstract void onProvideVirtualStructure(android.view.ViewStructure);
method public abstract void onScrollChanged(int, int, int, int);
method public abstract void onSizeChanged(int, int, int, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 1c01cf1..0fa83f1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -985,6 +985,7 @@
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
field public static final java.lang.String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
+ field public static final java.lang.String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS = "autofill_smart_suggestion_emulation_flags";
field public static final java.lang.String AUTOMATIC_POWER_SAVER_MODE = "automatic_power_saver_mode";
field public static final java.lang.String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold";
field public static final java.lang.String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
@@ -1155,8 +1156,10 @@
method public final void adjustNotification(android.service.notification.Adjustment);
method public final void adjustNotifications(java.util.List<android.service.notification.Adjustment>);
method public final android.os.IBinder onBind(android.content.Intent);
+ method public void onNotificationDirectReply(java.lang.String);
method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification);
method public android.service.notification.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, android.app.NotificationChannel);
+ method public void onNotificationExpansionChanged(java.lang.String, boolean, boolean);
method public abstract void onNotificationSnoozedUntilContext(android.service.notification.StatusBarNotification, java.lang.String);
method public void onNotificationsSeen(java.util.List<java.lang.String>);
method public final void unsnoozeNotification(java.lang.String);
@@ -1318,9 +1321,9 @@
method public int initialize(android.telephony.mbms.MbmsGroupCallSessionCallback, int) throws android.os.RemoteException;
method public void onAppCallbackDied(int, int);
method public android.os.IBinder onBind(android.content.Intent);
- method public int startGroupCall(int, long, int[], int[], android.telephony.mbms.GroupCallCallback);
+ method public int startGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>, android.telephony.mbms.GroupCallCallback);
method public void stopGroupCall(int, long);
- method public void updateGroupCall(int, long, int[], int[]);
+ method public void updateGroupCall(int, long, java.util.List<java.lang.Integer>, java.util.List<java.lang.Integer>);
}
public class MbmsStreamingServiceBase extends android.os.Binder {
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index a826ec7..3723fce 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -17,6 +17,7 @@
package com.android.commands.bmgr;
import android.annotation.IntDef;
+import android.annotation.UserIdInt;
import android.app.backup.BackupManager;
import android.app.backup.BackupManagerMonitor;
import android.app.backup.BackupProgress;
@@ -29,6 +30,7 @@
import android.app.backup.ISelectBackupTransportCallback;
import android.app.backup.RestoreSet;
import android.content.ComponentName;
+import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.os.Bundle;
@@ -37,8 +39,10 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArraySet;
+import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -49,20 +53,34 @@
import java.util.Set;
import java.util.concurrent.CountDownLatch;
-public final class Bmgr {
- IBackupManager mBmgr;
- IRestoreSession mRestore;
+/**
+ * Adb shell command for {@link android.app.backup.IBackupManager}.
+ */
+public class Bmgr {
+ public static final String TAG = "Bmgr";
- static final String BMGR_NOT_RUNNING_ERR =
+ private final IBackupManager mBmgr;
+ private IRestoreSession mRestore;
+
+ private static final String BMGR_NOT_RUNNING_ERR =
"Error: Could not access the Backup Manager. Is the system running?";
- static final String TRANSPORT_NOT_RUNNING_ERR =
+ private static final String TRANSPORT_NOT_RUNNING_ERR =
"Error: Could not access the backup transport. Is the system running?";
- static final String PM_NOT_RUNNING_ERR =
+ private static final String PM_NOT_RUNNING_ERR =
"Error: Could not access the Package Manager. Is the system running?";
private String[] mArgs;
private int mNextArg;
+ @VisibleForTesting
+ Bmgr(IBackupManager bmgr) {
+ mBmgr = bmgr;
+ }
+
+ Bmgr() {
+ mBmgr = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));
+ }
+
public static void main(String[] args) {
try {
new Bmgr().run(args);
@@ -78,71 +96,73 @@
return;
}
- if (!isBmgrActive()) {
+ mArgs = args;
+ mNextArg = 0;
+ int userId = parseUserId();
+ String op = nextArg();
+ Slog.v(TAG, "Running " + op + " for user:" + userId);
+
+ if (!isBmgrActive(userId)) {
return;
}
- mArgs = args;
- String op = args[0];
- mNextArg = 1;
-
if ("enabled".equals(op)) {
- doEnabled();
+ doEnabled(userId);
return;
}
if ("enable".equals(op)) {
- doEnable();
+ doEnable(userId);
return;
}
if ("run".equals(op)) {
- doRun();
+ doRun(userId);
return;
}
if ("backup".equals(op)) {
- doBackup();
+ doBackup(userId);
return;
}
if ("init".equals(op)) {
- doInit();
+ doInit(userId);
return;
}
if ("list".equals(op)) {
- doList();
+ doList(userId);
return;
}
if ("restore".equals(op)) {
- doRestore();
+ doRestore(userId);
return;
}
if ("transport".equals(op)) {
- doTransport();
+ doTransport(userId);
return;
}
if ("wipe".equals(op)) {
- doWipe();
+ doWipe(userId);
return;
}
if ("fullbackup".equals(op)) {
- doFullTransportBackup();
+ doFullTransportBackup(userId);
return;
}
if ("backupnow".equals(op)) {
- doBackupNow();
+ doBackupNow(userId);
return;
}
if ("cancel".equals(op)) {
- doCancel();
+ doCancel(userId);
return;
}
@@ -155,15 +175,14 @@
showUsage();
}
- private boolean isBmgrActive() {
- mBmgr = IBackupManager.Stub.asInterface(ServiceManager.getService("backup"));
+ boolean isBmgrActive(@UserIdInt int userId) {
if (mBmgr == null) {
System.err.println(BMGR_NOT_RUNNING_ERR);
return false;
}
try {
- if (!mBmgr.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
+ if (!mBmgr.isBackupServiceActive(userId)) {
System.err.println(BMGR_NOT_RUNNING_ERR);
return false;
}
@@ -180,7 +199,7 @@
return enabled ? "enabled" : "disabled";
}
- private void doEnabled() {
+ private void doEnabled(@UserIdInt int userId) {
try {
boolean isEnabled = mBmgr.isBackupEnabled();
System.out.println("Backup Manager currently "
@@ -191,7 +210,7 @@
}
}
- private void doEnable() {
+ private void doEnable(@UserIdInt int userId) {
String arg = nextArg();
if (arg == null) {
showUsage();
@@ -211,7 +230,7 @@
}
}
- private void doRun() {
+ void doRun(@UserIdInt int userId) {
try {
mBmgr.backupNow();
} catch (RemoteException e) {
@@ -220,7 +239,7 @@
}
}
- private void doBackup() {
+ private void doBackup(@UserIdInt int userId) {
String pkg = nextArg();
if (pkg == null) {
showUsage();
@@ -235,7 +254,7 @@
}
}
- private void doFullTransportBackup() {
+ private void doFullTransportBackup(@UserIdInt int userId) {
System.out.println("Performing full transport backup");
String pkg;
@@ -354,8 +373,8 @@
}
}
- private void backupNowAllPackages(boolean nonIncrementalBackup, @Monitor int monitorState) {
- int userId = UserHandle.USER_SYSTEM;
+ private void backupNowAllPackages(@UserIdInt int userId, boolean nonIncrementalBackup,
+ @Monitor int monitorState) {
IPackageManager mPm =
IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
if (mPm == null) {
@@ -379,11 +398,13 @@
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
}
- backupNowPackages(Arrays.asList(filteredPackages), nonIncrementalBackup, monitorState);
+ backupNowPackages(userId, Arrays.asList(filteredPackages), nonIncrementalBackup,
+ monitorState);
}
}
private void backupNowPackages(
+ @UserIdInt int userId,
List<String> packages, boolean nonIncrementalBackup, @Monitor int monitorState) {
int flags = 0;
if (nonIncrementalBackup) {
@@ -412,7 +433,7 @@
}
}
- private void doBackupNow() {
+ private void doBackupNow(@UserIdInt int userId) {
String pkg;
boolean backupAll = false;
boolean nonIncrementalBackup = false;
@@ -439,20 +460,20 @@
if (allPkgs.size() == 0) {
System.out.println("Running " + (nonIncrementalBackup ? "non-" : "") +
"incremental backup for all packages.");
- backupNowAllPackages(nonIncrementalBackup, monitor);
+ backupNowAllPackages(userId, nonIncrementalBackup, monitor);
} else {
System.err.println("Provide only '--all' flag or list of packages.");
}
} else if (allPkgs.size() > 0) {
System.out.println("Running " + (nonIncrementalBackup ? "non-" : "") +
"incremental backup for " + allPkgs.size() +" requested packages.");
- backupNowPackages(allPkgs, nonIncrementalBackup, monitor);
+ backupNowPackages(userId, allPkgs, nonIncrementalBackup, monitor);
} else {
System.err.println("Provide '--all' flag or list of packages.");
}
}
- private void doCancel() {
+ private void doCancel(@UserIdInt int userId) {
String arg = nextArg();
if ("backups".equals(arg)) {
try {
@@ -467,7 +488,7 @@
System.err.println("Unknown command.");
}
- private void doTransport() {
+ private void doTransport(@UserIdInt int userId) {
try {
String which = nextArg();
if (which == null) {
@@ -531,7 +552,7 @@
}
}
- private void doWipe() {
+ private void doWipe(@UserIdInt int userId) {
String transport = nextArg();
if (transport == null) {
showUsage();
@@ -563,7 +584,7 @@
}
}
- private void doInit() {
+ private void doInit(@UserIdInt int userId) {
ArraySet<String> transports = new ArraySet<>();
String transport;
while ((transport = nextArg()) != null) {
@@ -586,7 +607,7 @@
}
}
- private void doList() {
+ private void doList(@UserIdInt int userId) {
String arg = nextArg(); // sets, transports, packages set#
if ("transports".equals(arg)) {
doListTransports();
@@ -603,8 +624,6 @@
if ("sets".equals(arg)) {
doListRestoreSets();
- } else if ("transports".equals(arg)) {
- doListTransports();
}
mRestore.endRestoreSession();
@@ -717,7 +736,7 @@
}
}
- private void doRestore() {
+ private void doRestore(@UserIdInt int userId) {
String arg = nextArg();
if (arg == null) {
showUsage();
@@ -830,8 +849,18 @@
return arg;
}
+ private int parseUserId() {
+ String arg = nextArg();
+ if ("--user".equals(arg)) {
+ return UserHandle.parseUserArg(nextArg());
+ } else {
+ mNextArg--;
+ return UserHandle.USER_SYSTEM;
+ }
+ }
+
private static void showUsage() {
- System.err.println("usage: bmgr [backup|restore|list|transport|run]");
+ System.err.println("usage: bmgr [--user <userId>] [backup|restore|list|transport|run]");
System.err.println(" bmgr backup PACKAGE");
System.err.println(" bmgr enable BOOL");
System.err.println(" bmgr enabled");
@@ -847,6 +876,10 @@
System.err.println(" bmgr cancel backups");
System.err.println(" bmgr init TRANSPORT...");
System.err.println("");
+ System.err.println("The '--user' option specifies the user on which the operation is run.");
+ System.err.println("It must be the first argument before the operation.");
+ System.err.println("The default value is 0 which is the system user.");
+ System.err.println("");
System.err.println("The 'backup' command schedules a backup pass for the named package.");
System.err.println("Note that the backup pass will effectively be a no-op if the package");
System.err.println("does not actually have changed data to store.");
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 5a6c813..7d675ce 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -18,7 +18,7 @@
tidy: true,
tidy_flags: [
"-system-headers",
- "-warnings-as-errors=*",
+// b/120024673 "-warnings-as-errors=*",
],
srcs: [
"libidmap2/BinaryStreamVisitor.cpp",
@@ -64,7 +64,7 @@
tidy: true,
tidy_flags: [
"-system-headers",
- "-warnings-as-errors=*",
+// b/120024673 "-warnings-as-errors=*",
],
srcs: [
"tests/BinaryStreamVisitorTests.cpp",
@@ -118,7 +118,7 @@
tidy: true,
tidy_flags: [
"-system-headers",
- "-warnings-as-errors=*",
+// b/120024673 "-warnings-as-errors=*",
],
srcs: [
"idmap2/Create.cpp",
@@ -165,7 +165,7 @@
],
tidy_flags: [
"-system-headers",
- "-warnings-as-errors=*",
+// b/120024673 "-warnings-as-errors=*",
],
srcs: [
":idmap2_aidl",
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 8a770b9..ab1bf36 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -189,10 +189,10 @@
Landroid/app/IUiModeManager;->disableCarMode(I)V
Landroid/app/IUserSwitchObserver$Stub;-><init>()V
Landroid/app/IWallpaperManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/IWallpaperManager;
-Landroid/app/IWallpaperManager;->getHeightHint()I
+Landroid/app/IWallpaperManager;->getHeightHint(I)I
Landroid/app/IWallpaperManager;->getWallpaper(Ljava/lang/String;Landroid/app/IWallpaperManagerCallback;ILandroid/os/Bundle;I)Landroid/os/ParcelFileDescriptor;
Landroid/app/IWallpaperManager;->getWallpaperInfo(I)Landroid/app/WallpaperInfo;
-Landroid/app/IWallpaperManager;->getWidthHint()I
+Landroid/app/IWallpaperManager;->getWidthHint(I)I
Landroid/app/IWallpaperManager;->hasNamedWallpaper(Ljava/lang/String;)Z
Landroid/app/IWallpaperManager;->setWallpaperComponent(Landroid/content/ComponentName;)V
Landroid/app/IWallpaperManagerCallback$Stub;-><init>()V
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 805fb68..41166dd 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -157,7 +157,6 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.Preconditions;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.org.conscrypt.OpenSSLSocketImpl;
import com.android.org.conscrypt.TrustedCertificateStore;
@@ -5324,16 +5323,6 @@
}
}
- /**
- * Updates the application info.
- *
- * This only works in the system process. Must be called on the main thread.
- */
- public void handleSystemApplicationInfoChanged(@NonNull ApplicationInfo ai) {
- Preconditions.checkState(mSystemThread, "Must only be called in the system process");
- handleApplicationInfoChanged(ai);
- }
-
void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) {
// Updates triggered by package installation go through a package update
// receiver. Here we try to capture ApplicationInfo changes that are
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 5ef4be1..00547b4 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -87,24 +87,24 @@
/**
* Sets the dimension hint for the wallpaper. These hints indicate the desired
- * minimum width and height for the wallpaper.
+ * minimum width and height for the wallpaper in a particular display.
*/
- void setDimensionHints(in int width, in int height, in String callingPackage);
+ void setDimensionHints(in int width, in int height, in String callingPackage, int displayId);
/**
- * Returns the desired minimum width for the wallpaper.
+ * Returns the desired minimum width for the wallpaper in a particular display.
*/
- int getWidthHint();
+ int getWidthHint(int displayId);
/**
- * Returns the desired minimum height for the wallpaper.
+ * Returns the desired minimum height for the wallpaper in a particular display.
*/
- int getHeightHint();
+ int getHeightHint(int displayId);
/**
* Sets extra padding that we would like the wallpaper to have outside of the display.
*/
- void setDisplayPadding(in Rect padding, in String callingPackage);
+ void setDisplayPadding(in Rect padding, in String callingPackage, int displayId);
/**
* Returns the name of the wallpaper. Private API.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index f2a3e44..75b56f3 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1338,6 +1338,11 @@
private int mBadgeIcon = BADGE_ICON_NONE;
/**
+ * Determines whether the platform can generate contextual actions for a notification.
+ */
+ private boolean mAllowSystemGeneratedContextualActions = true;
+
+ /**
* Structure to encapsulate a named action that can be shown as part of this notification.
* It must include an icon, a label, and a {@link PendingIntent} to be fired when the action is
* selected by the user.
@@ -2238,6 +2243,8 @@
if (parcel.readInt() != 0) {
mAppOverlayIntent = PendingIntent.CREATOR.createFromParcel(parcel);
}
+
+ mAllowSystemGeneratedContextualActions = parcel.readBoolean();
}
@Override
@@ -2353,6 +2360,7 @@
that.mSettingsText = this.mSettingsText;
that.mGroupAlertBehavior = this.mGroupAlertBehavior;
that.mAppOverlayIntent = this.mAppOverlayIntent;
+ that.mAllowSystemGeneratedContextualActions = this.mAllowSystemGeneratedContextualActions;
if (!heavy) {
that.lightenPayload(); // will clean out extras
@@ -2681,6 +2689,8 @@
parcel.writeInt(0);
}
+ parcel.writeBoolean(mAllowSystemGeneratedContextualActions);
+
// mUsesStandardHeader is not written because it should be recomputed in listeners
}
@@ -3101,6 +3111,10 @@
return mAppOverlayIntent;
}
+ public boolean getAllowSystemGeneratedContextualActions() {
+ return mAllowSystemGeneratedContextualActions;
+ }
+
/**
* The small icon representing this notification in the status bar and content view.
*
@@ -5657,6 +5671,15 @@
}
/**
+ * Determines whether the platform can generate contextual actions for a notification.
+ * By default this is true.
+ */
+ public Builder setAllowSystemGeneratedContextualActions(boolean allowed) {
+ mN.mAllowSystemGeneratedContextualActions = allowed;
+ return this;
+ }
+
+ /**
* @deprecated Use {@link #build()} instead.
*/
@Deprecated
diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java
index e33d1fe..3ea3da2 100644
--- a/core/java/android/app/WallpaperInfo.java
+++ b/core/java/android/app/WallpaperInfo.java
@@ -36,6 +36,7 @@
import android.util.AttributeSet;
import android.util.Printer;
import android.util.Xml;
+import android.view.SurfaceHolder;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -79,6 +80,7 @@
final boolean mShowMetadataInPreview;
final boolean mSupportsAmbientMode;
final String mSettingsSliceUri;
+ final boolean mSupportMultipleDisplays;
/**
* Constructor.
@@ -143,6 +145,9 @@
false);
mSettingsSliceUri = sa.getString(
com.android.internal.R.styleable.Wallpaper_settingsSliceUri);
+ mSupportMultipleDisplays = sa.getBoolean(
+ com.android.internal.R.styleable.Wallpaper_supportsMultipleDisplays,
+ false);
sa.recycle();
} catch (NameNotFoundException e) {
@@ -163,6 +168,7 @@
mShowMetadataInPreview = source.readInt() != 0;
mSupportsAmbientMode = source.readInt() != 0;
mSettingsSliceUri = source.readString();
+ mSupportMultipleDisplays = source.readInt() != 0;
mService = ResolveInfo.CREATOR.createFromParcel(source);
}
@@ -358,6 +364,19 @@
return Uri.parse(mSettingsSliceUri);
}
+ /**
+ * Returns whether this wallpaper service can support multiple engines to render on each surface
+ * independently. An example use case is a multi-display set-up where the wallpaper service can
+ * render surfaces to each of the connected displays.
+ *
+ * @see WallpaperService#onCreateEngine()
+ * @see WallpaperService.Engine#onCreate(SurfaceHolder)
+ * @return {@code true} if multiple engines can render independently on each surface.
+ */
+ public boolean supportsMultipleDisplays() {
+ return mSupportMultipleDisplays;
+ }
+
public void dump(Printer pw, String prefix) {
pw.println(prefix + "Service:");
mService.dump(pw, prefix + " ");
@@ -387,6 +406,7 @@
dest.writeInt(mShowMetadataInPreview ? 1 : 0);
dest.writeInt(mSupportsAmbientMode ? 1 : 0);
dest.writeString(mSettingsSliceUri);
+ dest.writeInt(mSupportMultipleDisplays ? 1 : 0);
mService.writeToParcel(dest, flags);
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index bebe79e..27471ca 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1485,7 +1485,7 @@
throw new RuntimeException(new DeadSystemException());
}
try {
- return sGlobals.mService.getWidthHint();
+ return sGlobals.mService.getWidthHint(mContext.getDisplayId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1511,7 +1511,7 @@
throw new RuntimeException(new DeadSystemException());
}
try {
- return sGlobals.mService.getHeightHint();
+ return sGlobals.mService.getHeightHint(mContext.getDisplayId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1572,7 +1572,7 @@
throw new RuntimeException(new DeadSystemException());
} else {
sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight,
- mContext.getOpPackageName());
+ mContext.getOpPackageName(), mContext.getDisplayId());
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1597,7 +1597,8 @@
Log.w(TAG, "WallpaperService not running");
throw new RuntimeException(new DeadSystemException());
} else {
- sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName());
+ sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName(),
+ mContext.getDisplayId());
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 24ee7f7..00c1863 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -53,6 +53,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.Process;
@@ -87,6 +88,7 @@
import com.android.org.conscrypt.TrustedCertificateStore;
import java.io.ByteArrayInputStream;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -1930,6 +1932,48 @@
public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3;
/**
+ * Callback used in {@link #installSystemUpdate} to indicate that there was an error while
+ * trying to install an update.
+ */
+ public abstract static class InstallUpdateCallback {
+ /** Represents an unknown error while trying to install an update. */
+ public static final int UPDATE_ERROR_UNKNOWN = 1;
+
+ /** Represents the update file being intended for different OS version. */
+ public static final int UPDATE_ERROR_INCORRECT_OS_VERSION = 2;
+
+ /**
+ * Represents the update file being wrong, i.e. payloads are mismatched, wrong compressions
+ * method.
+ */
+ public static final int UPDATE_ERROR_UPDATE_FILE_INVALID = 3;
+
+ /** Represents that the file could not be found. */
+ public static final int UPDATE_ERROR_FILE_NOT_FOUND = 4;
+
+ /** Represents the battery being too low to apply an update. */
+ public static final int UPDATE_ERROR_BATTERY_LOW = 5;
+
+ /** Method invoked when there was an error while installing an update. */
+ public void onInstallUpdateError(
+ @InstallUpdateCallbackErrorConstants int errorCode, String errorMessage) {
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @IntDef(prefix = { "UPDATE_ERROR_" }, value = {
+ InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
+ InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION,
+ InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+ InstallUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND,
+ InstallUpdateCallback.UPDATE_ERROR_BATTERY_LOW
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InstallUpdateCallbackErrorConstants {}
+
+ /**
* Return true if the given administrator component is currently active (enabled) in the system.
*
* @param admin The administrator component to check for.
@@ -6796,7 +6840,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface CreateAndManageUserFlags {}
-
/**
* Called by a device owner to create a user with the specified name and a given component of
* the calling package as profile owner. The UserHandle returned by this method should not be
@@ -9827,6 +9870,62 @@
}
/**
+ * Called by device owner to install a system update from the given file. The device will be
+ * rebooted in order to finish installing the update. Note that if the device is rebooted, this
+ * doesn't necessarily mean that the update has been applied successfully. The caller should
+ * additionally check the system version with {@link android.os.Build#FINGERPRINT} or {@link
+ * android.os.Build.VERSION}. If an error occurs during processing the OTA before the reboot,
+ * the caller will be notified by {@link InstallUpdateCallback}. If device does not have
+ * sufficient battery level, the installation will fail with error {@link
+ * InstallUpdateCallback#UPDATE_ERROR_BATTERY_LOW}.
+ *
+ * @param admin The {@link DeviceAdminReceiver} that this request is associated with.
+ * @param updateFilePath An Uri of the file that contains the update. The file should be
+ * readable by the calling app.
+ * @param executor The executor through which the callback should be invoked.
+ * @param callback A callback object that will inform the caller when installing an update
+ * fails.
+ */
+ public void installSystemUpdate(
+ @NonNull ComponentName admin, @NonNull Uri updateFilePath,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull InstallUpdateCallback callback) {
+ throwIfParentInstance("installUpdate");
+ if (mService == null) {
+ return;
+ }
+ try (ParcelFileDescriptor fileDescriptor = mContext.getContentResolver()
+ .openFileDescriptor(updateFilePath, "r")) {
+ mService.installUpdateFromFile(
+ admin, fileDescriptor, new StartInstallingUpdateCallback.Stub() {
+ @Override
+ public void onStartInstallingUpdateError(
+ int errorCode, String errorMessage) {
+ executeCallback(errorCode, errorMessage, executor, callback);
+ }
+ });
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, e);
+ executeCallback(
+ InstallUpdateCallback.UPDATE_ERROR_FILE_NOT_FOUND, Log.getStackTraceString(e),
+ executor, callback);
+ } catch (IOException e) {
+ Log.w(TAG, e);
+ executeCallback(
+ InstallUpdateCallback.UPDATE_ERROR_UNKNOWN, Log.getStackTraceString(e),
+ executor, callback);
+ }
+ }
+
+ private void executeCallback(int errorCode, String errorMessage,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull InstallUpdateCallback callback) {
+ executor.execute(() -> callback.onInstallUpdateError(errorCode, errorMessage));
+ }
+
+ /**
* Returns the system-wide Private DNS mode.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 918c127..60f79d6 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -20,6 +20,7 @@
import android.app.admin.NetworkEvent;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
+import android.app.admin.StartInstallingUpdateCallback;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.app.admin.PasswordMetrics;
@@ -419,4 +420,6 @@
String getGlobalPrivateDnsHost(in ComponentName admin);
void grantDeviceIdsAccessToProfileOwner(in ComponentName who, int userId);
+
+ void installUpdateFromFile(in ComponentName admin, in ParcelFileDescriptor updateFileDescriptor, in StartInstallingUpdateCallback listener);
}
diff --git a/core/java/android/app/admin/StartInstallingUpdateCallback.aidl b/core/java/android/app/admin/StartInstallingUpdateCallback.aidl
new file mode 100644
index 0000000..df04707
--- /dev/null
+++ b/core/java/android/app/admin/StartInstallingUpdateCallback.aidl
@@ -0,0 +1,27 @@
+/*
+**
+** Copyright 2018, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.app.admin;
+
+/**
+* Callback used between {@link DevicePolicyManager} and {@link DevicePolicyManagerService} to
+* indicate that starting installing an update is finished.
+* {@hide}
+*/
+oneway interface StartInstallingUpdateCallback {
+ void onStartInstallingUpdateError(int errorCode, String errorMessage);
+}
\ No newline at end of file
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 5514851..3f34803 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -193,10 +193,6 @@
/** @hide */
public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000D;
/** @hide */
- public static final int REASON_SUB_USAGE_FOREGROUND_SERVICE_START = 0x000E;
- /** @hide */
- public static final int REASON_SUB_USAGE_FOREGROUND_SERVICE_STOP = 0x000F;
- /** @hide */
public static final int REASON_SUB_PREDICTED_RESTORED = 0x0001;
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 949cdd6..437039d 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -42,7 +42,6 @@
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.DeadObjectException;
@@ -3244,18 +3243,8 @@
Objects.requireNonNull(uri);
Objects.requireNonNull(size);
- // Older apps might be relying on mutable results, so only consider
- // giving them hardware bitmaps once they target Q or higher. If modern
- // apps need mutable thumbnails, they can always roll their own logic.
- final int allocator;
- if (getTargetSdkVersion() >= Build.VERSION_CODES.Q) {
- allocator = ImageDecoder.ALLOCATOR_DEFAULT;
- } else {
- allocator = ImageDecoder.ALLOCATOR_SOFTWARE;
- }
-
try (ContentProviderClient client = acquireContentProviderClient(uri)) {
- return loadThumbnail(client, uri, size, signal, allocator);
+ return loadThumbnail(client, uri, size, signal, ImageDecoder.ALLOCATOR_SOFTWARE);
}
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 10c6bc6..6bfddb0 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1767,6 +1767,9 @@
* that should be managed by the launched UI.
* </p>
* <p>
+ * <li> {@link #EXTRA_USER} specifies the UserHandle of the user that owns the app.
+ * </p>
+ * <p>
* Output: Nothing.
* </p>
*
@@ -3586,6 +3589,17 @@
public static final String
ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
+
+ /**
+ * Activity Action: Perform text translation.
+ * <p>
+ * Input: {@link #EXTRA_TEXT getCharSequence(EXTRA_TEXT)} is the text to translate.
+ * <p>
+ * Output: nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_TRANSLATE = "android.intent.action.TRANSLATE";
+
/**
* Broadcast Action: List of dynamic sensor is changed due to new sensor being connected or
* exisiting sensor being disconnected.
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 361beba..ad06be3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3143,6 +3143,33 @@
@PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
/**
+ * Retrieve overall information about an application package that is
+ * installed on the system.
+ *
+ * @param packageName The full name (i.e. com.google.apps.contacts) of the
+ * desired package.
+ * @param flags Additional option flags to modify the data returned.
+ * @param userHandle The user.
+ * @return A PackageInfo object containing information about the package. If
+ * flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the package
+ * is not found in the list of installed applications, the package
+ * information is retrieved from the list of uninstalled
+ * applications (which includes installed applications as well as
+ * applications with data directory i.e. applications which had been
+ * deleted with {@code DONT_DELETE_DATA} flag set).
+ * @throws NameNotFoundException if a package with the given name cannot be
+ * found on the system.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+ @SystemApi
+ public @NonNull PackageInfo getPackageInfoAsUser(@NonNull String packageName,
+ @PackageInfoFlags int flags,
+ @NonNull UserHandle userHandle) throws NameNotFoundException {
+ return getPackageInfoAsUser(packageName, flags, userHandle.getIdentifier());
+ }
+
+ /**
* Map from the current package names in use on the device to whatever
* the current canonical name of that package is.
* @param names Array of current names to be mapped.
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
index 8599f47..3552655 100644
--- a/core/java/android/net/IpSecConfig.java
+++ b/core/java/android/net/IpSecConfig.java
@@ -65,10 +65,13 @@
// An interval, in seconds between the NattKeepalive packets
private int mNattKeepaliveInterval;
- // XFRM mark and mask
+ // XFRM mark and mask; defaults to 0 (no mark/mask)
private int mMarkValue;
private int mMarkMask;
+ // XFRM interface id
+ private int mXfrmInterfaceId;
+
/** Set the mode for this IPsec transform */
public void setMode(int mode) {
mMode = mode;
@@ -125,14 +128,30 @@
mNattKeepaliveInterval = interval;
}
+ /**
+ * Sets the mark value
+ *
+ * <p>Internal (System server) use only. Marks passed in by users will be overwritten or
+ * ignored.
+ */
public void setMarkValue(int mark) {
mMarkValue = mark;
}
+ /**
+ * Sets the mark mask
+ *
+ * <p>Internal (System server) use only. Marks passed in by users will be overwritten or
+ * ignored.
+ */
public void setMarkMask(int mask) {
mMarkMask = mask;
}
+ public void setXfrmInterfaceId(int xfrmInterfaceId) {
+ mXfrmInterfaceId = xfrmInterfaceId;
+ }
+
// Transport or Tunnel
public int getMode() {
return mMode;
@@ -190,6 +209,10 @@
return mMarkMask;
}
+ public int getXfrmInterfaceId() {
+ return mXfrmInterfaceId;
+ }
+
// Parcelable Methods
@Override
@@ -213,6 +236,7 @@
out.writeInt(mNattKeepaliveInterval);
out.writeInt(mMarkValue);
out.writeInt(mMarkMask);
+ out.writeInt(mXfrmInterfaceId);
}
@VisibleForTesting
@@ -235,6 +259,7 @@
mNattKeepaliveInterval = c.mNattKeepaliveInterval;
mMarkValue = c.mMarkValue;
mMarkMask = c.mMarkMask;
+ mXfrmInterfaceId = c.mXfrmInterfaceId;
}
private IpSecConfig(Parcel in) {
@@ -255,6 +280,7 @@
mNattKeepaliveInterval = in.readInt();
mMarkValue = in.readInt();
mMarkMask = in.readInt();
+ mXfrmInterfaceId = in.readInt();
}
@Override
@@ -289,6 +315,8 @@
.append(mMarkValue)
.append(", mMarkMask=")
.append(mMarkMask)
+ .append(", mXfrmInterfaceId=")
+ .append(mXfrmInterfaceId)
.append("}");
return strBuilder.toString();
@@ -320,10 +348,10 @@
&& lhs.mNattKeepaliveInterval == rhs.mNattKeepaliveInterval
&& lhs.mSpiResourceId == rhs.mSpiResourceId
&& IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption)
- && IpSecAlgorithm.equals(
- lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption)
+ && IpSecAlgorithm.equals(lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption)
&& IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication)
&& lhs.mMarkValue == rhs.mMarkValue
- && lhs.mMarkMask == rhs.mMarkMask);
+ && lhs.mMarkMask == rhs.mMarkMask
+ && lhs.mXfrmInterfaceId == rhs.mXfrmInterfaceId);
}
}
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index 720c167..97d72f0 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -360,6 +360,16 @@
}
/**
+ * Returns the number of binder proxies held in this process.
+ * @return number of binder proxies in this process
+ */
+ public static int getProxyCount() {
+ synchronized (sProxyMap) {
+ return sProxyMap.size();
+ }
+ }
+
+ /**
* Dump proxy debug information.
*
* @hide
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
index 7858c59..767c15c 100644
--- a/core/java/android/os/ConfigUpdate.java
+++ b/core/java/android/os/ConfigUpdate.java
@@ -83,6 +83,14 @@
= "android.intent.action.UPDATE_SMART_SELECTION";
/**
+ * Update conversation actions model file.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_UPDATE_CONVERSATION_ACTIONS
+ = "android.intent.action.UPDATE_CONVERSATION_ACTIONS";
+
+ /**
* Update network watchlist config file.
* @hide
*/
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 16d454d..e032c18 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -1232,7 +1232,7 @@
public static Bitmap getDocumentThumbnail(ContentProviderClient client, Uri documentUri,
Point size, CancellationSignal signal) throws IOException {
return ContentResolver.loadThumbnail(client, documentUri, Point.convert(size), signal,
- ImageDecoder.ALLOCATOR_DEFAULT);
+ ImageDecoder.ALLOCATOR_SOFTWARE);
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 30bcbf4..dbdeb70 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1710,6 +1710,15 @@
/** @hide - Private call() method to reset to defaults the 'secure' table */
public static final String CALL_METHOD_RESET_SECURE = "RESET_secure";
+ /** @hide - Private call() method to query the 'system' table */
+ public static final String CALL_METHOD_LIST_SYSTEM = "LIST_system";
+
+ /** @hide - Private call() method to query the 'secure' table */
+ public static final String CALL_METHOD_LIST_SECURE = "LIST_secure";
+
+ /** @hide - Private call() method to query the 'global' table */
+ public static final String CALL_METHOD_LIST_GLOBAL = "LIST_global";
+
/**
* Activity Extra: Limit available options in launched activity based on the given authority.
* <p>
@@ -9330,6 +9339,13 @@
"location_background_throttle_package_whitelist";
/**
+ * Whether to disable location status callbacks in preparation for deprecation.
+ * @hide
+ */
+ public static final String LOCATION_DISABLE_STATUS_CALLBACKS =
+ "location_disable_status_callbacks";
+
+ /**
* Maximum staleness allowed for last location when returned to clients with only foreground
* location permissions.
* @hide
@@ -12129,6 +12145,20 @@
"smart_selection_metadata_url";
/**
+ * URL for conversation actions model updates
+ * @hide
+ */
+ public static final String CONVERSATION_ACTIONS_UPDATE_CONTENT_URL =
+ "conversation_actions_content_url";
+
+ /**
+ * URL for conversation actions model update metadata
+ * @hide
+ */
+ public static final String CONVERSATION_ACTIONS_UPDATE_METADATA_URL =
+ "conversation_actions_metadata_url";
+
+ /**
* SELinux enforcement status. If 0, permissive; if 1, enforcing.
* @hide
*/
@@ -12162,7 +12192,7 @@
/**
* Defines global runtime overrides to window policy.
*
- * See {@link com.android.server.policy.PolicyControl} for value format.
+ * See {@link com.android.server.wm.PolicyControl} for value format.
*
* @hide
*/
@@ -12678,6 +12708,17 @@
public static final String AUTOFILL_MAX_VISIBLE_DATASETS = "autofill_max_visible_datasets";
/**
+ * Used to emulate Smart Suggestion for Augmented Autofill during development
+ *
+ * <p>Valid values: {@code 0x1} for IME and/or {@code 0x2} for popup window.
+ *
+ * @hide
+ */
+ @TestApi
+ public static final String AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS =
+ "autofill_smart_suggestion_emulation_flags";
+
+ /**
* Exemptions to the hidden API blacklist.
*
* @hide
diff --git a/core/java/android/service/intelligence/FillCallback.java b/core/java/android/service/intelligence/FillCallback.java
new file mode 100644
index 0000000..af2da79
--- /dev/null
+++ b/core/java/android/service/intelligence/FillCallback.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.intelligence;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+/**
+ * Callback used to indicate at {@link FillRequest} has been fulfilled.
+ *
+ * @hide
+ */
+@SystemApi
+public final class FillCallback {
+
+ FillCallback() {}
+
+ /**
+ * Sets the response associated with the request.
+ *
+ * @param response response associated with the request, or {@code null} if the service
+ * could not provide autofill for the request.
+ */
+ public void onSuccess(@Nullable FillResponse response) {
+ final FillWindow fillWindow = response.getFillWindow();
+ if (fillWindow != null) {
+ fillWindow.show();
+ }
+ // TODO(b/111330312): properly implement on server-side by updating the Session state
+ // accordingly (and adding CTS tests)
+ }
+}
diff --git a/core/java/android/service/intelligence/FillController.java b/core/java/android/service/intelligence/FillController.java
new file mode 100644
index 0000000..c5e1242
--- /dev/null
+++ b/core/java/android/service/intelligence/FillController.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.intelligence;
+
+import static android.service.intelligence.IntelligenceService.DEBUG;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+import android.service.intelligence.IntelligenceService.AutofillProxy;
+import android.util.Log;
+import android.util.Pair;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Object used to interact with the autofill system.
+ *
+ * @hide
+ */
+@SystemApi
+public final class FillController {
+ private static final String TAG = "FillController";
+
+ private final AutofillProxy mProxy;
+
+ FillController(@NonNull AutofillProxy proxy) {
+ mProxy = proxy;
+ }
+
+ /**
+ * Fills the activity with the provided values.
+ *
+ * <p>As a side effect, the {@link FillWindow} associated with the {@link FillResponse} will be
+ * automatically {@link FillWindow#destroy() destroyed}.
+ */
+ public void autofill(@NonNull List<Pair<AutofillId, AutofillValue>> values) {
+ Preconditions.checkNotNull(values);
+
+ if (DEBUG) {
+ Log.d(TAG, "autofill() with " + values.size() + " values");
+ }
+
+ try {
+ mProxy.autofill(values);
+ final FillWindow fillWindow = mProxy.getFillWindow();
+ if (fillWindow != null) {
+ fillWindow.destroy();
+ }
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+}
diff --git a/core/java/android/service/intelligence/FillRequest.java b/core/java/android/service/intelligence/FillRequest.java
new file mode 100644
index 0000000..95e9224
--- /dev/null
+++ b/core/java/android/service/intelligence/FillRequest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.intelligence;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.service.intelligence.IntelligenceService.AutofillProxy;
+import android.view.autofill.AutofillId;
+
+/**
+ * Represents a request to augment-fill an activity.
+ * @hide
+ */
+@SystemApi
+public final class FillRequest {
+
+ final AutofillProxy mProxy;
+
+ /** @hide */
+ FillRequest(@NonNull AutofillProxy proxy) {
+ mProxy = proxy;
+ }
+
+ /**
+ * Gets the session associated with this request.
+ */
+ @NonNull
+ public InteractionSessionId getSessionId() {
+ return mProxy.sessionId;
+ }
+
+ /**
+ * Gets the id of the field that triggered the request.
+ */
+ @NonNull
+ public AutofillId getFocusedId() {
+ return mProxy.focusedId;
+ }
+
+ /**
+ * Gets the Smart Suggestions object used to embed the autofill UI.
+ *
+ * @return object used to embed the autofill UI, or {@code null} if not supported.
+ */
+ @Nullable
+ public PresentationParams getPresentationParams() {
+ return mProxy.getSmartSuggestionParams();
+ }
+
+ @Override
+ public String toString() {
+ return "FillRequest[id=" + mProxy.focusedId + "]";
+ }
+}
diff --git a/core/java/android/service/intelligence/FillResponse.java b/core/java/android/service/intelligence/FillResponse.java
new file mode 100644
index 0000000..860c027
--- /dev/null
+++ b/core/java/android/service/intelligence/FillResponse.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.intelligence;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.autofill.AutofillId;
+
+import java.util.List;
+
+/**
+ * Response to a {@link FillRequest}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class FillResponse implements Parcelable {
+
+ private final FillWindow mFillWindow;
+
+ private FillResponse(@NonNull Builder builder) {
+ mFillWindow = builder.mFillWindow;
+ }
+
+ /** @hide */
+ @Nullable
+ FillWindow getFillWindow() {
+ return mFillWindow;
+ }
+
+ /**
+ * Builder for {@link FillResponse} objects.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static class Builder {
+
+ private FillWindow mFillWindow;
+
+ /**
+ * Sets the {@link FillWindow} used to display the Autofill UI.
+ *
+ * <p>Must be called when the service is handling the request so the Android System can
+ * properly synchronize the UI.
+ *
+ * @return this builder
+ */
+ public Builder setFillWindow(@NonNull FillWindow fillWindow) {
+ // TODO(b/111330312): implement / check not null / unit test
+ // TODO(b/111330312): throw exception if FillWindow not updated yet
+ mFillWindow = fillWindow;
+ return this;
+ }
+
+ /**
+ * Tells the Android System that the given {@code ids} should not trigger further
+ * {@link FillRequest requests} when focused.
+ *
+ * @param ids ids of the fields that should be ignored
+ *
+ * @return this builder
+ */
+ public Builder setIgnoredIds(@NonNull List<AutofillId> ids) {
+ // TODO(b/111330312): implement / check not null / unit test
+ return this;
+ }
+
+ /**
+ * Builds a new {@link FillResponse} instance.
+ *
+ * @throws IllegalStateException if any of the following conditions occur:
+ * <ol>
+ * <li>{@link #build()} was already called.
+ * <li>No call was made to {@link #setFillWindow(FillWindow)} or
+ * {@ling #setIgnoredIds(List<AutofillId>)}.
+ * </ol>
+ *
+ * @return A built response.
+ */
+ public FillResponse build() {
+ // TODO(b/111330312): check conditions / add unit test
+ return new FillResponse(this);
+ }
+
+ // TODO(b/111330312): add methods to disable app / activity, either here or on manager
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ // TODO(b/111330312): implement
+ }
+
+ public static final Parcelable.Creator<FillResponse> CREATOR =
+ new Parcelable.Creator<FillResponse>() {
+
+ @Override
+ public FillResponse createFromParcel(Parcel parcel) {
+ // TODO(b/111330312): implement
+ return null;
+ }
+
+ @Override
+ public FillResponse[] newArray(int size) {
+ return new FillResponse[size];
+ }
+ };
+}
diff --git a/core/java/android/service/intelligence/FillWindow.java b/core/java/android/service/intelligence/FillWindow.java
new file mode 100644
index 0000000..4ea07bf
--- /dev/null
+++ b/core/java/android/service/intelligence/FillWindow.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.intelligence;
+
+import static android.service.intelligence.IntelligenceService.DEBUG;
+
+import android.annotation.LongDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.app.Dialog;
+import android.graphics.Rect;
+import android.service.intelligence.PresentationParams.Area;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.Preconditions;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Handle to a window used to display the augmented autofill UI.
+ *
+ * <p>The steps to create an augmented autofill UI are:
+ *
+ * <ol>
+ * <li>Gets the {@link PresentationParams} from the {@link FillRequest}.
+ * <li>Gets the {@link Area} to display the UI (for example, through
+ * {@link PresentationParams#getSuggestionArea()}.
+ * <li>Creates a {@link View} that must fit in the {@link Area#getBounds() area boundaries}.
+ * <li>Set the proper listeners to the view (for example, a click listener that
+ * triggers {@link FillController#autofill(java.util.List)}
+ * <li>Call {@link #update(Area, View, long)} with these arguments.
+ * <li>Create a {@link FillResponse} with the {@link FillWindow}.
+ * <li>Pass such {@link FillResponse} to {@link FillCallback#onSuccess(FillResponse)}.
+ * </ol>
+ *
+ * @hide
+ */
+@SystemApi
+public final class FillWindow {
+ private static final String TAG = "FillWindow";
+
+ /** Indicates the data being shown is a physical address */
+ public static final long FLAG_METADATA_ADDRESS = 0x1;
+
+ // TODO(b/111330312): add moar flags
+
+ /** @hide */
+ @LongDef(prefix = { "FLAG" }, value = {
+ FLAG_METADATA_ADDRESS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Flags{}
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private Dialog mDialog;
+
+ @GuardedBy("mLock")
+ private boolean mDestroyed;
+
+ /**
+ * Updates the content of the window.
+ *
+ * @param rootView new root view
+ * @param area coordinates to render the view.
+ * @param flags optional flags such as metadata of what will be rendered in the window. The
+ * Smart Suggestion host might decide whether or not to render the UI based on them.
+ *
+ * @return boolean whether the window was updated or not.
+ *
+ * @throws IllegalArgumentException if the area is not compatible with this window
+ */
+ public boolean update(@NonNull Area area, @NonNull View rootView, @Flags long flags) {
+ if (DEBUG) {
+ Log.d(TAG, "Updating " + area + " + with " + rootView);
+ }
+ // TODO(b/111330312): add test case for null
+ Preconditions.checkNotNull(area);
+ Preconditions.checkNotNull(rootView);
+ // TODO(b/111330312): must check the area is a valid object returned by
+ // SmartSuggestionParams, throw IAE if not
+
+ // TODO(b/111330312): must some how pass metadata to the SmartSuggestiongs provider
+
+
+ // TODO(b/111330312): use a SurfaceControl approach; for now, we're manually creating
+ // the window underneath the existing view.
+
+ final PresentationParams smartSuggestion = area.proxy.getSmartSuggestionParams();
+ if (smartSuggestion == null) {
+ Log.w(TAG, "No SmartSuggestionParams");
+ return false;
+ }
+
+ final Rect rect = area.getBounds();
+ if (rect == null) {
+ Log.wtf(TAG, "No Rect on SmartSuggestionParams");
+ return false;
+ }
+
+ synchronized (mLock) {
+ checkNotDestroyedLocked();
+
+ // TODO(b/111330312): once we have the SurfaceControl approach, we should update the
+ // window instead of destroying. In fact, it might be better to allocate a full window
+ // initially, which is transparent (and let touches get through) everywhere but in the
+ // rect boundaries.
+ destroy();
+
+ // TODO(b/111330312): make sure all touch events are handled, window is always closed,
+ // etc.
+
+ mDialog = new Dialog(rootView.getContext());
+ final Window window = mDialog.getWindow();
+ window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+
+ final int height = rect.bottom - rect.top;
+ final int width = rect.right - rect.left;
+ final WindowManager.LayoutParams windowParams = window.getAttributes();
+ windowParams.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
+ windowParams.y = rect.top - height;
+ windowParams.height = height;
+ windowParams.x = rect.left;
+ windowParams.width = width;
+
+ window.setAttributes(windowParams);
+ window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+
+ mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
+ final ViewGroup.LayoutParams diagParams = new ViewGroup.LayoutParams(width, height);
+ mDialog.setContentView(rootView, diagParams);
+
+ if (DEBUG) {
+ Log.d(TAG, "Created FillWindow: params= " + smartSuggestion + " view=" + rootView);
+ }
+
+ area.proxy.setFillWindow(this);
+ return true;
+ }
+ }
+
+ /** @hide */
+ void show() {
+ // TODO(b/111330312): check if updated first / throw exception
+ if (DEBUG) Log.d(TAG, "show()");
+
+ synchronized (mLock) {
+ checkNotDestroyedLocked();
+ if (mDialog == null) {
+ throw new IllegalStateException("update() not called yet, or already destroyed()");
+ }
+
+ mDialog.show();
+ }
+ }
+
+ /**
+ * Destroys the window.
+ *
+ * <p>Once destroyed, this window cannot be used anymore
+ */
+ public void destroy() {
+ if (DEBUG) Log.d(TAG, "destroy(): mDestroyed = " + mDestroyed);
+
+ synchronized (this) {
+ if (mDestroyed) return;
+
+ if (mDialog != null) {
+ mDialog.dismiss();
+ mDialog = null;
+ }
+ }
+ }
+
+ private void checkNotDestroyedLocked() {
+ if (mDestroyed) {
+ throw new IllegalStateException("already destroyed()");
+ }
+ }
+
+ /** @hide */
+ public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ synchronized (this) {
+ pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
+ if (mDialog != null) {
+ pw.print(prefix); pw.print("dialog: ");
+ pw.println(mDialog.isShowing() ? "shown" : "hidden");
+ pw.print(prefix); pw.print("window: ");
+ pw.println(mDialog.getWindow().getAttributes());
+ }
+ }
+ }
+}
diff --git a/core/java/android/service/intelligence/IIntelligenceService.aidl b/core/java/android/service/intelligence/IIntelligenceService.aidl
index 709c3b7..e2260d7 100644
--- a/core/java/android/service/intelligence/IIntelligenceService.aidl
+++ b/core/java/android/service/intelligence/IIntelligenceService.aidl
@@ -16,10 +16,12 @@
package android.service.intelligence;
+import android.os.IBinder;
import android.service.intelligence.InteractionSessionId;
import android.service.intelligence.InteractionContext;
import android.service.intelligence.SnapshotData;
+import android.view.autofill.AutofillId;
import android.view.intelligence.ContentCaptureEvent;
import java.util.List;
@@ -40,4 +42,9 @@
void onActivitySnapshot(in InteractionSessionId sessionId,
in SnapshotData snapshotData);
+
+ void onAutofillRequest(in InteractionSessionId sessionId, in IBinder autofillManagerClient,
+ int autofilSessionId, in AutofillId focusedId);
+
+ void onDestroyAutofillWindowsRequest(in InteractionSessionId sessionId);
}
diff --git a/core/java/android/service/intelligence/IntelligenceService.java b/core/java/android/service/intelligence/IntelligenceService.java
index 27569b6..040e25e 100644
--- a/core/java/android/service/intelligence/IntelligenceService.java
+++ b/core/java/android/service/intelligence/IntelligenceService.java
@@ -22,13 +22,26 @@
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
+import android.graphics.Rect;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.service.intelligence.PresentationParams.SystemPopupPresentationParams;
+import android.util.ArrayMap;
import android.util.Log;
+import android.util.Pair;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.view.autofill.IAugmentedAutofillManagerClient;
import android.view.intelligence.ContentCaptureEvent;
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -44,6 +57,9 @@
private static final String TAG = "IntelligenceService";
+ // TODO(b/111330312): STOPSHIP use dynamic value, or change to false
+ static final boolean DEBUG = true;
+
/**
* The {@link Intent} that must be declared as handled by the service.
* To be supported, the service must also require the
@@ -55,6 +71,8 @@
private Handler mHandler;
+ private ArrayMap<InteractionSessionId, AutofillProxy> mAutofillProxies;
+
private final IIntelligenceService mInterface = new IIntelligenceService.Stub() {
@Override
@@ -87,6 +105,20 @@
obtainMessage(IntelligenceService::onActivitySnapshot,
IntelligenceService.this, sessionId, snapshotData));
}
+
+ @Override
+ public void onAutofillRequest(InteractionSessionId sessionId, IBinder client,
+ int autofilSessionId, AutofillId focusedId) {
+ mHandler.sendMessage(obtainMessage(IntelligenceService::handleOnAutofillRequest,
+ IntelligenceService.this, sessionId, client, autofilSessionId, focusedId));
+ }
+
+ @Override
+ public void onDestroyAutofillWindowsRequest(InteractionSessionId sessionId) {
+ mHandler.sendMessage(
+ obtainMessage(IntelligenceService::handleOnDestroyAutofillWindowsRequest,
+ IntelligenceService.this, sessionId));
+ }
};
@CallSuper
@@ -122,10 +154,93 @@
* @param sessionId the session's Id
* @param events the events
*/
- // TODO(b/111276913): rename to onContentCaptureEvents
+ // TODO(b/111276913): rename to onContentCaptureEvents or something like that; also, pass a
+ // Request object so it can be extended
public abstract void onContentCaptureEvent(@NonNull InteractionSessionId sessionId,
@NonNull List<ContentCaptureEvent> events);
+ private void handleOnAutofillRequest(@NonNull InteractionSessionId sessionId,
+ @NonNull IBinder client, int autofillSessionId, @NonNull AutofillId focusedId) {
+ if (mAutofillProxies == null) {
+ mAutofillProxies = new ArrayMap<>();
+ }
+ AutofillProxy proxy = mAutofillProxies.get(sessionId);
+ if (proxy == null) {
+ proxy = new AutofillProxy(sessionId, client, autofillSessionId, focusedId);
+ mAutofillProxies.put(sessionId, proxy);
+ } else {
+ // TODO(b/111330312): figure out if it's ok to reuse the proxy; add logging
+ if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId);
+ }
+ // TODO(b/111330312): set cancellation signal
+ final CancellationSignal cancellationSignal = null;
+ onFillRequest(sessionId, new FillRequest(proxy), cancellationSignal,
+ new FillController(proxy), new FillCallback());
+ }
+
+ /**
+ * Asks the service to handle an "augmented" autofill request.
+ *
+ * <p>This method is called when the "stantard" autofill service cannot handle a request, which
+ * typically occurs when:
+ * <ul>
+ * <li>Service does not recognize what should be autofilled.
+ * <li>Service does not have data to fill the request.
+ * <li>Service blacklisted that app (or activity) for autofill.
+ * <li>App disabled itself for autofill.
+ * </ul>
+ *
+ * <p>Differently from the standard autofill workflow, on augmented autofill the service is
+ * responsible to generate the autofill UI and request the Android system to autofill the
+ * activity when the user taps an action in that UI (through the
+ * {@link FillController#autofill(List)} method).
+ *
+ * <p>The service <b>MUST</b> call {@link
+ * FillCallback#onSuccess(android.service.intelligence.FillResponse)} as soon as possible,
+ * passing {@code null} when it cannot fulfill the request.
+ *
+ * @param sessionId the session's id
+ * @param request the request to handle.
+ * @param cancellationSignal signal for observing cancellation requests. The system will use
+ * this to notify you that the fill result is no longer needed and you should stop
+ * handling this fill request in order to save resources.
+ * @param controller object used to interact with the autofill system.
+ * @param callback object used to notify the result of the request. Service <b>must</b> call
+ * {@link FillCallback#onSuccess(android.service.intelligence.FillResponse)}.
+ */
+ public void onFillRequest(@NonNull InteractionSessionId sessionId, @NonNull FillRequest request,
+ @NonNull CancellationSignal cancellationSignal, @NonNull FillController controller,
+ @NonNull FillCallback callback) {
+ }
+
+ private void handleOnDestroyAutofillWindowsRequest(@NonNull InteractionSessionId sessionId) {
+ AutofillProxy proxy = null;
+ if (mAutofillProxies != null) {
+ proxy = mAutofillProxies.get(sessionId);
+ }
+ if (proxy == null) {
+ // TODO(b/111330312): this might be fine, in which case we should logv it
+ Log.w(TAG, "No proxy for session " + sessionId);
+ return;
+ }
+ proxy.destroy();
+ mAutofillProxies.remove(sessionId);
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mAutofillProxies != null) {
+ final int size = mAutofillProxies.size();
+ pw.print("Number proxies: "); pw.println(size);
+ for (int i = 0; i < size; i++) {
+ final InteractionSessionId sessionId = mAutofillProxies.keyAt(i);
+ final AutofillProxy proxy = mAutofillProxies.valueAt(i);
+ pw.print(i); pw.print(") SessionId="); pw.print(sessionId); pw.println(":");
+ proxy.dump(" ", pw);
+ }
+ }
+ }
+
/**
* Notifies the service of {@link IntelligenceSnapshotData snapshot data} associated with a
* session.
@@ -142,4 +257,99 @@
* @param sessionId the id of the session to destroy
*/
public void onDestroyInteractionSession(@NonNull InteractionSessionId sessionId) {}
+
+ /** @hide */
+ static final class AutofillProxy {
+ private final Object mLock = new Object();
+ private final IAugmentedAutofillManagerClient mClient;
+ private final int mAutofillSessionId;
+ public final InteractionSessionId sessionId;
+ public final AutofillId focusedId;
+
+ @GuardedBy("mLock")
+ private SystemPopupPresentationParams mSmartSuggestion;
+
+ @GuardedBy("mLock")
+ private FillWindow mFillWindow;
+
+ private AutofillProxy(@NonNull InteractionSessionId sessionId, @NonNull IBinder client,
+ int autofillSessionId, @NonNull AutofillId focusedId) {
+ this.sessionId = sessionId;
+ mClient = IAugmentedAutofillManagerClient.Stub.asInterface(client);
+ mAutofillSessionId = autofillSessionId;
+ this.focusedId = focusedId;
+ // TODO(b/111330312): linkToDeath
+ }
+
+ @NonNull
+ public SystemPopupPresentationParams getSmartSuggestionParams() {
+ synchronized (mLock) {
+ if (mSmartSuggestion != null) {
+ return mSmartSuggestion;
+ }
+ Rect rect;
+ try {
+ rect = mClient.getViewCoordinates(focusedId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not get coordinates for " + focusedId);
+ return null;
+ }
+ if (rect == null) {
+ if (DEBUG) Log.d(TAG, "getViewCoordinates(" + focusedId + ") returned null");
+ return null;
+ }
+ mSmartSuggestion = new SystemPopupPresentationParams(this, rect);
+ return mSmartSuggestion;
+ }
+ }
+
+ public void autofill(@NonNull List<Pair<AutofillId, AutofillValue>> pairs)
+ throws RemoteException {
+ final int size = pairs.size();
+ final List<AutofillId> ids = new ArrayList<>(size);
+ final List<AutofillValue> values = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ final Pair<AutofillId, AutofillValue> pair = pairs.get(i);
+ ids.add(pair.first);
+ values.add(pair.second);
+ }
+ mClient.autofill(mAutofillSessionId, ids, values);
+ }
+
+ public void setFillWindow(@NonNull FillWindow fillWindow) {
+ synchronized (mLock) {
+ mFillWindow = fillWindow;
+ }
+ }
+
+ public FillWindow getFillWindow() {
+ synchronized (mLock) {
+ return mFillWindow;
+ }
+ }
+
+ public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ pw.print(prefix); pw.print("afSessionId: "); pw.println(mAutofillSessionId);
+ pw.print(prefix); pw.print("focusedId: "); pw.println(focusedId);
+ pw.print(prefix); pw.print("client: "); pw.println(mClient);
+ final String prefix2 = prefix + " ";
+ if (mFillWindow != null) {
+ pw.print(prefix); pw.println("window:");
+ mFillWindow.dump(prefix2, pw);
+ }
+ if (mSmartSuggestion != null) {
+ pw.print(prefix); pw.println("smartSuggestion:");
+ mSmartSuggestion.dump(prefix2, pw);
+ }
+ }
+
+ private void destroy() {
+ synchronized (mLock) {
+ if (mFillWindow != null) {
+ if (DEBUG) Log.d(TAG, "destroying window");
+ mFillWindow.destroy();
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/service/intelligence/PresentationParams.java b/core/java/android/service/intelligence/PresentationParams.java
new file mode 100644
index 0000000..b92f8f1
--- /dev/null
+++ b/core/java/android/service/intelligence/PresentationParams.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.intelligence;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.graphics.Rect;
+import android.service.intelligence.IntelligenceService.AutofillProxy;
+import android.util.DebugUtils;
+import android.view.View;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Abstraction of a "Smart Suggestion" component responsible to embed the autofill UI provided by
+ * the intelligence service.
+ *
+ * <p>The Smart Suggestion can embed the autofill UI in 3 distinct places:
+ *
+ * <ul>
+ * <li>A small area associated with suggestions (like a small strip in the top of the IME),
+ * returned by {@link #getSuggestionArea()}
+ * <li>The full area (like the full IME window), returned by {@link #getFullArea()}
+ * <li>A subset of the aforementioned areas, returned by {@link Area#getSubArea(Rect)}
+ * </ul>
+ *
+ * <p>The Smart Suggestion is represented by a {@link Area} object that contains the
+ * dimensions the smart suggestion window, so the service can use it to calculate the size of the
+ * view that will be passed to {@link FillWindow#update(Area, View, long)}.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class PresentationParams {
+
+ /**
+ * Flag indicating the Smart Suggestion is hosted in the top of its container.
+ */
+ public static final int FLAG_HINT_GRAVITY_TOP = 0x1;
+
+ /**
+ * Flag indicating the Smart Suggestion is hosted in the bottom of its container.
+ */
+ public static final int FLAG_HINT_GRAVITY_BOTTOM = 0x2;
+
+ /**
+ * Flag indicating the Smart Suggestion is hosted in the left of its container.
+ */
+ public static final int FLAG_HINT_GRAVITY_LEFT = 0x4;
+
+ /**
+ * Flag indicating the Smart Suggestion is hosted in the right of its container.
+ */
+ public static final int FLAG_HINT_GRAVITY_RIGHT = 0x8;
+
+ /**
+ * Flag indicating the Smart Suggestion is hosted by the IME.
+ */
+ public static final int FLAG_HOST_IME = 0x10;
+
+ /**
+ * Flag indicating the Smart Suggestion is hosted by the Android System as a floating popup
+ * window.
+ */
+ public static final int FLAG_HOST_SYSTEM = 0x20;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ FLAG_HINT_GRAVITY_TOP,
+ FLAG_HINT_GRAVITY_BOTTOM,
+ FLAG_HINT_GRAVITY_LEFT,
+ FLAG_HINT_GRAVITY_RIGHT,
+ FLAG_HOST_IME,
+ FLAG_HOST_SYSTEM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface Flags {}
+
+
+ // /** @hide */
+ PresentationParams() {}
+
+ /**
+ * Gets the area of the suggestion strip for the given {@code metadata}
+ *
+ * @return strip dimensions, or {@code null} if the Smart Suggestion provider does not support
+ * suggestions strip.
+ */
+ @Nullable
+ public Area getSuggestionArea() {
+ return null;
+ }
+
+ /**
+ * Gets the full area for the of the Smart Suggestion provider.
+ *
+ * @return full dimensions, or {@code null} if the Smart Suggestion provider does not support
+ * embeding the UI on its full area.
+ */
+ @Nullable
+ public Area getFullArea() {
+ return null;
+ }
+
+ /**
+ * Gets flags associated with the Smart Suggestion.
+ *
+ * @return any combination of {@link #FLAG_HINT_GRAVITY_TOP},
+ * {@link #FLAG_HINT_GRAVITY_BOTTOM}, {@link #FLAG_HINT_GRAVITY_LEFT},
+ * {@link #FLAG_HINT_GRAVITY_RIGHT}, {@link #FLAG_HOST_IME}, or
+ * {@link #FLAG_HOST_SYSTEM},
+ */
+ public @Flags int getFlags() {
+ return 0;
+ }
+
+ /** @hide */
+ void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ final int flags = getFlags();
+ if (flags > 0) {
+ pw.print(prefix); pw.print("flags: "); pw.println(flagsToString(flags));
+ }
+ }
+
+ private static String flagsToString(int flags) {
+ return DebugUtils.flagsToString(PresentationParams.class, "FLAG_", flags);
+ }
+
+ /**
+ * Area associated with a {@link PresentationParams Smart Suggestions} provider.
+ *
+ * @hide
+ * */
+ @SystemApi
+ public abstract static class Area {
+
+ /** @hide */
+ public final AutofillProxy proxy;
+
+ private final Rect mBounds;
+
+ private Area(@NonNull AutofillProxy proxy, @NonNull Rect bounds) {
+ this.proxy = proxy;
+ mBounds = bounds;
+ }
+
+ /**
+ * Gets the area boundaries.
+ */
+ @NonNull
+ public Rect getBounds() {
+ return mBounds;
+ }
+
+ /**
+ * Gets a subarea limited by given boundaries.
+ *
+ * @param bounds boundaries relative to this Area.
+ *
+ * @throw {@link IllegalArgumentException} if the {@code bounds} is not fully-contained
+ * inside this full Area.
+ *
+ * @return new subarea, or {@code null} if the Smart Suggestion host does not support such
+ * subaarea.
+ */
+ @Nullable
+ public Area getSubArea(@NonNull Rect bounds) {
+ // TODO(b/111330312): implement / check boundaries / throw IAE / add unit test
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return mBounds.toString();
+ }
+ }
+
+ /**
+ * System-provided poup window anchored to a view.
+ *
+ * <p>Used just for debugging purposes.
+ *
+ * @hide
+ */
+ public static final class SystemPopupPresentationParams extends PresentationParams {
+ private final Area mSuggestionArea;
+
+ public SystemPopupPresentationParams(@NonNull AutofillProxy proxy, @NonNull Rect rect) {
+ mSuggestionArea = new Area(proxy, rect) {};
+ }
+
+ @Override
+ public Area getSuggestionArea() {
+ return mSuggestionArea;
+ }
+
+ @Override
+ public int getFlags() {
+ return FLAG_HOST_SYSTEM | FLAG_HINT_GRAVITY_BOTTOM;
+ }
+
+ @Override
+ void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+ super.dump(prefix, pw);
+ pw.print(prefix); pw.print("area: "); pw.println(mSuggestionArea);
+ }
+ }
+}
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index d8bd002..0988510 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -47,4 +47,6 @@
void onNotificationEnqueuedWithChannel(in IStatusBarNotificationHolder notificationHolder, in NotificationChannel channel);
void onNotificationSnoozedUntilContext(in IStatusBarNotificationHolder notificationHolder, String snoozeCriterionId);
void onNotificationsSeen(in List<String> keys);
+ void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded);
+ void onNotificationDirectReply(String key);
}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index c1a3c2b..90f4792 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -160,6 +160,21 @@
}
/**
+ * Implement this to know when a notification is expanded / collapsed.
+ * @param key the notification key
+ * @param isUserAction whether the expanded change is caused by user action.
+ * @param isExpanded whether the notification is expanded.
+ */
+ public void onNotificationExpansionChanged(
+ String key, boolean isUserAction, boolean isExpanded) {}
+
+ /**
+ * Implement this to know when a direct reply is sent from a notification.
+ * @param key the notification key
+ */
+ public void onNotificationDirectReply(String key) {}
+
+ /**
* Updates a notification. N.B. this won’t cause
* an existing notification to alert, but might allow a future update to
* this notification to alert.
@@ -255,12 +270,33 @@
mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATIONS_SEEN,
args).sendToTarget();
}
+
+ @Override
+ public void onNotificationExpansionChanged(String key, boolean isUserAction,
+ boolean isExpanded) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = key;
+ args.argi1 = isUserAction ? 1 : 0;
+ args.argi2 = isExpanded ? 1 : 0;
+ mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_EXPANSION_CHANGED, args)
+ .sendToTarget();
+ }
+
+ @Override
+ public void onNotificationDirectReply(String key) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = key;
+ mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT, args)
+ .sendToTarget();
+ }
}
private final class MyHandler extends Handler {
public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1;
public static final int MSG_ON_NOTIFICATION_SNOOZED = 2;
public static final int MSG_ON_NOTIFICATIONS_SEEN = 3;
+ public static final int MSG_ON_NOTIFICATION_EXPANSION_CHANGED = 4;
+ public static final int MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT = 5;
public MyHandler(Looper looper) {
super(looper, null, false);
@@ -305,6 +341,22 @@
onNotificationsSeen(keys);
break;
}
+ case MSG_ON_NOTIFICATION_EXPANSION_CHANGED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ String key = (String) args.arg1;
+ boolean isUserAction = args.argi1 == 1;
+ boolean isExpanded = args.argi2 == 1;
+ args.recycle();
+ onNotificationExpansionChanged(key, isUserAction, isExpanded);
+ break;
+ }
+ case MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ String key = (String) args.arg1;
+ args.recycle();
+ onNotificationDirectReply(key);
+ break;
+ }
}
}
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 64eae0c..a4db451 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1366,6 +1366,17 @@
}
@Override
+ public void onNotificationExpansionChanged(
+ String key, boolean isUserAction, boolean isExpanded) {
+ // no-op in the listener
+ }
+
+ @Override
+ public void onNotificationDirectReply(String key) {
+ // no-op in the listener
+ }
+
+ @Override
public void onNotificationChannelModification(String pkgName, UserHandle user,
NotificationChannel channel,
@ChannelOrGroupModificationTypes int modificationType) {
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 6f51bec..f6bb762 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -129,7 +129,7 @@
Bundle extras;
boolean sync;
}
-
+
/**
* The actual implementation of a wallpaper. A wallpaper service may
* have multiple instances running (for example as a real wallpaper
@@ -144,7 +144,7 @@
HandlerCaller mCaller;
IWallpaperConnection mConnection;
IBinder mWindowToken;
-
+
boolean mInitializing = true;
boolean mVisible;
boolean mReportedVisible;
@@ -208,7 +208,6 @@
private final Supplier<Long> mClockFunction;
private final Handler mHandler;
- DisplayManager mDisplayManager;
Display mDisplay;
private int mDisplayState;
@@ -419,7 +418,7 @@
public int getDesiredMinimumHeight() {
return mIWallpaperEngine.mReqHeight;
}
-
+
/**
* Return whether the wallpaper is currently visible to the user,
* this is the last value supplied to
@@ -1015,14 +1014,6 @@
return;
}
- mDisplayManager = getSystemService(DisplayManager.class);
- mDisplay = mDisplayManager.getDisplay(wrapper.mDisplayId);
- if (mDisplay == null) {
- // TODO(b/115486823) Ignore this engine.
- Log.e(TAG, "Attaching to a non-existent display: " + wrapper.mDisplayId);
- return;
- }
-
mIWallpaperEngine = wrapper;
mCaller = wrapper.mCaller;
mConnection = wrapper.mConnection;
@@ -1034,13 +1025,16 @@
mWindow.setSession(mSession);
mLayout.packageName = getPackageName();
- mDisplayManager.registerDisplayListener(mDisplayListener, mCaller.getHandler());
+ mIWallpaperEngine.mDisplayManager.registerDisplayListener(mDisplayListener,
+ mCaller.getHandler());
+ mDisplay = mIWallpaperEngine.mDisplay;
mDisplayState = mDisplay.getState();
if (DEBUG) Log.v(TAG, "onCreate(): " + this);
onCreate(mSurfaceHolder);
-
+
mInitializing = false;
+
mReportedVisible = false;
updateSurface(false, false, false);
}
@@ -1202,8 +1196,8 @@
mDestroyed = true;
- if (mDisplayManager != null) {
- mDisplayManager.unregisterDisplayListener(mDisplayListener);
+ if (mIWallpaperEngine.mDisplayManager != null) {
+ mIWallpaperEngine.mDisplayManager.unregisterDisplayListener(mDisplayListener);
}
if (mVisible) {
@@ -1272,7 +1266,9 @@
int mReqWidth;
int mReqHeight;
final Rect mDisplayPadding = new Rect();
- int mDisplayId;
+ final int mDisplayId;
+ final DisplayManager mDisplayManager;
+ final Display mDisplay;
Engine mEngine;
@@ -1289,7 +1285,15 @@
mReqHeight = reqHeight;
mDisplayPadding.set(padding);
mDisplayId = displayId;
-
+
+ // Create a display context before onCreateEngine.
+ mDisplayManager = getSystemService(DisplayManager.class);
+ mDisplay = mDisplayManager.getDisplay(mDisplayId);
+
+ if (mDisplay == null) {
+ // Ignore this engine.
+ throw new IllegalArgumentException("Cannot find display with id" + mDisplayId);
+ }
Message msg = mCaller.obtainMessage(DO_ATTACH);
mCaller.sendMessage(msg);
}
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index ec63cd9..7815864 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -1009,7 +1009,7 @@
Log.e(TAG, "null synthesis text");
return false;
}
- if (mText.length() >= TextToSpeech.getMaxSpeechInputLength()) {
+ if (mText.length() > TextToSpeech.getMaxSpeechInputLength()) {
Log.w(TAG, "Text too long: " + mText.length() + " chars");
return false;
}
@@ -1609,7 +1609,7 @@
synchronized (mCallerToCallback) {
mCallerToCallback.remove(caller);
}
- //mSynthHandler.stopForApp(caller);
+ mSynthHandler.stopForApp(caller);
}
@Override
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c836c9e..308a000 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -271,7 +271,7 @@
/**
* Called by the status bar to notify Views of changes to System UI visiblity.
*/
- oneway void statusBarVisibilityChanged(int visibility);
+ oneway void statusBarVisibilityChanged(int displayId, int visibility);
/**
* Called by System UI to notify of changes to the visibility of Recents.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 5f1336f..cb454ff 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3993,7 +3993,7 @@
*
* @see #getParent()
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
protected ViewParent mParent;
/**
@@ -4199,7 +4199,7 @@
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "layout")
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
protected int mLeft;
/**
* The distance in pixels from the left edge of this view's parent
@@ -4207,7 +4207,7 @@
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "layout")
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
protected int mRight;
/**
* The distance in pixels from the top edge of this view's parent
@@ -4215,7 +4215,7 @@
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "layout")
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
protected int mTop;
/**
* The distance in pixels from the top edge of this view's parent
@@ -4223,7 +4223,7 @@
* {@hide}
*/
@ViewDebug.ExportedProperty(category = "layout")
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
protected int mBottom;
/**
@@ -4714,7 +4714,7 @@
* of this view to at least this amount.
*/
@ViewDebug.ExportedProperty(category = "measurement")
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mMinHeight;
/**
@@ -4722,7 +4722,7 @@
* of this view to at least this amount.
*/
@ViewDebug.ExportedProperty(category = "measurement")
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mMinWidth;
/**
@@ -8152,6 +8152,9 @@
* the user, and the activity rendering the view is enabled for Content Capture) is laid out and
* is visible.
*
+ * <p>The populated structure is then passed to the service through
+ * {@link IntelligenceManager#notifyViewAppeared(ViewStructure)}.
+ *
* <p><b>Note: </b>the following methods of the {@code structure} will be ignored:
* <ul>
* <li>{@link ViewStructure#setChildCount(int)}
@@ -8165,16 +8168,9 @@
* <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}
* <li>{@link ViewStructure#setDataIsSensitive(boolean)}
* </ul>
- *
- * @return whether the IntelligenceService should be notified that the view was added (through
- * the {@link IntelligenceManager#notifyViewAppeared(ViewStructure)} method) to the view
- * hierarchy. Most views should return {@code true} here, but views that contains virtual
- * hierarchy might opt to return {@code false} and notify the manager independently, as the
- * virtual views are rendered.
*/
- public boolean onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) {
+ public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) {
onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags);
- return true;
}
/** @hide */
@@ -8986,10 +8982,8 @@
if (type == CONTENT_CAPTURE_NOTIFICATION_TYPE_APPEARED) {
final ViewStructure structure = im.newViewStructure(this);
- boolean notifyMgr = onProvideContentCaptureStructure(structure, /* flags= */ 0);
- if (notifyMgr) {
- im.notifyViewAppeared(structure);
- }
+ onProvideContentCaptureStructure(structure, /* flags= */ 0);
+ im.notifyViewAppeared(structure);
mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED;
} else {
if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_ADDED) == 0) {
@@ -23157,26 +23151,24 @@
* Modifies the input matrix such that it maps view-local coordinates to
* on-screen coordinates.
*
- * @param m input matrix to modify
- * @hide
+ * @param matrix input matrix to modify
*/
- @UnsupportedAppUsage
- public void transformMatrixToGlobal(Matrix m) {
+ public void transformMatrixToGlobal(Matrix matrix) {
final ViewParent parent = mParent;
if (parent instanceof View) {
final View vp = (View) parent;
- vp.transformMatrixToGlobal(m);
- m.preTranslate(-vp.mScrollX, -vp.mScrollY);
+ vp.transformMatrixToGlobal(matrix);
+ matrix.preTranslate(-vp.mScrollX, -vp.mScrollY);
} else if (parent instanceof ViewRootImpl) {
final ViewRootImpl vr = (ViewRootImpl) parent;
- vr.transformMatrixToGlobal(m);
- m.preTranslate(0, -vr.mCurScrollY);
+ vr.transformMatrixToGlobal(matrix);
+ matrix.preTranslate(0, -vr.mCurScrollY);
}
- m.preTranslate(mLeft, mTop);
+ matrix.preTranslate(mLeft, mTop);
if (!hasIdentityMatrix()) {
- m.preConcat(getMatrix());
+ matrix.preConcat(getMatrix());
}
}
@@ -23184,26 +23176,24 @@
* Modifies the input matrix such that it maps on-screen coordinates to
* view-local coordinates.
*
- * @param m input matrix to modify
- * @hide
+ * @param matrix input matrix to modify
*/
- @UnsupportedAppUsage
- public void transformMatrixToLocal(Matrix m) {
+ public void transformMatrixToLocal(Matrix matrix) {
final ViewParent parent = mParent;
if (parent instanceof View) {
final View vp = (View) parent;
- vp.transformMatrixToLocal(m);
- m.postTranslate(vp.mScrollX, vp.mScrollY);
+ vp.transformMatrixToLocal(matrix);
+ matrix.postTranslate(vp.mScrollX, vp.mScrollY);
} else if (parent instanceof ViewRootImpl) {
final ViewRootImpl vr = (ViewRootImpl) parent;
- vr.transformMatrixToLocal(m);
- m.postTranslate(0, vr.mCurScrollY);
+ vr.transformMatrixToLocal(matrix);
+ matrix.postTranslate(0, vr.mCurScrollY);
}
- m.postTranslate(-mLeft, -mTop);
+ matrix.postTranslate(-mLeft, -mTop);
if (!hasIdentityMatrix()) {
- m.postConcat(getInverseMatrix());
+ matrix.postConcat(getInverseMatrix());
}
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index d4c7069..9227249 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -202,6 +202,14 @@
public static final String EXTRA_RESTORE_SESSION_TOKEN =
"android.view.autofill.extra.RESTORE_SESSION_TOKEN";
+ /**
+ * Internal extra used to pass a binder to the {@link IAugmentedAutofillManagerClient}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_AUGMENTED_AUTOFILL_CLIENT =
+ "android.view.autofill.extra.AUGMENTED_AUTOFILL_CLIENT";
+
private static final String SESSION_ID_TAG = "android:sessionId";
private static final String STATE_TAG = "android:state";
private static final String LAST_AUTOFILLED_DATA_TAG = "android:lastAutoFilledData";
@@ -370,6 +378,9 @@
private Cleaner mServiceClientCleaner;
@GuardedBy("mLock")
+ private IAugmentedAutofillManagerClient mAugmentedAutofillServiceClient;
+
+ @GuardedBy("mLock")
private AutofillCallback mCallback;
private final Context mContext;
@@ -1664,6 +1675,8 @@
final IAutoFillManager service = mService;
final IAutoFillManagerClient serviceClient = mServiceClient;
mServiceClientCleaner = Cleaner.create(this, () -> {
+ // TODO(b/111330312): call service to also remove reference to
+ // mAugmentedAutofillServiceClient
try {
service.removeClient(serviceClient, userId);
} catch (RemoteException e) {
@@ -1808,6 +1821,7 @@
if ((flags & SET_STATE_FLAG_RESET_CLIENT) != 0) {
// Reset connection to system
mServiceClient = null;
+ mAugmentedAutofillServiceClient = null;
if (mServiceClientCleaner != null) {
mServiceClientCleaner.clean();
mServiceClientCleaner = null;
@@ -2054,6 +2068,29 @@
}
}
+ /**
+ * Gets a {@link AugmentedAutofillManagerClient} for this {@link AutofillManagerClient}.
+ *
+ * <p>These are 2 distinct objects because we need to restrict what the Augmented Autofill
+ * service can do (which is defined by {@code IAugmentedAutofillManagerClient.aidl}).
+ */
+ private void getAugmentedAutofillClient(@NonNull IResultReceiver result) {
+ synchronized (mLock) {
+ if (mAugmentedAutofillServiceClient == null) {
+ mAugmentedAutofillServiceClient = new AugmentedAutofillManagerClient(this);
+ }
+ final Bundle resultData = new Bundle();
+ resultData.putBinder(EXTRA_AUGMENTED_AUTOFILL_CLIENT,
+ mAugmentedAutofillServiceClient.asBinder());
+
+ try {
+ result.send(0, resultData);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not send AugmentedAutofillClient back: " + e);
+ }
+ }
+ }
+
/** @hide */
public void requestHideFillUi() {
requestHideFillUi(mIdShownFillUi, true);
@@ -2801,7 +2838,7 @@
private static final class AutofillManagerClient extends IAutoFillManagerClient.Stub {
private final WeakReference<AutofillManager> mAfm;
- AutofillManagerClient(AutofillManager autofillManager) {
+ private AutofillManagerClient(AutofillManager autofillManager) {
mAfm = new WeakReference<>(autofillManager);
}
@@ -2904,6 +2941,50 @@
afm.post(() -> afm.setSessionFinished(newState));
}
}
+
+ @Override
+ public void getAugmentedAutofillClient(IResultReceiver result) {
+ final AutofillManager afm = mAfm.get();
+ if (afm != null) {
+ afm.post(() -> afm.getAugmentedAutofillClient(result));
+ }
+ }
+ }
+
+ private static final class AugmentedAutofillManagerClient
+ extends IAugmentedAutofillManagerClient.Stub {
+ private final WeakReference<AutofillManager> mAfm;
+
+ private AugmentedAutofillManagerClient(AutofillManager autofillManager) {
+ mAfm = new WeakReference<>(autofillManager);
+ }
+
+ @Override
+ public Rect getViewCoordinates(@NonNull AutofillId id) {
+ // TODO(b/111330312): use handler / callback?
+ final AutofillManager afm = mAfm.get();
+ if (afm == null) return null;
+
+ final View view = afm.getClient().autofillClientFindViewByAutofillIdTraversal(id);
+ // TODO(b/111330312): optimize (for example, use temp rect from attach info) and
+ // fix (for example, take system status bar height into account) logic below
+ final int[] location = new int[2];
+ view.getLocationOnScreen(location);
+ final Rect rect = new Rect(location[0], location[1], location[0] + view.getWidth(),
+ location[1] + view.getHeight());
+ if (sVerbose) {
+ Log.v(TAG, "Coordinates for " + id + ": " + rect);
+ }
+ return rect;
+ }
+
+ @Override
+ public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
+ final AutofillManager afm = mAfm.get();
+ if (afm != null) {
+ afm.post(() -> afm.autofill(sessionId, ids, values));
+ }
+ }
}
/**
diff --git a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
new file mode 100644
index 0000000..67cd0bf
--- /dev/null
+++ b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import java.util.List;
+
+import android.graphics.Rect;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+
+/**
+ * Object running in the application process and responsible to provide the functionalities
+ * required by an Augmented Autofill service.
+ *
+ * @hide
+ */
+interface IAugmentedAutofillManagerClient {
+ Rect getViewCoordinates(in AutofillId id);
+ void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+}
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 0ff7a0b..63394b4 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -27,6 +27,8 @@
import android.view.autofill.IAutofillWindowPresenter;
import android.view.KeyEvent;
+import com.android.internal.os.IResultReceiver;
+
/**
* Object running in the application process and responsible for autofilling it.
*
@@ -93,8 +95,18 @@
/**
* Marks the state of the session as finished.
+ *
* @param newState STATE_FINISHED (because the autofill service returned a null
* FillResponse) or STATE_UNKNOWN (because the session was removed).
*/
void setSessionFinished(int newState);
+
+ /**
+ * Gets a reference to the binder object that can be used by the Augmented Autofill service.
+ *
+ * @param receiver, whose AutofillManager.EXTRA_AUGMENTED_AUTOFILL_CLIENT extra will contain
+ * the reference.
+ */
+ void getAugmentedAutofillClient(in IResultReceiver result);
+
}
diff --git a/core/java/android/view/intelligence/IntelligenceManager.java b/core/java/android/view/intelligence/IntelligenceManager.java
index dfa52d9..755c54c 100644
--- a/core/java/android/view/intelligence/IntelligenceManager.java
+++ b/core/java/android/view/intelligence/IntelligenceManager.java
@@ -391,7 +391,7 @@
}
/**
- * Called by apps to explicitly enabled or disable content capture.
+ * Called by apps to explicitly enable or disable content capture.
*
* <p><b>Note: </b> this call is not persisted accross reboots, so apps should typically call
* it on {@link android.app.Activity#onCreate(android.os.Bundle, android.os.PersistableBundle)}.
diff --git a/core/java/android/view/intelligence/ViewNode.java b/core/java/android/view/intelligence/ViewNode.java
index cc78e6b..ea57461 100644
--- a/core/java/android/view/intelligence/ViewNode.java
+++ b/core/java/android/view/intelligence/ViewNode.java
@@ -238,6 +238,8 @@
@Override
public void setText(CharSequence text, int selectionStart, int selectionEnd) {
+ // TODO(b/111276913): temporarily setting directly; should be done on superclass instead
+ mNode.mText = text;
// TODO(b/111276913): implement or move to superclass
}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 66da45d..74678df 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -57,7 +57,6 @@
import java.time.Instant;
import java.time.ZonedDateTime;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -515,10 +514,10 @@
final TextClassification.Builder builder = new TextClassification.Builder()
.setText(classifiedText);
- final int size = classifications.length;
+ final int typeCount = classifications.length;
AnnotatorModel.ClassificationResult highestScoringResult =
- size > 0 ? classifications[0] : null;
- for (int i = 0; i < size; i++) {
+ typeCount > 0 ? classifications[0] : null;
+ for (int i = 0; i < typeCount; i++) {
builder.setEntityType(classifications[i].getCollection(),
classifications[i].getScore());
if (classifications[i].getScore() > highestScoringResult.getScore()) {
@@ -526,9 +525,12 @@
}
}
+ // TODO: Make this configurable.
+ final float foreignTextThreshold = typeCount == 0 ? 0.5f : 0.7f;
boolean isPrimaryAction = true;
for (LabeledIntent labeledIntent : IntentFactory.create(
- mContext, classifiedText, referenceTime, highestScoringResult)) {
+ mContext, classifiedText, isForeignText(classifiedText, foreignTextThreshold),
+ referenceTime, highestScoringResult)) {
final RemoteAction action = labeledIntent.asRemoteAction(mContext);
if (action == null) {
continue;
@@ -550,6 +552,42 @@
return builder.setId(createId(text, start, end)).build();
}
+ private boolean isForeignText(String text, float threshold) {
+ // TODO: Revisit this algorithm.
+ try {
+ final LangIdModel.LanguageResult[] langResults = getLangIdImpl().detectLanguages(text);
+ if (langResults.length <= 0) {
+ return false;
+ }
+
+ LangIdModel.LanguageResult highestScoringResult = langResults[0];
+ for (int i = 1; i < langResults.length; i++) {
+ if (langResults[i].getScore() > highestScoringResult.getScore()) {
+ highestScoringResult = langResults[i];
+ }
+ }
+ if (highestScoringResult.getScore() < threshold) {
+ return false;
+ }
+ // TODO: Remove
+ Log.d(LOG_TAG, String.format("Language detected: <%s:%s>",
+ highestScoringResult.getLanguage(), highestScoringResult.getScore()));
+
+ final Locale detected = new Locale(highestScoringResult.getLanguage());
+ final LocaleList deviceLocales = LocaleList.getDefault();
+ final int size = deviceLocales.size();
+ for (int i = 0; i < size; i++) {
+ if (deviceLocales.get(i).getLanguage().equals(detected.getLanguage())) {
+ return false;
+ }
+ }
+ return true;
+ } catch (Throwable t) {
+ Log.e(LOG_TAG, "Error detecting foreign text. Ignored.", t);
+ }
+ return false;
+ }
+
@Override
public void dump(@NonNull IndentingPrintWriter printWriter) {
synchronized (mLock) {
@@ -690,53 +728,67 @@
public static List<LabeledIntent> create(
Context context,
String text,
+ boolean foreignText,
@Nullable Instant referenceTime,
@Nullable AnnotatorModel.ClassificationResult classification) {
final String type = classification != null
? classification.getCollection().trim().toLowerCase(Locale.ENGLISH)
- : null;
+ : "";
text = text.trim();
+ final List<LabeledIntent> actions;
switch (type) {
case TextClassifier.TYPE_EMAIL:
- return createForEmail(context, text);
+ actions = createForEmail(context, text);
+ break;
case TextClassifier.TYPE_PHONE:
- return createForPhone(context, text);
+ actions = createForPhone(context, text);
+ break;
case TextClassifier.TYPE_ADDRESS:
- return createForAddress(context, text);
+ actions = createForAddress(context, text);
+ break;
case TextClassifier.TYPE_URL:
- return createForUrl(context, text);
- case TextClassifier.TYPE_DATE:
+ actions = createForUrl(context, text);
+ break;
+ case TextClassifier.TYPE_DATE: // fall through
case TextClassifier.TYPE_DATE_TIME:
if (classification.getDatetimeResult() != null) {
final Instant parsedTime = Instant.ofEpochMilli(
classification.getDatetimeResult().getTimeMsUtc());
- return createForDatetime(context, type, referenceTime, parsedTime);
+ actions = createForDatetime(context, type, referenceTime, parsedTime);
} else {
- return new ArrayList<>();
+ actions = new ArrayList<>();
}
+ break;
case TextClassifier.TYPE_FLIGHT_NUMBER:
- return createForFlight(context, text);
+ actions = createForFlight(context, text);
+ break;
default:
- return new ArrayList<>();
+ actions = new ArrayList<>();
+ break;
}
+ if (foreignText) {
+ insertTranslateAction(actions, context, text);
+ }
+ return actions;
}
@NonNull
private static List<LabeledIntent> createForEmail(Context context, String text) {
- return Arrays.asList(
- new LabeledIntent(
- context.getString(com.android.internal.R.string.email),
- context.getString(com.android.internal.R.string.email_desc),
- new Intent(Intent.ACTION_SENDTO)
- .setData(Uri.parse(String.format("mailto:%s", text))),
- LabeledIntent.DEFAULT_REQUEST_CODE),
- new LabeledIntent(
- context.getString(com.android.internal.R.string.add_contact),
- context.getString(com.android.internal.R.string.add_contact_desc),
- new Intent(Intent.ACTION_INSERT_OR_EDIT)
- .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
- .putExtra(ContactsContract.Intents.Insert.EMAIL, text),
- text.hashCode()));
+ final List<LabeledIntent> actions = new ArrayList<>();
+ actions.add(new LabeledIntent(
+ context.getString(com.android.internal.R.string.email),
+ context.getString(com.android.internal.R.string.email_desc),
+ new Intent(Intent.ACTION_SENDTO)
+ .setData(Uri.parse(String.format("mailto:%s", text))),
+ LabeledIntent.DEFAULT_REQUEST_CODE));
+ actions.add(new LabeledIntent(
+ context.getString(com.android.internal.R.string.add_contact),
+ context.getString(com.android.internal.R.string.add_contact_desc),
+ new Intent(Intent.ACTION_INSERT_OR_EDIT)
+ .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
+ .putExtra(ContactsContract.Intents.Insert.EMAIL, text),
+ text.hashCode()));
+ return actions;
}
@NonNull
@@ -793,12 +845,14 @@
if (Uri.parse(text).getScheme() == null) {
text = "http://" + text;
}
- return Arrays.asList(new LabeledIntent(
+ final List<LabeledIntent> actions = new ArrayList<>();
+ actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.browse),
context.getString(com.android.internal.R.string.browse_desc),
new Intent(Intent.ACTION_VIEW, Uri.parse(text))
.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()),
LabeledIntent.DEFAULT_REQUEST_CODE));
+ return actions;
}
@NonNull
@@ -820,12 +874,14 @@
@NonNull
private static List<LabeledIntent> createForFlight(Context context, String text) {
- return Arrays.asList(new LabeledIntent(
+ final List<LabeledIntent> actions = new ArrayList<>();
+ actions.add(new LabeledIntent(
context.getString(com.android.internal.R.string.view_flight),
context.getString(com.android.internal.R.string.view_flight_desc),
new Intent(Intent.ACTION_WEB_SEARCH)
.putExtra(SearchManager.QUERY, text),
text.hashCode()));
+ return actions;
}
@NonNull
@@ -856,5 +912,17 @@
parsedTime.toEpochMilli() + DEFAULT_EVENT_DURATION),
parsedTime.hashCode());
}
+
+ private static void insertTranslateAction(
+ List<LabeledIntent> actions, Context context, String text) {
+ actions.add(new LabeledIntent(
+ context.getString(com.android.internal.R.string.translate),
+ context.getString(com.android.internal.R.string.translate_desc),
+ new Intent(Intent.ACTION_TRANSLATE)
+ // TODO: Probably better to introduce a "translate" scheme instead of
+ // using EXTRA_TEXT.
+ .putExtra(Intent.EXTRA_TEXT, text),
+ text.hashCode()));
+ }
}
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 1093719..4f1417e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2695,8 +2695,8 @@
}
@Override
- public boolean onProvideContentCaptureStructure(ViewStructure structure, int flags) {
- return mProvider.getViewDelegate().onProvideContentCaptureStructure(structure, flags);
+ public void onProvideContentCaptureStructure(ViewStructure structure, int flags) {
+ mProvider.getViewDelegate().onProvideContentCaptureStructure(structure, flags);
}
@Override
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index ceada07..95e7a986 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -341,10 +341,9 @@
return true; // true is the default value returned by View.isVisibleToUserForAutofill()
}
- default boolean onProvideContentCaptureStructure(
+ default void onProvideContentCaptureStructure(
@SuppressWarnings("unused") android.view.ViewStructure structure,
@SuppressWarnings("unused") int flags) {
- return false; // WebView provides virtual views and is responsible to notify manager
}
public AccessibilityNodeProvider getAccessibilityNodeProvider();
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 12cc54d..3cd0748 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -106,9 +106,9 @@
private boolean mHaveFrame = false;
@UnsupportedAppUsage
private boolean mAdjustViewBounds = false;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mMaxWidth = Integer.MAX_VALUE;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mMaxHeight = Integer.MAX_VALUE;
// these are applied to the drawable
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index f2e478d..15910bb 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -189,7 +189,7 @@
@ViewDebug.FlagToString(mask = Gravity.RELATIVE_LAYOUT_DIRECTION,
equals = Gravity.RELATIVE_LAYOUT_DIRECTION, name = "RELATIVE")
}, formatToHexString = true)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mGravity = Gravity.START | Gravity.TOP;
@ViewDebug.ExportedProperty(category = "measurement")
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 74051e2..506d615 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -204,7 +204,7 @@
private View mBaselineView = null;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
private int mGravity = Gravity.START | Gravity.TOP;
private final Rect mContentBounds = new Rect();
private final Rect mSelfBounds = new Rect();
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index d55c09f..79dc670 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -1419,27 +1419,10 @@
return Switch.class.getName();
}
+ /** @hide */
@Override
- public void onProvideStructure(ViewStructure structure) {
- super.onProvideStructure(structure);
- onProvideStructureForAssistOrAutofillOrViewCapture(structure);
- }
-
- @Override
- public void onProvideAutofillStructure(ViewStructure structure, int flags) {
- super.onProvideAutofillStructure(structure, flags);
- onProvideStructureForAssistOrAutofillOrViewCapture(structure);
- }
-
- @Override
- public boolean onProvideContentCaptureStructure(ViewStructure structure, int flags) {
- final boolean notifyManager = super.onProvideContentCaptureStructure(structure, flags);
- onProvideStructureForAssistOrAutofillOrViewCapture(structure);
- return notifyManager;
- }
-
- // NOTE: currently there is no difference for any type, so it doesn't take flags
- private void onProvideStructureForAssistOrAutofillOrViewCapture(ViewStructure structure) {
+ protected void onProvideStructure(@NonNull ViewStructure structure,
+ @ViewStructureType int viewFor, int flags) {
CharSequence switchText = isChecked() ? mTextOn : mTextOff;
if (!TextUtils.isEmpty(switchText)) {
CharSequence oldText = structure.getText();
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index 3861739..826cd89 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -109,6 +109,13 @@
uid -> 1000 <= uid && uid < 2000;
/**
+ * Do not report any threads that have a total CPU usage (across all frequencies) less than or
+ * equal to this number. This significantly reduces the amount of reported threads without
+ * losing any important information
+ */
+ private static final int TOTAL_CPU_USAGE_THRESHOLD_MILLIS = 20;
+
+ /**
* Value returned when there was an error getting an integer ID value (e.g. PID, UID)
*/
private static final int ID_ERROR = -1;
@@ -339,6 +346,15 @@
}
int[] cpuUsages = mFrequencyBucketCreator.getBucketedValues(cpuUsagesLong);
+ // Filter threads that have low total CPU usage
+ int cpuUsageSum = 0;
+ for (int i = 0; i < cpuUsages.length; i++) {
+ cpuUsageSum += cpuUsages[i];
+ }
+ if (cpuUsageSum <= TOTAL_CPU_USAGE_THRESHOLD_MILLIS) {
+ return null;
+ }
+
return new ThreadCpuUsage(threadId, threadName, cpuUsages);
}
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index 2b661c2..cf2a297 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -50,6 +50,7 @@
private int mSamplingInterval;
private CachedDeviceState.Readonly mDeviceState;
private long mStartTime = System.currentTimeMillis();
+ private boolean mAddDebugEntries = false;
public LooperStats(int samplingInterval, int entriesSizeCap) {
this.mSamplingInterval = samplingInterval;
@@ -60,6 +61,10 @@
mDeviceState = deviceState;
}
+ public void setAddDebugEntries(boolean addDebugEntries) {
+ mAddDebugEntries = addDebugEntries;
+ }
+
@Override
public Object messageDispatchStarting() {
if (deviceStateAllowsCollection() && shouldCollectDetailedData()) {
@@ -142,9 +147,22 @@
// Add the overflow and collision entries only if they have any data.
maybeAddSpecialEntry(exportedEntries, mOverflowEntry);
maybeAddSpecialEntry(exportedEntries, mHashCollisionEntry);
+ // Debug entries added to help validate the data.
+ if (mAddDebugEntries) {
+ exportedEntries.add(createDebugEntry("start_time_millis", mStartTime));
+ exportedEntries.add(createDebugEntry("end_time_millis", System.currentTimeMillis()));
+ }
return exportedEntries;
}
+ private ExportedEntry createDebugEntry(String variableName, long value) {
+ final Entry entry = new Entry("__DEBUG_" + variableName);
+ entry.messageCount = 1;
+ entry.recordedMessageCount = 1;
+ entry.maxDelayMillis = value;
+ return new ExportedEntry(entry);
+ }
+
/** Returns a timestamp indicating when the statistics were last reset. */
public long getStartTimeMillis() {
return mStartTime;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index b0dbaa0..99f096d 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -97,7 +97,7 @@
message WindowManagerPolicyProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- optional int32 last_system_ui_flags = 1;
+ optional int32 last_system_ui_flags = 1 [deprecated=true];
enum UserRotationMode {
USER_ROTATION_FREE = 0;
USER_ROTATION_LOCKED = 1;
@@ -108,18 +108,18 @@
optional bool screen_on_fully = 5;
optional bool keyguard_draw_complete = 6;
optional bool window_manager_draw_complete = 7;
- optional string focused_app_token = 8;
- optional IdentifierProto focused_window = 9;
- optional IdentifierProto top_fullscreen_opaque_window = 10;
- optional IdentifierProto top_fullscreen_opaque_or_dimming_window = 11;
+ optional string focused_app_token = 8 [deprecated=true];
+ optional IdentifierProto focused_window = 9 [deprecated=true];
+ optional IdentifierProto top_fullscreen_opaque_window = 10 [deprecated=true];
+ optional IdentifierProto top_fullscreen_opaque_or_dimming_window = 11 [deprecated=true];
optional bool keyguard_occluded = 12;
optional bool keyguard_occluded_changed = 13;
optional bool keyguard_occluded_pending = 14;
- optional bool force_status_bar = 15;
- optional bool force_status_bar_from_keyguard = 16;
- optional BarControllerProto status_bar = 17;
- optional BarControllerProto navigation_bar = 18;
- optional WindowOrientationListenerProto orientation_listener = 19;
+ optional bool force_status_bar = 15 [deprecated=true];
+ optional bool force_status_bar_from_keyguard = 16 [deprecated=true];
+ optional BarControllerProto status_bar = 17 [deprecated=true];
+ optional BarControllerProto navigation_bar = 18 [deprecated=true];
+ optional WindowOrientationListenerProto orientation_listener = 19 [deprecated=true];
optional KeyguardServiceDelegateProto keyguard_delegate = 20;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e35b701..e064423 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4500,6 +4500,14 @@
</intent-filter>
</receiver>
+ <receiver android:name="com.android.server.updates.ConversationActionsInstallReceiver"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.intent.action.ACTION_UPDATE_CONVERSATION_ACTIONS" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
<receiver android:name="com.android.server.updates.CarrierIdInstallReceiver"
android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
diff --git a/core/res/res/layout/notification_material_action.xml b/core/res/res/layout/notification_material_action.xml
index 3c9f6ee..c024dbe 100644
--- a/core/res/res/layout/notification_material_action.xml
+++ b/core/res/res/layout/notification_material_action.xml
@@ -16,16 +16,14 @@
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
- style="@android:style/Widget.Material.Light.Button.Borderless.Small"
+ style="@android:style/NotificationAction"
android:id="@+id/action0"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_gravity="center"
android:gravity="start|center_vertical"
android:layout_marginStart="4dp"
- android:textColor="@color/notification_default_color"
android:singleLine="true"
android:textAlignment="viewStart"
android:ellipsize="end"
- android:background="@drawable/notification_material_action_background"
/>
diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
index 07559f4..4258019 100644
--- a/core/res/res/layout/notification_material_action_list.xml
+++ b/core/res/res/layout/notification_material_action_list.xml
@@ -18,6 +18,7 @@
android:id="@+id/actions_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/notification_action_list_margin_top"
android:layout_gravity="bottom">
<com.android.internal.widget.NotificationActionListLayout
android:id="@+id/actions"
@@ -27,6 +28,7 @@
android:orientation="horizontal"
android:gravity="center_vertical"
android:visibility="gone"
+ android:background="@color/notification_action_list_background_color"
>
<!-- actions will be added here -->
</com.android.internal.widget.NotificationActionListLayout>
diff --git a/core/res/res/layout/notification_material_action_tombstone.xml b/core/res/res/layout/notification_material_action_tombstone.xml
index 9fa7c6a..f165724 100644
--- a/core/res/res/layout/notification_material_action_tombstone.xml
+++ b/core/res/res/layout/notification_material_action_tombstone.xml
@@ -16,7 +16,7 @@
-->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
- style="@android:style/Widget.Material.Light.Button.Borderless.Small"
+ style="@android:style/NotificationTombstoneAction"
android:id="@+id/action0"
android:layout_width="wrap_content"
android:layout_height="48dp"
diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml
index 9de8842..a2ad3b9 100644
--- a/core/res/res/values-night/values.xml
+++ b/core/res/res/values-night/values.xml
@@ -20,7 +20,7 @@
<!-- Color palette -->
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
<item name="colorSecondary">@color/secondary_device_default_settings</item>
- <item name="colorAccent">@color/white</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
<item name="colorError">@color/error_color_device_default_dark</item>
<item name="colorControlNormal">?attr/textColorPrimary</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 605662a..6c4861b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7941,6 +7941,11 @@
<!-- Uri that specifies a settings Slice for this wallpaper. -->
<attr name="settingsSliceUri" />
+ <!-- Indicates that this wallpaper service can support multiple engines to render on each
+ surface independently. An example use case is a multi-display set-up where the
+ wallpaper service can render surfaces to each of the connected displays. -->
+ <attr name="supportsMultipleDisplays" format="boolean" />
+
</declare-styleable>
<!-- Use <code>dream</code> as the root tag of the XML resource that
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 4122cf0..16c0744 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -146,10 +146,14 @@
<color name="notification_default_color">#757575</color> <!-- Gray 600 -->
+ <color name="notification_action_button_text_color">@color/notification_default_color</color>
+
<color name="notification_progress_background_color">@color/secondary_text_material_light</color>
<color name="notification_action_list">#ffeeeeee</color>
+ <color name="notification_action_list_background_color">@null</color>
+
<!-- Keyguard colors -->
<color name="keyguard_avatar_frame_color">#ffffffff</color>
<color name="keyguard_avatar_frame_shadow_color">#80000000</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 829d6f5..1d80961 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -364,7 +364,7 @@
<!-- Max number of Bluetooth tethering connections allowed. If this is
updated config_tether_dhcp_range has to be updated appropriately. -->
- <integer translateable="false" name="config_max_pan_devices">5</integer>
+ <integer translatable="false" name="config_max_pan_devices">5</integer>
<!-- Dhcp range (min, max) to use for tethering purposes -->
<string-array translatable="false" name="config_tether_dhcp_range">
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index e902989..f7b9961 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -200,6 +200,9 @@
<!-- The height of the notification action list -->
<dimen name="notification_action_list_height">60dp</dimen>
+ <!-- The margin of the notification action list at the top -->
+ <dimen name="notification_action_list_margin_top">0dp</dimen>
+
<!-- The height of the notification action list -->
<dimen name="notification_action_emphasized_height">48dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 73dae08..3373d14 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2920,6 +2920,7 @@
<public name="shell" />
<public name="interactiveUiTimeout" />
<public name="importantForContentCapture" />
+ <public name="supportsMultipleDisplays" />
</public-group>
<public-group type="drawable" first-id="0x010800b4">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 200c35d..9204ee4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2989,6 +2989,12 @@
<!-- Accessibility description for an item in the text selection menu to track a flight [CHAR LIMIT=NONE] -->
<string name="view_flight_desc">Track selected flight</string>
+ <!-- Label for item in the text selection menu to translate selected text with a translation app. Should be a verb. [CHAR LIMIT=30] -->
+ <string name="translate">Translate</string>
+
+ <!-- Accessibility description for an item in the text selection menu to translate selected text with a translation app. [CHAR LIMIT=NONE] -->
+ <string name="translate_desc">Translate selected text</string>
+
<!-- If the device is getting low on internal storage, a notification is shown to the user. This is the title of that notification. -->
<string name="low_internal_storage_view_title">Storage space running out</string>
<!-- If the device is getting low on internal storage, a notification is shown to the user. This is the message of that notification. -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index bd53936..18f7e48 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1526,10 +1526,22 @@
<item name="gravity">top</item>
</style>
- <!-- Colored bordered ink button -->
+ <!-- The style for normal action button on notification -->
+ <style name="NotificationAction" parent="Widget.Material.Light.Button.Borderless.Small">
+ <item name="textColor">@color/notification_action_button_text_color</item>
+ <item name="background">@drawable/notification_material_action_background</item>
+ </style>
+
+ <!-- The style for emphasized action button on notification: Colored bordered ink button -->
<style name="NotificationEmphasizedAction" parent="Widget.Material.Button">
<item name="background">@drawable/btn_notification_emphasized</item>
<item name="stateListAnimator">@anim/flat_button_state_list_anim_material</item>
</style>
+ <!-- The style for disabled action button on notification -->
+ <style name="NotificationTombstoneAction" parent="NotificationAction">
+ <item name="textColor">#555555</item>
+ </style>
+
+
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 82c9ff3..7a78327 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -574,6 +574,8 @@
<java-symbol type="string" name="add_calendar_event_desc" />
<java-symbol type="string" name="view_flight" />
<java-symbol type="string" name="view_flight_desc" />
+ <java-symbol type="string" name="translate" />
+ <java-symbol type="string" name="translate_desc" />
<java-symbol type="string" name="textSelectionCABTitle" />
<java-symbol type="string" name="BaMmi" />
<java-symbol type="string" name="CLIRDefaultOffNextCallOff" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 002b6a8..2c001c9 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -124,6 +124,7 @@
Settings.Global.AUTOFILL_LOGGING_LEVEL,
Settings.Global.AUTOFILL_MAX_PARTITIONS_SIZE,
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS,
+ Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS,
Settings.Global.AUTOMATIC_POWER_SAVER_MODE,
Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD,
Settings.Global.BATTERY_DISCHARGE_THRESHOLD,
@@ -181,6 +182,8 @@
Settings.Global.CONNECTIVITY_METRICS_BUFFER_SIZE,
Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
Settings.Global.CONTACT_METADATA_SYNC_ENABLED,
+ Settings.Global.CONVERSATION_ACTIONS_UPDATE_CONTENT_URL,
+ Settings.Global.CONVERSATION_ACTIONS_UPDATE_METADATA_URL,
Settings.Global.CONTACTS_DATABASE_WAL_ENABLED,
Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE,
Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
@@ -281,6 +284,7 @@
Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
+ Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS,
Settings.Global.LOCATION_LAST_LOCATION_MAX_AGE_MILLIS,
Settings.Global.LOCATION_GLOBAL_KILL_SWITCH,
Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
diff --git a/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
new file mode 100644
index 0000000..0180856
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/FakeContextBuilder.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.support.test.InstrumentationRegistry;
+
+import androidx.annotation.Nullable;
+
+import com.google.common.base.Preconditions;
+
+import org.mockito.stubbing.Answer;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * A builder used to build a fake context for testing.
+ */
+// TODO: Consider making public.
+final class FakeContextBuilder {
+
+ /**
+ * A component name that can be used for tests.
+ */
+ public static final ComponentName DEFAULT_COMPONENT = new ComponentName("pkg", "cls");
+
+ private final PackageManager mPackageManager;
+ private final ContextWrapper mContext;
+ private final Map<String, ComponentName> mComponents = new HashMap<>();
+ private @Nullable ComponentName mAllIntentComponent;
+
+ FakeContextBuilder() {
+ mPackageManager = mock(PackageManager.class);
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenReturn(null);
+ mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()) {
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
+ };
+ }
+
+ /**
+ * Sets the component name of an activity to handle the specified intent action.
+ * <p>
+ * <strong>NOTE: </strong>By default, no component is set to handle any intent.
+ */
+ public FakeContextBuilder setIntentComponent(
+ String intentAction, @Nullable ComponentName component) {
+ Preconditions.checkNotNull(intentAction);
+ mComponents.put(intentAction, component);
+ return this;
+ }
+
+
+ /**
+ * Sets the component name of an activity to handle all intents.
+ * <p>
+ * <strong>NOTE: </strong>By default, no component is set to handle any intent.
+ */
+ public FakeContextBuilder setAllIntentComponent(@Nullable ComponentName component) {
+ mAllIntentComponent = component;
+ return this;
+ }
+
+ /**
+ * Builds and returns a fake context.
+ */
+ public Context build() {
+ when(mPackageManager.resolveActivity(any(Intent.class), anyInt())).thenAnswer(
+ (Answer<ResolveInfo>) invocation -> {
+ final String action = ((Intent) invocation.getArgument(0)).getAction();
+ final ComponentName component = mComponents.containsKey(action)
+ ? mComponents.get(action)
+ : mAllIntentComponent;
+ return getResolveInfo(component);
+ });
+ return mContext;
+ }
+
+ /**
+ * Returns a component name with random package and class names.
+ */
+ public static ComponentName newComponent() {
+ return new ComponentName(UUID.randomUUID().toString(), UUID.randomUUID().toString());
+ }
+
+ private static ResolveInfo getResolveInfo(ComponentName component) {
+ final ResolveInfo info;
+ if (component == null) {
+ info = null;
+ } else {
+ // NOTE: If something breaks in TextClassifier because we expect more fields to be set
+ // in here, just add them.
+ info = new ResolveInfo();
+ info.activityInfo = new ActivityInfo();
+ info.activityInfo.packageName = component.getPackageName();
+ info.activityInfo.name = component.getClassName();
+ info.activityInfo.exported = true;
+ info.activityInfo.applicationInfo = new ApplicationInfo();
+ info.activityInfo.applicationInfo.icon = 0;
+ }
+ return info;
+ }
+
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 46aa5b4..a3f69d9 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -20,18 +20,10 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.argThat;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
import android.os.LocaleList;
import android.service.textclassifier.TextClassifierService;
import android.support.test.InstrumentationRegistry;
@@ -41,7 +33,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatcher;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -78,23 +69,10 @@
@Test
public void testCannotResolveIntent() {
- final PackageManager fakePackageMgr = mock(PackageManager.class);
-
- ResolveInfo validInfo = mContext.getPackageManager().resolveActivity(
- new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:+12122537077")), 0);
- // Make packageManager fail when it gets the following intent:
- ArgumentMatcher<Intent> toFailIntent =
- intent -> intent.getAction().equals(Intent.ACTION_INSERT_OR_EDIT);
-
- when(fakePackageMgr.resolveActivity(any(Intent.class), anyInt())).thenReturn(validInfo);
- when(fakePackageMgr.resolveActivity(argThat(toFailIntent), anyInt())).thenReturn(null);
-
- ContextWrapper fakeContext = new ContextWrapper(mContext) {
- @Override
- public PackageManager getPackageManager() {
- return fakePackageMgr;
- }
- };
+ Context fakeContext = new FakeContextBuilder()
+ .setAllIntentComponent(FakeContextBuilder.DEFAULT_COMPONENT)
+ .setIntentComponent(Intent.ACTION_INSERT_OR_EDIT, null)
+ .build();
TextClassifier fallback = TextClassifier.NO_OP;
TextClassifier classifier = new TextClassifierImpl(
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
index b242a34..385bad5 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
@@ -39,7 +39,9 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.List;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -56,8 +58,8 @@
1000, 2000, 3000, 4000,
};
private static final int[][] THREAD_CPU_TIMES = {
- {1, 0, 0, 1},
- {0, 0, 0, 0},
+ {100, 0, 0, 100},
+ {0, 0, 9999999, 0},
{1000, 1000, 1000, 1000},
{0, 1, 2, 3},
};
@@ -108,6 +110,42 @@
}
@Test
+ public void testReader_filtersLowTotalCpuUsage() throws IOException {
+ KernelCpuThreadReader.Injector processUtils =
+ new KernelCpuThreadReader.Injector() {
+ @Override
+ public int myPid() {
+ return PROCESS_ID;
+ }
+
+ @Override
+ public int myUid() {
+ return UID;
+ }
+
+ @Override
+ public int getUidForPid(int pid) {
+ return 0;
+ }
+ };
+ setupDirectory(mProcDirectory.toPath().resolve("self"), new int[]{1, 2}, PROCESS_NAME,
+ THREAD_NAMES, new int[]{1000, 2000}, new int[][]{{0, 1}, {100, 0}});
+
+ final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
+ mProcDirectory.toPath(),
+ mProcDirectory.toPath().resolve("self/task/1/time_in_state"),
+ processUtils);
+ final KernelCpuThreadReader.ProcessCpuUsage processCpuUsage =
+ kernelCpuThreadReader.getCurrentProcessCpuUsage();
+
+ List<Integer> threadIds = processCpuUsage.threadCpuUsages.stream()
+ .map(t -> t.threadId)
+ .collect(Collectors.toList());
+ assertEquals(1, threadIds.size());
+ assertEquals(2, (long) threadIds.get(0));
+ }
+
+ @Test
public void testReader_byUids() throws IOException {
int[] uids = new int[]{0, 2, 3, 4, 5, 6000};
Predicate<Integer> uidPredicate = uid -> uid == 0 || uid >= 4;
@@ -134,7 +172,7 @@
setupDirectory(mProcDirectory.toPath().resolve(String.valueOf(uid)),
new int[]{uid * 10},
"process" + uid, new String[]{"thread" + uid}, new int[]{1000},
- new int[][]{{uid}});
+ new int[][]{{uid + 100}});
}
final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
mProcDirectory.toPath(),
@@ -151,7 +189,7 @@
int uid = expectedUids[i];
checkResults(processCpuUsage, kernelCpuThreadReader.getCpuFrequenciesKhz(),
uid, uid, new int[]{uid * 10}, "process" + uid, new String[]{"thread" + uid},
- new int[]{1000}, new int[][]{{uid}});
+ new int[]{1000}, new int[][]{{uid + 100}});
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index f637b7c..31dde5c 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -105,7 +105,6 @@
assertThat(entry.recordedDelayMessageCount).isEqualTo(1);
assertThat(entry.delayMillis).isEqualTo(30);
assertThat(entry.maxDelayMillis).isEqualTo(30);
-
}
@Test
@@ -429,6 +428,28 @@
assertThat(entries).hasSize(0);
}
+ @Test
+ public void testAddsDebugEntries() {
+ TestableLooperStats looperStats = new TestableLooperStats(1, 100);
+ looperStats.setAddDebugEntries(true);
+
+ Message message = mHandlerFirst.obtainMessage(1000);
+ message.when = looperStats.getSystemUptimeMillis();
+ Object token = looperStats.messageDispatchStarting();
+ looperStats.messageDispatched(token, message);
+
+ List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+ assertThat(entries).hasSize(3);
+ LooperStats.ExportedEntry debugEntry1 = entries.get(1);
+ assertThat(debugEntry1.handlerClassName).isEqualTo("");
+ assertThat(debugEntry1.messageName).isEqualTo("__DEBUG_start_time_millis");
+ assertThat(debugEntry1.maxDelayMillis).isEqualTo(looperStats.getStartTimeMillis());
+ LooperStats.ExportedEntry debugEntry2 = entries.get(2);
+ assertThat(debugEntry2.handlerClassName).isEqualTo("");
+ assertThat(debugEntry2.messageName).isEqualTo("__DEBUG_end_time_millis");
+ assertThat(debugEntry2.maxDelayMillis).isAtLeast(looperStats.getStartTimeMillis());
+ }
+
private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) {
try {
r.run();
@@ -450,6 +471,7 @@
super(samplingInterval, sizeCap);
this.mSamplingInterval = samplingInterval;
this.setDeviceState(mDeviceState.getReadonlyClient());
+ this.setAddDebugEntries(false);
}
void tickRealtime(long micros) {
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index fdd638a..dea2f45 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -108,11 +108,10 @@
* Scaled mask based on the view bounds.
*/
private final Path mMask;
+ private final Path mMaskScaleOnly;
private final Matrix mMaskMatrix;
private final Region mTransparentRegion;
- private Bitmap mMaskBitmap;
-
/**
* Indices used to access {@link #mLayerState.mChildDrawable} array for foreground and
* background layer.
@@ -156,8 +155,8 @@
sMask = PathParser.createPathFromPathData(
Resources.getSystem().getString(R.string.config_icon_mask));
}
- mMask = PathParser.createPathFromPathData(
- Resources.getSystem().getString(R.string.config_icon_mask));
+ mMask = new Path(sMask);
+ mMaskScaleOnly = new Path(mMask);
mMaskMatrix = new Matrix();
mCanvas = new Canvas();
mTransparentRegion = new Region();
@@ -329,24 +328,19 @@
}
private void updateMaskBoundsInternal(Rect b) {
+ // reset everything that depends on the view bounds
mMaskMatrix.setScale(b.width() / MASK_SIZE, b.height() / MASK_SIZE);
+ sMask.transform(mMaskMatrix, mMaskScaleOnly);
+
+ mMaskMatrix.postTranslate(b.left, b.top);
sMask.transform(mMaskMatrix, mMask);
- if (mMaskBitmap == null || mMaskBitmap.getWidth() != b.width() ||
- mMaskBitmap.getHeight() != b.height()) {
- mMaskBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ALPHA_8);
+ if (mLayersBitmap == null || mLayersBitmap.getWidth() != b.width()
+ || mLayersBitmap.getHeight() != b.height()) {
mLayersBitmap = Bitmap.createBitmap(b.width(), b.height(), Bitmap.Config.ARGB_8888);
}
- // mMaskBitmap bound [0, w] x [0, h]
- mCanvas.setBitmap(mMaskBitmap);
- mPaint.setShader(null);
- mCanvas.drawPath(mMask, mPaint);
- // mMask bound [left, top, right, bottom]
- mMaskMatrix.postTranslate(b.left, b.top);
- mMask.reset();
- sMask.transform(mMaskMatrix, mMask);
- // reset everything that depends on the view bounds
+ mPaint.setShader(null);
mTransparentRegion.setEmpty();
mLayersShader = null;
}
@@ -371,9 +365,11 @@
mLayersShader = new BitmapShader(mLayersBitmap, TileMode.CLAMP, TileMode.CLAMP);
mPaint.setShader(mLayersShader);
}
- if (mMaskBitmap != null) {
+ if (mMaskScaleOnly != null) {
Rect bounds = getBounds();
- canvas.drawBitmap(mMaskBitmap, bounds.left, bounds.top, mPaint);
+ canvas.translate(bounds.left, bounds.top);
+ canvas.drawPath(mMaskScaleOnly, mPaint);
+ canvas.translate(-bounds.left, -bounds.top);
}
}
@@ -549,7 +545,7 @@
final ChildDrawable[] layers = mLayerState.mChildren;
for (int i = 0; i < mLayerState.N_CHILDREN; i++) {
- if (layers[i].mDrawable.isProjected()) {
+ if (layers[i].mDrawable != null && layers[i].mDrawable.isProjected()) {
return true;
}
}
@@ -674,7 +670,7 @@
@Override
public int getAlpha() {
- return PixelFormat.TRANSLUCENT;
+ return mPaint.getAlpha();
}
@Override
@@ -718,10 +714,7 @@
@Override
public int getOpacity() {
- if (mLayerState.mOpacityOverride != PixelFormat.UNKNOWN) {
- return mLayerState.mOpacityOverride;
- }
- return mLayerState.getOpacity();
+ return PixelFormat.TRANSLUCENT;
}
@Override
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 1cb0d25..365be10 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -349,7 +349,7 @@
goto exit;
}
}
- ret = tables[0].createIdmap(tables[1], targetCrc, overlayCrc,
+ ret = tables[1].createIdmap(tables[0], targetCrc, overlayCrc,
targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR;
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 76db18d..f7fb89e 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -26,7 +26,9 @@
#include <algorithm>
#include <limits>
+#include <map>
#include <memory>
+#include <set>
#include <type_traits>
#include <android-base/macros.h>
@@ -7033,170 +7035,178 @@
return NO_ERROR;
}
-struct IdmapTypeMap {
- ssize_t overlayTypeId;
- size_t entryOffset;
- Vector<uint32_t> entryMap;
+struct IdmapMatchingResources {
+ void Add(uint32_t targetResId, uint32_t overlayResId) {
+ uint8_t targetTypeid = Res_GETTYPE(targetResId);
+ if (typeMappings.find(targetTypeid) == typeMappings.end()) {
+ typeMappings.emplace(targetTypeid, std::set<std::pair<uint32_t, uint32_t>>());
+ }
+ auto& entries = typeMappings[targetTypeid];
+ entries.insert(std::make_pair(targetResId, overlayResId));
+ }
+
+ void FixPadding() {
+ for (auto ti = typeMappings.cbegin(); ti != typeMappings.cend(); ++ti) {
+ uint32_t last_seen = 0xffffffff;
+ size_t total_entries = 0;
+ for (auto ei = ti->second.cbegin(); ei != ti->second.cend(); ++ei) {
+ assert(last_seen == 0xffffffff || last_seen < ei->first);
+ entryPadding[ei->first] = (last_seen == 0xffffffff) ? 0 : ei->first - last_seen - 1;
+ last_seen = ei->first;
+ total_entries += 1 + entryPadding[ei->first];
+ }
+ numberOfEntriesIncludingPadding[ti->first] = total_entries;
+ }
+ }
+
+ // resource type ID in context of target -> set of resource entries mapping target -> overlay
+ std::map<uint8_t, std::set<std::pair<uint32_t, uint32_t>>> typeMappings;
+
+ // resource ID in context of target -> trailing padding for that resource (call FixPadding
+ // before use)
+ std::map<uint32_t, size_t> entryPadding;
+
+ // resource type ID in context of target -> total number of entries, including padding entries,
+ // for that type (call FixPadding before use)
+ std::map<uint8_t, size_t> numberOfEntriesIncludingPadding;
};
-status_t ResTable::createIdmap(const ResTable& overlay,
+status_t ResTable::createIdmap(const ResTable& targetResTable,
uint32_t targetCrc, uint32_t overlayCrc,
const char* targetPath, const char* overlayPath,
void** outData, size_t* outSize) const
{
- // see README for details on the format of map
- if (mPackageGroups.size() == 0) {
- ALOGW("idmap: target package has no package groups, cannot create idmap\n");
+ if (targetPath == NULL || overlayPath == NULL || outData == NULL || outSize == NULL) {
+ ALOGE("idmap: unexpected NULL parameter");
+ return UNKNOWN_ERROR;
+ }
+ if (strlen(targetPath) > 255) {
+ ALOGE("idmap: target path exceeds idmap file format limit of 255 chars");
+ return UNKNOWN_ERROR;
+ }
+ if (strlen(overlayPath) > 255) {
+ ALOGE("idmap: overlay path exceeds idmap file format limit of 255 chars");
+ return UNKNOWN_ERROR;
+ }
+ if (mPackageGroups.size() == 0 || mPackageGroups[0]->packages.size() == 0) {
+ ALOGE("idmap: invalid overlay package");
+ return UNKNOWN_ERROR;
+ }
+ if (targetResTable.mPackageGroups.size() == 0 ||
+ targetResTable.mPackageGroups[0]->packages.size() == 0) {
+ ALOGE("idmap: invalid target package");
return UNKNOWN_ERROR;
}
- if (mPackageGroups[0]->packages.size() == 0) {
- ALOGW("idmap: target package has no packages in its first package group, "
- "cannot create idmap\n");
- return UNKNOWN_ERROR;
- }
+ const ResTable_package* targetPackageStruct = targetResTable.mPackageGroups[0]->packages[0]->package;
+ const size_t tmpNameSize = arraysize(targetPackageStruct->name);
+ char16_t tmpName[tmpNameSize];
+ strcpy16_dtoh(tmpName, targetPackageStruct->name, tmpNameSize);
+ const String16 targetPackageName(tmpName);
- // The number of resources overlaid that were not explicitly marked overlayable.
+ const PackageGroup* packageGroup = mPackageGroups[0];
+
+ // the number of resources overlaid that were not explicitly marked overlayable
size_t forcedOverlayCount = 0u;
- KeyedVector<uint8_t, IdmapTypeMap> map;
-
- // overlaid packages are assumed to contain only one package group
- const PackageGroup* pg = mPackageGroups[0];
-
- // starting size is header
- *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES;
-
- // target package id and number of types in map
- *outSize += 2 * sizeof(uint16_t);
-
- // overlay packages are assumed to contain only one package group
- const ResTable_package* overlayPackageStruct = overlay.mPackageGroups[0]->packages[0]->package;
- char16_t tmpName[sizeof(overlayPackageStruct->name)/sizeof(overlayPackageStruct->name[0])];
- strcpy16_dtoh(tmpName, overlayPackageStruct->name, sizeof(overlayPackageStruct->name)/sizeof(overlayPackageStruct->name[0]));
- const String16 overlayPackage(tmpName);
-
- for (size_t typeIndex = 0; typeIndex < pg->types.size(); ++typeIndex) {
- const TypeList& typeList = pg->types[typeIndex];
+ // find the resources that exist in both packages
+ IdmapMatchingResources matchingResources;
+ for (size_t typeIndex = 0; typeIndex < packageGroup->types.size(); ++typeIndex) {
+ const TypeList& typeList = packageGroup->types[typeIndex];
if (typeList.isEmpty()) {
continue;
}
-
const Type* typeConfigs = typeList[0];
- IdmapTypeMap typeMap;
- typeMap.overlayTypeId = -1;
- typeMap.entryOffset = 0;
-
for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
- uint32_t resID = Res_MAKEID(pg->id - 1, typeIndex, entryIndex);
- resource_name resName;
- if (!this->getResourceName(resID, false, &resName)) {
- if (typeMap.entryMap.isEmpty()) {
- typeMap.entryOffset++;
- }
+ uint32_t overlay_resid = Res_MAKEID(packageGroup->id - 1, typeIndex, entryIndex);
+ resource_name current_res;
+ if (!getResourceName(overlay_resid, false, ¤t_res)) {
continue;
}
uint32_t typeSpecFlags = 0u;
- const String16 overlayType(resName.type, resName.typeLen);
- const String16 overlayName(resName.name, resName.nameLen);
- uint32_t overlayResID = overlay.identifierForName(overlayName.string(),
- overlayName.size(),
- overlayType.string(),
- overlayType.size(),
- overlayPackage.string(),
- overlayPackage.size(),
- &typeSpecFlags);
- if (overlayResID == 0) {
- // No such target resource was found.
- if (typeMap.entryMap.isEmpty()) {
- typeMap.entryOffset++;
- }
+ const uint32_t target_resid = targetResTable.identifierForName(
+ current_res.name,
+ current_res.nameLen,
+ current_res.type,
+ current_res.typeLen,
+ targetPackageName.string(),
+ targetPackageName.size(),
+ &typeSpecFlags);
+
+ if (target_resid == 0) {
continue;
}
- // Now that we know this is being overlaid, check if it can be, and emit a warning if
- // it can't.
if ((dtohl(typeConfigs->typeSpecFlags[entryIndex]) &
ResTable_typeSpec::SPEC_OVERLAYABLE) == 0) {
- forcedOverlayCount++;
+ ++forcedOverlayCount;
}
- if (typeMap.overlayTypeId == -1) {
- typeMap.overlayTypeId = Res_GETTYPE(overlayResID) + 1;
- }
-
- if (Res_GETTYPE(overlayResID) + 1 != static_cast<size_t>(typeMap.overlayTypeId)) {
- ALOGE("idmap: can't mix type ids in entry map. Resource 0x%08x maps to 0x%08x"
- " but entries should map to resources of type %02zx",
- resID, overlayResID, typeMap.overlayTypeId);
- return BAD_TYPE;
- }
-
- if (typeMap.entryOffset + typeMap.entryMap.size() < entryIndex) {
- // pad with 0xffffffff's (indicating non-existing entries) before adding this entry
- size_t index = typeMap.entryMap.size();
- size_t numItems = entryIndex - (typeMap.entryOffset + index);
- if (typeMap.entryMap.insertAt(0xffffffff, index, numItems) < 0) {
- return NO_MEMORY;
- }
- }
- typeMap.entryMap.add(Res_GETENTRY(overlayResID));
- }
-
- if (!typeMap.entryMap.isEmpty()) {
- if (map.add(static_cast<uint8_t>(typeIndex), typeMap) < 0) {
- return NO_MEMORY;
- }
- *outSize += (4 * sizeof(uint16_t)) + (typeMap.entryMap.size() * sizeof(uint32_t));
+ matchingResources.Add(target_resid, overlay_resid);
}
}
- if (map.isEmpty()) {
- ALOGW("idmap: no resources in overlay package present in base package");
+ if (matchingResources.typeMappings.empty()) {
+ ALOGE("idmap: no matching resources");
return UNKNOWN_ERROR;
}
+ matchingResources.FixPadding();
+
+ // write idmap
+ *outSize = ResTable::IDMAP_HEADER_SIZE_BYTES; // magic, version, target and overlay crc
+ *outSize += 2 * sizeof(uint16_t); // target package id, type count
+ const auto typesEnd = matchingResources.typeMappings.cend();
+ for (auto ti = matchingResources.typeMappings.cbegin(); ti != typesEnd; ++ti) {
+ *outSize += 4 * sizeof(uint16_t); // target type, overlay type, entry count, entry offset
+ *outSize += matchingResources.numberOfEntriesIncludingPadding[ti->first] *
+ sizeof(uint32_t); // entries
+ }
if ((*outData = malloc(*outSize)) == NULL) {
return NO_MEMORY;
}
- uint32_t* data = (uint32_t*)*outData;
- *data++ = htodl(IDMAP_MAGIC);
- *data++ = htodl(ResTable::IDMAP_CURRENT_VERSION);
- *data++ = htodl(targetCrc);
- *data++ = htodl(overlayCrc);
- const char* paths[] = { targetPath, overlayPath };
- for (int j = 0; j < 2; ++j) {
- char* p = (char*)data;
- const char* path = paths[j];
- const size_t I = strlen(path);
- if (I > 255) {
- ALOGV("path exceeds expected 255 characters: %s\n", path);
- return UNKNOWN_ERROR;
- }
- for (size_t i = 0; i < 256; ++i) {
- *p++ = i < I ? path[i] : '\0';
- }
- data += 256 / sizeof(uint32_t);
- }
- const size_t mapSize = map.size();
- uint16_t* typeData = reinterpret_cast<uint16_t*>(data);
- *typeData++ = htods(pg->id);
- *typeData++ = htods(mapSize);
- for (size_t i = 0; i < mapSize; ++i) {
- uint8_t targetTypeId = map.keyAt(i);
- const IdmapTypeMap& typeMap = map[i];
- *typeData++ = htods(targetTypeId + 1);
- *typeData++ = htods(typeMap.overlayTypeId);
- *typeData++ = htods(typeMap.entryMap.size());
- *typeData++ = htods(typeMap.entryOffset);
+ // write idmap header
+ uint32_t* data = reinterpret_cast<uint32_t*>(*outData);
+ *data++ = htodl(IDMAP_MAGIC); // write: magic
+ *data++ = htodl(ResTable::IDMAP_CURRENT_VERSION); // write: version
+ *data++ = htodl(targetCrc); // write: target crc
+ *data++ = htodl(overlayCrc); // write: overlay crc
- const size_t entryCount = typeMap.entryMap.size();
- uint32_t* entries = reinterpret_cast<uint32_t*>(typeData);
- for (size_t j = 0; j < entryCount; j++) {
- entries[j] = htodl(typeMap.entryMap[j]);
+ char* charData = reinterpret_cast<char*>(data);
+ size_t pathLen = strlen(targetPath);
+ for (size_t i = 0; i < 256; ++i) {
+ *charData++ = i < pathLen ? targetPath[i] : '\0'; // write: target path
+ }
+ pathLen = strlen(overlayPath);
+ for (size_t i = 0; i < 256; ++i) {
+ *charData++ = i < pathLen ? overlayPath[i] : '\0'; // write: overlay path
+ }
+ data += (2 * 256) / sizeof(uint32_t);
+
+ // write idmap data header
+ uint16_t* typeData = reinterpret_cast<uint16_t*>(data);
+ *typeData++ = htods(targetPackageStruct->id); // write: target package id
+ *typeData++ =
+ htods(static_cast<uint16_t>(matchingResources.typeMappings.size())); // write: type count
+
+ // write idmap data
+ for (auto ti = matchingResources.typeMappings.cbegin(); ti != typesEnd; ++ti) {
+ const size_t entryCount = matchingResources.numberOfEntriesIncludingPadding[ti->first];
+ auto ei = ti->second.cbegin();
+ *typeData++ = htods(Res_GETTYPE(ei->first) + 1); // write: target type id
+ *typeData++ = htods(Res_GETTYPE(ei->second) + 1); // write: overlay type id
+ *typeData++ = htods(entryCount); // write: entry count
+ *typeData++ = htods(Res_GETENTRY(ei->first)); // write: (target) entry offset
+ uint32_t *entryData = reinterpret_cast<uint32_t*>(typeData);
+ for (; ei != ti->second.cend(); ++ei) {
+ const size_t padding = matchingResources.entryPadding[ei->first];
+ for (size_t i = 0; i < padding; ++i) {
+ *entryData++ = htodl(0xffffffff); // write: padding
+ }
+ *entryData++ = htodl(Res_GETENTRY(ei->second)); // write: (overlay) entry
}
typeData += entryCount * 2;
}
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 59abad4..ad33fcf 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1990,7 +1990,7 @@
// Return value: on success: NO_ERROR; caller is responsible for free-ing
// outData (using free(3)). On failure, any status_t value other than
// NO_ERROR; the caller should not free outData.
- status_t createIdmap(const ResTable& overlay,
+ status_t createIdmap(const ResTable& targetResTable,
uint32_t targetCrc, uint32_t overlayCrc,
const char* targetPath, const char* overlayPath,
void** outData, size_t* outSize) const;
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index 26d2896..10b83a7 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -40,7 +40,7 @@
ASSERT_EQ(NO_ERROR, overlay_table.add(overlay_data_.data(), overlay_data_.size()));
char target_name[256] = "com.android.basic";
- ASSERT_EQ(NO_ERROR, target_table_.createIdmap(overlay_table, 0, 0, target_name, target_name,
+ ASSERT_EQ(NO_ERROR, overlay_table.createIdmap(target_table_, 0, 0, target_name, target_name,
&data_, &data_size_));
}
diff --git a/location/java/android/location/ILocationListener.aidl b/location/java/android/location/ILocationListener.aidl
index 7627cf6..180183e 100644
--- a/location/java/android/location/ILocationListener.aidl
+++ b/location/java/android/location/ILocationListener.aidl
@@ -26,7 +26,9 @@
oneway interface ILocationListener
{
void onLocationChanged(in Location location);
- void onStatusChanged(String provider, int status, in Bundle extras);
void onProviderEnabled(String provider);
void onProviderDisabled(String provider);
+
+ // --- deprecated ---
+ void onStatusChanged(String provider, int status, in Bundle extras);
}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index b5d835a..ff2fad4 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -99,9 +99,10 @@
void clearTestProviderLocation(String provider, String opPackageName);
void setTestProviderEnabled(String provider, boolean enabled, String opPackageName);
void clearTestProviderEnabled(String provider, String opPackageName);
+
+ // --- deprecated ---
void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime,
String opPackageName);
- void clearTestProviderStatus(String provider, String opPackageName);
boolean sendExtraCommand(String provider, String command, inout Bundle extras);
diff --git a/location/java/android/location/LocationListener.java b/location/java/android/location/LocationListener.java
index 88904c8..aa9dddc 100644
--- a/location/java/android/location/LocationListener.java
+++ b/location/java/android/location/LocationListener.java
@@ -44,29 +44,12 @@
void onLocationChanged(Location location);
/**
- * Called when the provider status changes. This method is called when
- * a provider is unable to fetch a location or if the provider has recently
- * become available after a period of unavailability.
+ * This callback will never be invoked and providers can be considers as always in the
+ * {@link LocationProvider#AVAILABLE} state.
*
- * @param provider the name of the location provider associated with this
- * update.
- * @param status {@link LocationProvider#OUT_OF_SERVICE} if the
- * provider is out of service, and this is not expected to change in the
- * near future; {@link LocationProvider#TEMPORARILY_UNAVAILABLE} if
- * the provider is temporarily unavailable but is expected to be available
- * shortly; and {@link LocationProvider#AVAILABLE} if the
- * provider is currently available.
- * @param extras an optional Bundle which will contain provider specific
- * status variables.
- *
- * <p> A number of common key/value pairs for the extras Bundle are listed
- * below. Providers that use any of the keys on this list must
- * provide the corresponding value as described below.
- *
- * <ul>
- * <li> satellites - the number of satellites used to derive the fix
- * </ul>
+ * @deprecated This callback will never be invoked.
*/
+ @Deprecated
void onStatusChanged(String provider, int status, Bundle extras);
/**
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 02680ab..b66ceef 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -146,9 +146,14 @@
public static final String KEY_PROXIMITY_ENTERING = "entering";
/**
+ * This key is no longer in use.
+ *
* Key used for a Bundle extra holding an Integer status value
* when a status change is broadcast using a PendingIntent.
+ *
+ * @deprecated Status changes are deprecated and no longer broadcast.
*/
+ @Deprecated
public static final String KEY_STATUS_CHANGED = "status";
/**
@@ -1581,8 +1586,7 @@
}
/**
- * Sets mock status values for the given provider. These values will be used in place
- * of any actual values from the provider.
+ * This method has no effect as provider status has been deprecated and is no longer supported.
*
* @param provider the provider name
* @param status the mock status
@@ -1593,7 +1597,10 @@
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
* @throws IllegalArgumentException if no provider with the given name exists
+ *
+ * @deprecated This method has no effect.
*/
+ @Deprecated
public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
try {
mService.setTestProviderStatus(provider, status, extras, updateTime,
@@ -1604,21 +1611,19 @@
}
/**
- * Removes any mock status values associated with the given provider.
+ * This method has no effect as provider status has been deprecated and is no longer supported.
*
* @param provider the provider name
- *
* @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
* allowed} for your app.
* @throws IllegalArgumentException if no provider with the given name exists
+ *
+ * @deprecated This method has no effect.
*/
+ @Deprecated
public void clearTestProviderStatus(String provider) {
- try {
- mService.clearTestProviderStatus(provider, mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ setTestProviderStatus(provider, LocationProvider.AVAILABLE, null, 0L);
}
// --- GPS-specific support ---
diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java
index c4fd097..b69a9d7 100644
--- a/location/java/android/location/LocationProvider.java
+++ b/location/java/android/location/LocationProvider.java
@@ -34,8 +34,23 @@
* user-specified criteria.
*/
public class LocationProvider {
+
+ /**
+ * @deprecated Location provider statuses are no longer supported.
+ */
+ @Deprecated
public static final int OUT_OF_SERVICE = 0;
+
+ /**
+ * @deprecated Location provider statuses are no longer supported.
+ */
+ @Deprecated
public static final int TEMPORARILY_UNAVAILABLE = 1;
+
+ /**
+ * @deprecated Location provider statuses are no longer supported.
+ */
+ @Deprecated
public static final int AVAILABLE = 2;
/**
diff --git a/location/lib/api/current.txt b/location/lib/api/current.txt
index 1e69f16..d19559e 100644
--- a/location/lib/api/current.txt
+++ b/location/lib/api/current.txt
@@ -11,8 +11,8 @@
method public abstract void onDisable();
method public void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
method public abstract void onEnable();
- method public abstract int onGetStatus(android.os.Bundle);
- method public abstract long onGetStatusUpdateTime();
+ method public deprecated int onGetStatus(android.os.Bundle);
+ method public deprecated long onGetStatusUpdateTime();
method public boolean onSendExtraCommand(java.lang.String, android.os.Bundle);
method public abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
method public final void reportLocation(android.location.Location);
diff --git a/location/lib/java/com/android/location/provider/LocationProviderBase.java b/location/lib/java/com/android/location/provider/LocationProviderBase.java
index 30655f5..d45a4ba 100644
--- a/location/lib/java/com/android/location/provider/LocationProviderBase.java
+++ b/location/lib/java/com/android/location/provider/LocationProviderBase.java
@@ -16,14 +16,11 @@
package com.android.location.provider;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-
import android.content.Context;
import android.location.ILocationManager;
import android.location.Location;
import android.location.LocationManager;
+import android.location.LocationProvider;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -36,6 +33,10 @@
import com.android.internal.location.ProviderRequest;
import com.android.internal.util.FastPrintWriter;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+
/**
* Base class for location providers implemented as unbundled services.
*
@@ -173,6 +174,8 @@
}
/**
+ * This method will no longer be invoked.
+ *
* Returns a information on the status of this provider.
* <p>{@link android.location.LocationProvider#OUT_OF_SERVICE} is returned if the provider is
* out of service, and this is not expected to change in the near
@@ -183,10 +186,17 @@
*
* <p>If extras is non-null, additional status information may be
* added to it in the form of provider-specific key/value pairs.
+ *
+ * @deprecated This method will no longer be invoked.
*/
- public abstract int onGetStatus(Bundle extras);
+ @Deprecated
+ public int onGetStatus(Bundle extras) {
+ return LocationProvider.AVAILABLE;
+ }
/**
+ * This method will no longer be invoked.
+ *
* Returns the time at which the status was last updated. It is the
* responsibility of the provider to appropriately set this value using
* {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.
@@ -195,8 +205,13 @@
* the same status again.
*
* @return time of last status update in millis since last reboot
+ *
+ * @deprecated This method will no longer be invoked.
*/
- public abstract long onGetStatusUpdateTime();
+ @Deprecated
+ public long onGetStatusUpdateTime() {
+ return 0;
+ }
/**
* Implements addditional location provider specific additional commands.
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 976d380..ff1bdd4 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1911,7 +1911,7 @@
* system failed to generate a new session, a condition in which audio playback or recording
* will subsequently fail as well.
*/
- public static int generateAudioSessionId() {
+ public int generateAudioSessionId() {
int session = AudioSystem.newAudioSessionId();
if (session > 0) {
return session;
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 995ebb2..dfe29e9 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1135,6 +1135,10 @@
maxChannels = 6;
} else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_EAC3)) {
maxChannels = 16;
+ } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_AC4)) {
+ sampleRates = new int[] { 44100, 48000, 96000, 192000 };
+ bitRates = Range.create(16000, 2688000);
+ maxChannels = 24;
} else {
Log.w(TAG, "Unsupported mime " + mime);
mParent.mError |= ERROR_UNSUPPORTED;
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index c203fa9..7785900 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -434,9 +434,12 @@
*/
@NonNull
public List<AudioPresentation> getAudioPresentations(int trackIndex) {
- return new ArrayList<AudioPresentation>();
+ return native_getAudioPresentations(trackIndex);
}
+ @NonNull
+ private native List<AudioPresentation> native_getAudioPresentations(int trackIndex);
+
/**
* Get the PSSH info if present.
* @return a map of uuid-to-bytes, with the uuid specifying
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 5dee16e..284e422 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -138,6 +138,7 @@
public static final String MIMETYPE_AUDIO_MSGSM = "audio/gsm";
public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3";
public static final String MIMETYPE_AUDIO_EAC3 = "audio/eac3";
+ public static final String MIMETYPE_AUDIO_AC4 = "audio/ac4";
public static final String MIMETYPE_AUDIO_SCRAMBLED = "audio/scrambled";
/**
diff --git a/media/java/android/media/update/SessionToken2Provider.java b/media/java/android/media/update/SessionToken2Provider.java
deleted file mode 100644
index 95d6ce0..0000000
--- a/media/java/android/media/update/SessionToken2Provider.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.update;
-
-import android.os.Bundle;
-
-/**
- * @hide
- */
-public interface SessionToken2Provider {
- String getPackageName_impl();
- String getId_imp();
- int getType_impl();
- int getUid_impl();
- Bundle toBundle_impl();
-
- int hashCode_impl();
- boolean equals_impl(Object obj);
- String toString_impl();
-}
diff --git a/media/jni/android_media_AudioPresentation.h b/media/jni/android_media_AudioPresentation.h
index 5306de6..a3adddd 100644
--- a/media/jni/android_media_AudioPresentation.h
+++ b/media/jni/android_media_AudioPresentation.h
@@ -14,173 +14,135 @@
* limitations under the License.
*/
-#ifndef _ANDROID_MEDIA_AUDIO_PRESENTATION_H_
-#define _ANDROID_MEDIA_AUDIO_PRESENTATION_H_
+#ifndef _ANDROID_MEDIA_AUDIOPRESENTATION_H_
+#define _ANDROID_MEDIA_AUDIOPRESENTATION_H_
#include "jni.h"
-#include <media/AudioPresentationInfo.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-
+#include <media/stagefright/foundation/ADebug.h> // CHECK
+#include <media/stagefright/foundation/AudioPresentationInfo.h>
#include <nativehelper/ScopedLocalRef.h>
namespace android {
struct JAudioPresentationInfo {
struct fields_t {
- jclass clazz;
+ jclass clazz = NULL;
jmethodID constructID;
// list parameters
- jclass listclazz;
+ jclass listClazz = NULL;
jmethodID listConstructId;
jmethodID listAddId;
+ // hashmap parameters
+ jclass hashMapClazz = NULL;
+ jmethodID hashMapConstructID;
+ jmethodID hashMapPutID;
+
+ // ulocale parameters
+ jclass ulocaleClazz = NULL;
+ jmethodID ulocaleConstructID;
+
void init(JNIEnv *env) {
jclass lclazz = env->FindClass("android/media/AudioPresentation");
- if (lclazz == NULL) {
- return;
- }
-
+ CHECK(lclazz != NULL);
clazz = (jclass)env->NewGlobalRef(lclazz);
- if (clazz == NULL) {
- return;
- }
-
+ CHECK(clazz != NULL);
constructID = env->GetMethodID(clazz, "<init>",
- "(IILandroid/icu/util/ULocale;IZZZLjava/util/Map;)V");
- env->DeleteLocalRef(lclazz);
+ "(IILandroid/icu/util/ULocale;IZZZLjava/util/Map;)V");
+ CHECK(constructID != NULL);
// list objects
- jclass llistclazz = env->FindClass("java/util/ArrayList");
- CHECK(llistclazz != NULL);
- listclazz = static_cast<jclass>(env->NewGlobalRef(llistclazz));
- CHECK(listclazz != NULL);
- listConstructId = env->GetMethodID(listclazz, "<init>", "()V");
+ jclass llistClazz = env->FindClass("java/util/ArrayList");
+ CHECK(llistClazz != NULL);
+ listClazz = static_cast<jclass>(env->NewGlobalRef(llistClazz));
+ CHECK(listClazz != NULL);
+ listConstructId = env->GetMethodID(listClazz, "<init>", "()V");
CHECK(listConstructId != NULL);
- listAddId = env->GetMethodID(listclazz, "add", "(Ljava/lang/Object;)Z");
+ listAddId = env->GetMethodID(listClazz, "add", "(Ljava/lang/Object;)Z");
CHECK(listAddId != NULL);
- env->DeleteLocalRef(llistclazz);
+
+ // hashmap objects
+ jclass lhashMapClazz = env->FindClass("java/util/HashMap");
+ CHECK(lhashMapClazz != NULL);
+ hashMapClazz = (jclass)env->NewGlobalRef(lhashMapClazz);
+ CHECK(hashMapClazz != NULL);
+ hashMapConstructID = env->GetMethodID(hashMapClazz, "<init>", "()V");
+ CHECK(hashMapConstructID != NULL);
+ hashMapPutID = env->GetMethodID(
+ hashMapClazz,
+ "put",
+ "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+ CHECK(hashMapPutID != NULL);
+
+ jclass lulocaleClazz = env->FindClass("android/icu/util/ULocale");
+ CHECK(lulocaleClazz != NULL);
+ ulocaleClazz = (jclass)env->NewGlobalRef(lulocaleClazz);
+ CHECK(ulocaleClazz != NULL);
+ ulocaleConstructID = env->GetMethodID(ulocaleClazz, "<init>", "(Ljava/lang/String;)V");
+ CHECK(ulocaleConstructID != NULL);
}
void exit(JNIEnv *env) {
- env->DeleteGlobalRef(clazz);
- clazz = NULL;
- env->DeleteGlobalRef(listclazz);
- listclazz = NULL;
+ env->DeleteGlobalRef(clazz); clazz = NULL;
+ env->DeleteGlobalRef(listClazz); listClazz = NULL;
+ env->DeleteGlobalRef(hashMapClazz); hashMapClazz = NULL;
+ env->DeleteGlobalRef(ulocaleClazz); ulocaleClazz = NULL;
}
};
- static status_t ConvertMessageToMap(JNIEnv *env, const sp<AMessage> &msg, jobject *map) {
- ScopedLocalRef<jclass> hashMapClazz(env, env->FindClass("java/util/HashMap"));
-
- if (hashMapClazz.get() == NULL) {
- return -EINVAL;
- }
- jmethodID hashMapConstructID =
- env->GetMethodID(hashMapClazz.get(), "<init>", "()V");
-
- if (hashMapConstructID == NULL) {
- return -EINVAL;
- }
- jmethodID hashMapPutID =
- env->GetMethodID(
- hashMapClazz.get(),
- "put",
- "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
-
- if (hashMapPutID == NULL) {
- return -EINVAL;
- }
-
- jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID);
-
- for (size_t i = 0; i < msg->countEntries(); ++i) {
- AMessage::Type valueType;
- const char *key = msg->getEntryNameAt(i, &valueType);
-
- if (!strncmp(key, "android._", 9)) {
- // don't expose private keys (starting with android._)
- continue;
- }
- jobject valueObj = NULL;
- AString val;
- CHECK(msg->findString(key, &val));
- valueObj = env->NewStringUTF(val.c_str());
- if (valueObj != NULL) {
- ScopedLocalRef<jclass> localeClazz(env, env->FindClass("android/icu/util/ULocale"));
- if (localeClazz.get() == NULL) {
- return -EINVAL;
- }
- jmethodID localeConstructID =
- env->GetMethodID(localeClazz.get(), "<init>", "(Ljava/lang/String;)V");
- if (localeConstructID == NULL) {
- return -EINVAL;
- }
- jstring jLanguage = env->NewStringUTF(key);
- jobject jLocale = env->NewObject(localeClazz.get(), localeConstructID, jLanguage);
- env->CallObjectMethod(hashMap, hashMapPutID, jLocale, valueObj);
- env->DeleteLocalRef(jLocale); jLocale = NULL;
- env->DeleteLocalRef(valueObj); valueObj = NULL;
- env->DeleteLocalRef(jLanguage); jLanguage = NULL;
- }
- }
-
- *map = hashMap;
-
- return OK;
+ static jobject asJobject(JNIEnv *env, const fields_t& fields) {
+ return env->NewObject(fields.listClazz, fields.listConstructId);
}
- jobject asJobject(JNIEnv *env, const fields_t& fields, const AudioPresentationInfo &info) {
- jobject list = env->NewObject(fields.listclazz, fields.listConstructId);
-
- for (size_t i = 0; i < info.countPresentations(); ++i) {
- const sp<AudioPresentation> &ap = info.getPresentation(i);
- jobject jLabelObject;
-
- sp<AMessage> labelMessage = new AMessage();
- for (size_t i = 0; i < ap->mLabels.size(); ++i) {
- labelMessage->setString(ap->mLabels.keyAt(i).string(),
- ap->mLabels.valueAt(i).string());
+ static void addPresentations(JNIEnv *env, const fields_t& fields,
+ const AudioPresentationCollection& presentations, jobject presentationsJObj) {
+ for (const auto& ap : presentations) {
+ ScopedLocalRef<jobject> jLabelObject = convertLabelsToMap(env, fields, ap.mLabels);
+ if (jLabelObject == nullptr) return;
+ ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(ap.mLanguage.c_str()));
+ if (jLanguage == nullptr) return;
+ ScopedLocalRef<jobject> jLocale(env, env->NewObject(
+ fields.ulocaleClazz, fields.ulocaleConstructID, jLanguage.get()));
+ ScopedLocalRef<jobject> jValueObj(env, env->NewObject(fields.clazz, fields.constructID,
+ static_cast<jint>(ap.mPresentationId),
+ static_cast<jint>(ap.mProgramId),
+ jLocale.get(),
+ static_cast<jint>(ap.mMasteringIndication),
+ static_cast<jboolean>((ap.mAudioDescriptionAvailable == 1) ? 1 : 0),
+ static_cast<jboolean>((ap.mSpokenSubtitlesAvailable == 1) ? 1 : 0),
+ static_cast<jboolean>((ap.mDialogueEnhancementAvailable == 1) ? 1 : 0),
+ jLabelObject.get()));
+ if (jValueObj != nullptr) {
+ env->CallBooleanMethod(presentationsJObj, fields.listAddId, jValueObj.get());
}
- if (ConvertMessageToMap(env, labelMessage, &jLabelObject) != OK) {
- return NULL;
- }
- ScopedLocalRef<jclass> localeClazz(env, env->FindClass("android/icu/util/ULocale"));
- if (localeClazz.get() == NULL) {
- return NULL;
- }
- jmethodID localeConstructID =
- env->GetMethodID(localeClazz.get(), "<init>", "(Ljava/lang/String;)V");
- if (localeConstructID == NULL) {
- return NULL;
- }
- jstring jLanguage = env->NewStringUTF(ap->mLanguage.c_str());
- jobject jLocale = env->NewObject(localeClazz.get(), localeConstructID, jLanguage);
- jobject jValueObj = env->NewObject(fields.clazz, fields.constructID,
- static_cast<jint>(ap->mPresentationId),
- static_cast<jint>(ap->mProgramId),
- jLocale,
- static_cast<jint>(ap->mMasteringIndication),
- static_cast<jboolean>((ap->mAudioDescriptionAvailable == 1) ?
- 1 : 0),
- static_cast<jboolean>((ap->mSpokenSubtitlesAvailable == 1) ?
- 1 : 0),
- static_cast<jboolean>((ap->mDialogueEnhancementAvailable == 1) ?
- 1 : 0),
- jLabelObject);
- if (jValueObj == NULL) {
- env->DeleteLocalRef(jLanguage); jLanguage = NULL;
- return NULL;
- }
-
- env->CallBooleanMethod(list, fields.listAddId, jValueObj);
- env->DeleteLocalRef(jLocale); jLocale = NULL;
- env->DeleteLocalRef(jValueObj); jValueObj = NULL;
- env->DeleteLocalRef(jLanguage); jLanguage = NULL;
}
- return list;
+ }
+
+ private:
+ static ScopedLocalRef<jobject> convertLabelsToMap(
+ JNIEnv *env, const fields_t& fields, const std::map<std::string, std::string> &labels) {
+ ScopedLocalRef<jobject> nullMap(env, nullptr);
+ ScopedLocalRef<jobject> hashMap(env, env->NewObject(
+ fields.hashMapClazz, fields.hashMapConstructID));
+ if (hashMap == nullptr) {
+ return nullMap;
+ }
+
+ for (const auto& label : labels) {
+ ScopedLocalRef<jstring> jLanguage(env, env->NewStringUTF(label.first.c_str()));
+ if (jLanguage == nullptr) return nullMap;
+ ScopedLocalRef<jobject> jLocale(env, env->NewObject(
+ fields.ulocaleClazz,
+ fields.ulocaleConstructID,
+ jLanguage.get()));
+ if (jLocale == nullptr) return nullMap;
+ ScopedLocalRef<jobject> jValue(env, env->NewStringUTF(label.second.c_str()));
+ if (jValue == nullptr) return nullMap;
+ env->CallObjectMethod(hashMap.get(), fields.hashMapPutID, jLocale.get(), jValue.get());
+ }
+ return hashMap;
}
};
} // namespace android
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 15957c6..29238d3 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "MediaExtractor-JNI"
#include <utils/Log.h>
+#include "android_media_AudioPresentation.h"
#include "android_media_MediaDataSource.h"
#include "android_media_MediaExtractor.h"
#include "android_media_MediaMetricsJNI.h"
@@ -56,6 +57,7 @@
};
static fields_t gFields;
+static JAudioPresentationInfo::fields_t gAudioPresentationFields;
JMediaExtractor::JMediaExtractor(JNIEnv *env, jobject thiz)
: mClass(NULL),
@@ -289,6 +291,10 @@
return mImpl->getCachedDuration(durationUs, eos);
}
+status_t JMediaExtractor::getAudioPresentations(size_t trackIdx,
+ AudioPresentationCollection *presentations) const {
+ return mImpl->getAudioPresentations(trackIdx, presentations);
+}
} // namespace android
////////////////////////////////////////////////////////////////////////////////
@@ -668,6 +674,28 @@
return JNI_TRUE;
}
+static jobject android_media_MediaExtractor_getAudioPresentations(
+ JNIEnv *env, jobject thiz, jint trackIdx) {
+ sp<JMediaExtractor> extractor = getMediaExtractor(env, thiz);
+ jobject presentationsJObj = JAudioPresentationInfo::asJobject(env, gAudioPresentationFields);
+ if (extractor == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return presentationsJObj;
+ }
+ AudioPresentationCollection presentations;
+ status_t err = extractor->getAudioPresentations(trackIdx, &presentations);
+ if (err == ERROR_END_OF_STREAM || err == ERROR_UNSUPPORTED) {
+ return presentationsJObj;
+ } else if (err != OK) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return presentationsJObj;
+ }
+
+ JAudioPresentationInfo::addPresentations(
+ env, gAudioPresentationFields, presentations, presentationsJObj);
+ return presentationsJObj;
+}
+
static void android_media_MediaExtractor_native_init(JNIEnv *env) {
jclass clazz = env->FindClass("android/media/MediaExtractor");
CHECK(clazz != NULL);
@@ -683,6 +711,8 @@
gFields.cryptoInfoSetPatternID =
env->GetMethodID(clazz, "setPattern", "(II)V");
+
+ gAudioPresentationFields.init(env);
}
static void android_media_MediaExtractor_native_setup(
@@ -963,6 +993,9 @@
{"native_getMetrics", "()Landroid/os/PersistableBundle;",
(void *)android_media_MediaExtractor_native_getMetrics},
+
+ { "native_getAudioPresentations", "(I)Ljava/util/List;",
+ (void *)android_media_MediaExtractor_getAudioPresentations },
};
int register_android_media_MediaExtractor(JNIEnv *env) {
diff --git a/media/jni/android_media_MediaExtractor.h b/media/jni/android_media_MediaExtractor.h
index aaa8421..baa779c 100644
--- a/media/jni/android_media_MediaExtractor.h
+++ b/media/jni/android_media_MediaExtractor.h
@@ -18,6 +18,7 @@
#define _ANDROID_MEDIA_MEDIAEXTRACTOR_H_
#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AudioPresentationInfo.h>
#include <media/MediaSource.h>
#include <media/DataSource.h>
#include <utils/Errors.h>
@@ -66,6 +67,8 @@
status_t getMetrics(Parcel *reply) const;
bool getCachedDuration(int64_t *durationUs, bool *eos) const;
+ status_t getAudioPresentations(size_t trackIdx,
+ AudioPresentationCollection *presentations) const;
protected:
virtual ~JMediaExtractor();
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 8f13497..f244f9f 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -45,6 +45,7 @@
"androidx.slice_slice-builders",
"androidx.arch.core_core-runtime",
"androidx.lifecycle_lifecycle-extensions",
+ "car-theme-lib-bp",
"SystemUI-tags",
"SystemUI-proto",
],
diff --git a/packages/CarSystemUI/res/layout/car_volume_dialog.xml b/packages/CarSystemUI/res/layout/car_volume_dialog.xml
index c98740e..709797d 100644
--- a/packages/CarSystemUI/res/layout/car_volume_dialog.xml
+++ b/packages/CarSystemUI/res/layout/car_volume_dialog.xml
@@ -20,11 +20,9 @@
android:id="@+id/volume_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@android:color/black"
android:minWidth="@dimen/volume_dialog_panel_width"
- android:theme="@style/Theme.Car.DialogListView"
- app:dividerEndMargin="@dimen/car_keyline_1"
- app:dividerStartMargin="@dimen/car_keyline_1"
+ android:theme="@style/PagedListViewTheme"
app:gutter="none"
app:scrollBarEnabled="false"
+ app:listDividerColor="@color/list_divider_color"
app:showPagedListViewDivider="true"/>
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index df8f8db..c510ab6 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -51,4 +51,6 @@
<color name="car_grey_900">#ff212121</color>
<color name="keyguard_button_text_color">@android:color/black</color>
+
+ <color name="list_divider_color">@*android:color/car_list_divider_light</color>
</resources>
diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml
index 7f4544a..0d95d30 100644
--- a/packages/CarSystemUI/res/values/styles.xml
+++ b/packages/CarSystemUI/res/values/styles.xml
@@ -41,15 +41,16 @@
<item name="android:colorControlHighlight">@color/nav_bar_ripple_background_color</item>
</style>
- <style name="Theme.Car.DialogListView" parent="@style/Theme.Car.NoActionBar">
- <item name="android:colorControlActivated">@color/car_accent</item>
- <item name="listItemBackgroundColor">@android:color/black</item>
- </style>
-
<style name="NavigationBarButton">
<item name="android:layout_height">96dp</item>
<item name="android:layout_width">96dp</item>
<item name="android:background">@drawable/nav_button_background</item>
</style>
-</resources>
+ <style name="PagedListViewTheme" parent="@style/Theme.CarSupportWrapper.NoActionBar">
+ <item name="android:background">@*android:color/car_background</item>
+ <item name="listItemBackgroundColor">@*android:color/car_background</item>
+ <item name="dividerEndMargin">@dimen/car_keyline_1</item>
+ <item name="dividerStartMargin">@dimen/car_keyline_1</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index 60153fc..0e4900a 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -355,6 +355,21 @@
}
@Override
+ public void onNotificationExpansionChanged(String key, boolean isUserAction,
+ boolean isExpanded) {
+ if (DEBUG) {
+ Log.i(TAG,
+ "onNotificationExpansionChanged " + key + ", isUserAction =" + isUserAction
+ + ", isExpanded = isExpanded");
+ }
+ }
+
+ @Override
+ public void onNotificationDirectReply(String key) {
+ if (DEBUG) Log.i(TAG, "onNotificationDirectReply " + key);
+ }
+
+ @Override
public void onListenerConnected() {
if (DEBUG) Log.i(TAG, "CONNECTED");
try {
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
index 56feb47..87d6e4a 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusedLocationProvider.java
@@ -16,27 +16,24 @@
package com.android.location.fused;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-import com.android.location.provider.LocationProviderBase;
-import com.android.location.provider.ProviderPropertiesUnbundled;
-import com.android.location.provider.ProviderRequestUnbundled;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.Criteria;
-import android.location.LocationProvider;
-import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
import android.os.WorkSource;
+import com.android.location.provider.LocationProviderBase;
+import com.android.location.provider.ProviderPropertiesUnbundled;
+import com.android.location.provider.ProviderRequestUnbundled;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
public class FusedLocationProvider extends LocationProviderBase implements FusionEngine.Callback {
private static final String TAG = "FusedLocationProvider";
@@ -48,7 +45,6 @@
private static final int MSG_DISABLE = 2;
private static final int MSG_SET_REQUEST = 3;
- private final Context mContext;
private final FusionEngine mEngine;
private static class RequestWrapper {
@@ -62,13 +58,12 @@
public FusedLocationProvider(Context context) {
super(TAG, PROPERTIES);
- mContext = context;
mEngine = new FusionEngine(context, Looper.myLooper());
// listen for user change
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
+ context.registerReceiverAsUser(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -122,14 +117,4 @@
// perform synchronously
mEngine.dump(fd, pw, args);
}
-
- @Override
- public int onGetStatus(Bundle extras) {
- return LocationProvider.AVAILABLE;
- }
-
- @Override
- public long onGetStatusUpdateTime() {
- return 0;
- }
}
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index d1f140f..444e724 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -16,6 +16,7 @@
"SettingsLibAppPreference",
"SettingsLibSearchWidget",
"SettingsLibSettingsSpinner",
+ "SettingsLayoutPreference",
],
// ANDROIDMK TRANSLATION ERROR: unsupported assignment to LOCAL_SHARED_JAVA_LIBRARIES
diff --git a/packages/SettingsLib/SettingsLayoutPreference/Android.bp b/packages/SettingsLib/SettingsLayoutPreference/Android.bp
new file mode 100644
index 0000000..489d360
--- /dev/null
+++ b/packages/SettingsLib/SettingsLayoutPreference/Android.bp
@@ -0,0 +1,13 @@
+android_library {
+ name: "SettingsLayoutPreference",
+
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+
+ static_libs: [
+ "androidx.preference_preference",
+ ],
+
+ sdk_version: "system_current",
+ min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/SettingsLayoutPreference/AndroidManifest.xml b/packages/SettingsLib/SettingsLayoutPreference/AndroidManifest.xml
new file mode 100644
index 0000000..4b9f1ab
--- /dev/null
+++ b/packages/SettingsLib/SettingsLayoutPreference/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.widget">
+
+ <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/SettingsLayoutPreference/res/layout/layout_preference_frame.xml b/packages/SettingsLib/SettingsLayoutPreference/res/layout/layout_preference_frame.xml
new file mode 100644
index 0000000..ee4ce49
--- /dev/null
+++ b/packages/SettingsLib/SettingsLayoutPreference/res/layout/layout_preference_frame.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
diff --git a/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml b/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml
new file mode 100644
index 0000000..0678263
--- /dev/null
+++ b/packages/SettingsLib/SettingsLayoutPreference/res/layout/settings_entity_header.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/entity_header"
+ style="@style/EntityHeader"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:id="@+id/entity_header_content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/entity_header_icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:scaleType="fitXY"
+ android:antialias="true"/>
+
+ <TextView
+ android:id="@+id/entity_header_title"
+ style="@style/TextAppearance.EntityHeaderTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="false"
+ android:ellipsize="marquee"
+ android:textDirection="locale"
+ android:layout_marginTop="8dp"/>
+
+ <TextView
+ android:id="@+id/install_type"
+ style="@style/TextAppearance.EntityHeaderSummary"
+ android:visibility="gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dp"/>
+
+ <TextView
+ android:id="@+id/entity_header_summary"
+ style="@style/TextAppearance.EntityHeaderSummary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dp"/>
+
+ <TextView
+ android:id="@+id/entity_header_second_summary"
+ style="@style/TextAppearance.EntityHeaderSummary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/entity_header_links"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_centerVertical="true"
+ android:layout_alignParentEnd="true"
+ android:orientation="vertical">
+
+ <ImageButton
+ android:id="@android:id/button1"
+ style="?android:attr/actionOverflowButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:layout_height="0dp"
+ android:minWidth="24dp"
+ android:src="@null"
+ android:tint="?android:attr/colorAccent"/>
+
+ <ImageButton
+ android:id="@android:id/button2"
+ style="?android:attr/actionOverflowButtonStyle"
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:layout_height="0dp"
+ android:minWidth="24dp"
+ android:src="@null"
+ android:tint="?android:attr/colorAccent"/>
+
+ </LinearLayout>
+
+</RelativeLayout>
diff --git a/packages/SettingsLib/SettingsLayoutPreference/res/values/styles.xml b/packages/SettingsLib/SettingsLayoutPreference/res/values/styles.xml
new file mode 100644
index 0000000..805744b
--- /dev/null
+++ b/packages/SettingsLib/SettingsLayoutPreference/res/values/styles.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources>
+ <style name="EntityHeader">
+ <item name="android:background">?android:attr/colorPrimaryDark</item>
+ <item name="android:paddingTop">24dp</item>
+ <item name="android:paddingBottom">16dp</item>
+ <item name="android:paddingEnd">16dp</item>
+ </style>
+
+ <style name="TextAppearance.EntityHeaderTitle"
+ parent="@android:style/TextAppearance.Material.Subhead">
+ <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
+ <item name="android:textColor">?android:attr/textColorPrimary</item>
+ <item name="android:textSize">20sp</item>
+ </style>
+
+ <style name="TextAppearance.EntityHeaderSummary"
+ parent="@android:style/TextAppearance.Material.Body1">
+ <item name="android:textAlignment">viewStart</item>
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:gravity">start</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:ellipsize">marquee</item>
+ <item name="android:textSize">14sp</item>
+ </style>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsLayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java b/packages/SettingsLib/SettingsLayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java
new file mode 100644
index 0000000..2a635b0
--- /dev/null
+++ b/packages/SettingsLib/SettingsLayoutPreference/src/com/android/settingslib/widget/LayoutPreference.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import androidx.core.content.res.TypedArrayUtils;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * A preference can be simply customized a view by adding layout attribute in xml.
+ * User also can decide whether or not LayoutPreference allows above divider or below divider.
+ *
+ * For instances,
+ *
+ * <com.android.settingslib.widget.LayoutPreference
+ * ...
+ * android:layout="@layout/settings_entity_header"
+ * xxxxxxx:allowDividerAbove="true"
+ * xxxxxxx:allowDividerBelow="true"
+ *
+ */
+public class LayoutPreference extends Preference {
+
+ private final View.OnClickListener mClickListener = v -> performClick(v);
+ private boolean mAllowDividerAbove;
+ private boolean mAllowDividerBelow;
+ private View mRootView;
+
+ /**
+ * Constructs a new LayoutPreference with the given context's theme and the supplied
+ * attribute set.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ */
+ public LayoutPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs, 0 /* defStyleAttr */);
+ }
+
+ /**
+ * Constructs a new LayoutPreference with the given context's theme, the supplied
+ * attribute set, and default style attribute.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ * @param defStyleAttr An attribute in the current theme that contains a
+ * reference to a style resource that supplies default
+ * values for the view. Can be 0 to not look for
+ * defaults.
+ */
+ public LayoutPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs, defStyleAttr);
+ }
+
+ /**
+ * Constructs a new LayoutPreference with the given context's theme and a customized view id.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param resource The view id which you expected to be inflated and show in preference.
+ */
+ public LayoutPreference(Context context, int resource) {
+ this(context, LayoutInflater.from(context).inflate(resource, null, false));
+ }
+
+ /**
+ * Constructs a new LayoutPreference with the given context's theme and a customized view.
+ *
+ * @param context The Context the view is running in, through which it can
+ * access the current theme, resources, etc.
+ * @param view The view which you expected show in preference.
+ */
+ public LayoutPreference(Context context, View view) {
+ super(context);
+ setView(view);
+ }
+
+ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Preference);
+ mAllowDividerAbove = TypedArrayUtils.getBoolean(a, R.styleable.Preference_allowDividerAbove,
+ R.styleable.Preference_allowDividerAbove, false);
+ mAllowDividerBelow = TypedArrayUtils.getBoolean(a, R.styleable.Preference_allowDividerBelow,
+ R.styleable.Preference_allowDividerBelow, false);
+ a.recycle();
+
+ a = context.obtainStyledAttributes(
+ attrs, R.styleable.Preference, defStyleAttr, 0);
+ int layoutResource = a.getResourceId(R.styleable.Preference_android_layout, 0);
+ if (layoutResource == 0) {
+ throw new IllegalArgumentException("LayoutPreference requires a layout to be defined");
+ }
+ a.recycle();
+
+ // Need to create view now so that findViewById can be called immediately.
+ final View view = LayoutInflater.from(getContext())
+ .inflate(layoutResource, null, false);
+ setView(view);
+ }
+
+ private void setView(View view) {
+ setLayoutResource(R.layout.layout_preference_frame);
+ mRootView = view;
+ setShouldDisableView(false);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ holder.itemView.setOnClickListener(mClickListener);
+
+ final boolean selectable = isSelectable();
+ holder.itemView.setFocusable(selectable);
+ holder.itemView.setClickable(selectable);
+ holder.setDividerAllowedAbove(mAllowDividerAbove);
+ holder.setDividerAllowedBelow(mAllowDividerBelow);
+
+ FrameLayout layout = (FrameLayout) holder.itemView;
+ layout.removeAllViews();
+ ViewGroup parent = (ViewGroup) mRootView.getParent();
+ if (parent != null) {
+ parent.removeView(mRootView);
+ }
+ layout.addView(mRootView);
+ }
+
+ /**
+ * Finds the view with the given ID.
+ *
+ * @param id the ID to search for
+ * @return a view with given ID if found, or {@code null} otherwise
+ */
+ public <T extends View> T findViewById(int id) {
+ return mRootView.findViewById(id);
+ }
+
+ /**
+ * LayoutPreference whether or not allows to set a below divider.
+ */
+ public void setAllowDividerBelow(boolean allowed) {
+ mAllowDividerBelow = allowed;
+ }
+
+ /**
+ * Return a value whether or not LayoutPreference allows to set a below divider.
+ */
+ public boolean isAllowDividerBelow() {
+ return mAllowDividerBelow;
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 86928fc..4f81daf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -154,8 +154,10 @@
static final String KEY_CARRIER_NAME = "key_carrier_name";
static final AtomicInteger sLastId = new AtomicInteger(0);
- /**
- * These values are matched in string arrays -- changes must be kept in sync
+ /*
+ * NOTE: These constants for security and PSK types are saved to the bundle in saveWifiState,
+ * and sent across IPC. The numeric values should remain stable, otherwise the changes will need
+ * to be synced with other unbundled users of this library.
*/
public static final int SECURITY_NONE = 0;
public static final int SECURITY_WEP = 1;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
index ede248b..8757eed 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/SettingsLibRobolectricTestRunner.java
@@ -55,6 +55,8 @@
paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/AppPreference/res"));
paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/HelpUtils/res"));
paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/RestrictedLockUtils/res"));
+ paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/"
+ + "SettingsLayoutPreference/res"));
paths.add(resourcePath("file:frameworks/base/packages/SettingsLib/res"));
paths.add(resourcePath("file:frameworks/base/core/res/res"));
paths.add(resourcePath("file:out/soong/.intermediates/prebuilts/sdk/current/androidx/androidx.appcompat_appcompat-nodeps/android_common/aar/res/"));
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/LayoutPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/LayoutPreferenceTest.java
new file mode 100644
index 0000000..427a611
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/LayoutPreferenceTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+
+import androidx.preference.Preference.OnPreferenceClickListener;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settingslib.SettingsLibRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(SettingsLibRobolectricTestRunner.class)
+public class LayoutPreferenceTest {
+
+ private LayoutPreference mPreference;
+ private PreferenceViewHolder mHolder;
+
+ @Before
+ public void setUp() {
+ final Context mContext = RuntimeEnvironment.application;
+ mPreference = new LayoutPreference(mContext, R.layout.settings_entity_header);
+ mHolder = PreferenceViewHolder.createInstanceForTests(LayoutInflater.from(mContext)
+ .inflate(R.layout.layout_preference_frame, null, false));
+ }
+
+ @Test
+ public void setOnPreferenceClickListener_layoutPreferenceShouldListenClickEvent() {
+ final OnPreferenceClickListener listener = mock(OnPreferenceClickListener.class);
+
+ mPreference.setOnPreferenceClickListener(listener);
+ mPreference.onBindViewHolder(mHolder);
+
+ mHolder.itemView.callOnClick();
+
+ verify(listener).onPreferenceClick(mPreference);
+ assertThat(mHolder.itemView.isFocusable()).isTrue();
+ assertThat(mHolder.itemView.isClickable()).isTrue();
+ }
+
+ @Test
+ public void setNonSelectable_viewShouldNotBeSelectable() {
+ mPreference.setSelectable(false);
+ mPreference.onBindViewHolder(mHolder);
+
+ assertThat(mHolder.itemView.isFocusable()).isFalse();
+ assertThat(mHolder.itemView.isClickable()).isFalse();
+ }
+
+ @Test
+ public void disableSomeView_shouldMaintainStateAfterBind() {
+ mPreference.findViewById(android.R.id.button1).setEnabled(false);
+ mPreference.findViewById(android.R.id.button2).setEnabled(true);
+
+ mPreference.onBindViewHolder(mHolder);
+
+ assertThat(mPreference.findViewById(android.R.id.button1).isEnabled()).isFalse();
+ assertThat(mPreference.findViewById(android.R.id.button2).isEnabled()).isTrue();
+ }
+
+ @Test
+ public void allowDividerBelow_shouldSaveCorrectDividerStatus() {
+ mPreference.setAllowDividerBelow(true);
+
+ assertThat(mPreference.isAllowDividerBelow()).isTrue();
+ }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 2227642..00ea45c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -186,6 +186,7 @@
Settings.NameValueTable.VALUE, null);
public static final String RESULT_ROWS_DELETED = "result_rows_deleted";
+ public static final String RESULT_SETTINGS_LIST = "result_settings_list";
// Overlay specified settings whitelisted for Instant Apps
private static final Set<String> OVERLAY_ALLOWED_GLOBAL_INSTANT_APP_SETTINGS = new ArraySet<>();
@@ -483,6 +484,27 @@
return result;
}
+ case Settings.CALL_METHOD_LIST_SYSTEM: {
+ Bundle result = new Bundle();
+ result.putStringArrayList(RESULT_SETTINGS_LIST,
+ buildSettingsList(getAllSystemSettings(requestingUserId, null)));
+ return result;
+ }
+
+ case Settings.CALL_METHOD_LIST_SECURE: {
+ Bundle result = new Bundle();
+ result.putStringArrayList(RESULT_SETTINGS_LIST,
+ buildSettingsList(getAllSecureSettings(requestingUserId, null)));
+ return result;
+ }
+
+ case Settings.CALL_METHOD_LIST_GLOBAL: {
+ Bundle result = new Bundle();
+ result.putStringArrayList(RESULT_SETTINGS_LIST,
+ buildSettingsList(getAllGlobalSettings(null)));
+ return result;
+ }
+
default: {
Slog.w(LOG_TAG, "call() with invalid method: " + method);
} break;
@@ -552,6 +574,20 @@
}
}
+ private ArrayList<String> buildSettingsList(Cursor cursor) {
+ final ArrayList<String> lines = new ArrayList<String>();
+ try {
+ while (cursor != null && cursor.moveToNext()) {
+ lines.add(cursor.getString(1) + "=" + cursor.getString(2));
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ return lines;
+ }
+
@Override
public Uri insert(Uri uri, ContentValues values) {
if (DEBUG) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
index f8445fd..13537c4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsService.java
@@ -19,8 +19,6 @@
import android.app.ActivityManager;
import android.content.IContentProvider;
import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Process;
@@ -265,9 +263,6 @@
}
if (mUser < 0) {
mUser = UserHandle.USER_SYSTEM;
- } else if (mVerb == CommandVerb.LIST) {
- perr.println("--user not supported for list.");
- return -1;
}
UserManager userManager = UserManager.get(mProvider.getContext());
if (userManager.getUserInfo(mUser) == null) {
@@ -304,27 +299,22 @@
return 0;
}
- private List<String> listForUser(IContentProvider provider, int userHandle, String table) {
- final Uri uri = "system".equals(table) ? Settings.System.CONTENT_URI
- : "secure".equals(table) ? Settings.Secure.CONTENT_URI
- : "global".equals(table) ? Settings.Global.CONTENT_URI
- : null;
- final ArrayList<String> lines = new ArrayList<String>();
- if (uri == null) {
- return lines;
+ List<String> listForUser(IContentProvider provider, int userHandle, String table) {
+ final String callListCommand;
+ if ("system".equals(table)) callListCommand = Settings.CALL_METHOD_LIST_SYSTEM;
+ else if ("secure".equals(table)) callListCommand = Settings.CALL_METHOD_LIST_SECURE;
+ else if ("global".equals(table)) callListCommand = Settings.CALL_METHOD_LIST_GLOBAL;
+ else {
+ getErrPrintWriter().println("Invalid table; no list performed");
+ throw new IllegalArgumentException("Invalid table " + table);
}
+ final ArrayList<String> lines = new ArrayList<String>();
try {
- final Cursor cursor = provider.query(resolveCallingPackage(), uri, null, null,
- null);
- try {
- while (cursor != null && cursor.moveToNext()) {
- lines.add(cursor.getString(1) + "=" + cursor.getString(2));
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
+ Bundle arg = new Bundle();
+ arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle);
+ Bundle result =
+ provider.call(resolveCallingPackage(), callListCommand, null, arg);
+ lines.addAll(result.getStringArrayList(SettingsProvider.RESULT_SETTINGS_LIST));
Collections.sort(lines);
} catch (RemoteException e) {
throw new RuntimeException("Failed in IPC", e);
@@ -483,7 +473,7 @@
pw.println(" reset [--user <USER_ID> | current] NAMESPACE {PACKAGE_NAME | RESET_MODE}");
pw.println(" Reset the global/secure table for a package with mode.");
pw.println(" RESET_MODE is one of {untrusted_defaults, untrusted_clear, trusted_defaults}, case-insensitive");
- pw.println(" list NAMESPACE");
+ pw.println(" list [--user <USER_ID> | current] NAMESPACE");
pw.println(" Print all defined keys.");
pw.println(" NAMESPACE is one of {system, secure, global}, case-insensitive");
}
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index c86ebe7..eb3f70a 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -51,7 +51,7 @@
android:layout_centerVertical="true"
android:layout_toEndOf="@id/pkgicon" />
<TextView
- android:id="@+id/pkg_group_divider"
+ android:id="@+id/pkg_divider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info"
@@ -61,7 +61,7 @@
android:layout_centerVertical="true"
android:layout_toEndOf="@id/pkgname" />
<TextView
- android:id="@+id/group_name"
+ android:id="@+id/delegate_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@*android:style/TextAppearance.Material.Notification.Info"
@@ -70,7 +70,7 @@
android:ellipsize="end"
android:maxLines="1"
android:layout_centerVertical="true"
- android:layout_toEndOf="@id/pkg_group_divider" />
+ android:layout_toEndOf="@id/pkg_divider" />
<!-- 24 dp icon with 16 dp padding all around to mirror notification content margins -->
<ImageButton
android:id="@+id/info"
@@ -101,13 +101,39 @@
android:layout_marginStart="@*android:dimen/notification_content_margin_start"
android:layout_marginEnd="@*android:dimen/notification_content_margin_start"
android:orientation="vertical">
- <!-- Channel Name -->
- <TextView
- android:id="@+id/channel_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- style="@android:style/TextAppearance.Material.Notification.Title" />
+ <RelativeLayout
+ android:id="@+id/names"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@+id/group_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
+ android:layout_marginStart="2dp"
+ android:layout_marginEnd="2dp"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:layout_centerVertical="true" />
+ <TextView
+ android:id="@+id/pkg_group_divider"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
+ android:layout_marginStart="2dp"
+ android:layout_marginEnd="2dp"
+ android:text="@*android:string/notification_header_divider_symbol"
+ android:layout_centerVertical="true"
+ android:layout_toEndOf="@id/group_name" />
+ <!-- Channel Name -->
+ <TextView
+ android:id="@+id/channel_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ style="@android:style/TextAppearance.Material.Notification.Title"
+ android:layout_toEndOf="@id/pkg_group_divider"/>
+ </RelativeLayout>
<!-- Question prompt -->
<TextView
android:id="@+id/block_prompt"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4a0bc9b..31dd46c 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1574,6 +1574,9 @@
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">These notifications can\'t be turned off</string>
+ <!-- Notification: Control panel: Label for the app that posted this notification, if it's not the package that the notification was posted for -->
+ <string name="notification_delegate_header">via <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
+
<!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] -->
<string name="appops_camera">This app is using the camera.</string>
<!-- Notification Inline controls: describes what the app is doing in the background [CHAR_LIMIT=NONE] -->
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index 3191d14..42e60aa 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -17,6 +17,9 @@
package com.android.systemui.shared.system;
import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
import android.app.WindowConfiguration;
import android.graphics.Rect;
@@ -26,10 +29,6 @@
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
-
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -179,6 +178,7 @@
*/
public int getNavBarPosition() {
try {
+ // TODO: Use WindowManagerService.getNavBarPosition(int displayId)
return WindowManagerGlobal.getWindowManagerService().getNavBarPosition();
} catch (RemoteException e) {
Log.w(TAG, "Failed to get nav bar position");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 0818513..450d34d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -108,13 +108,13 @@
VisualStabilityManager.Callback, BubbleController.BubbleDismissListener {
private static final String TAG = "NotificationEntryMgr";
protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- protected static final boolean ENABLE_HEADS_UP = true;
- protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
+ private static final boolean ENABLE_HEADS_UP = true;
+ private static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
- protected final NotificationMessagingUtil mMessagingUtil;
+ private final NotificationMessagingUtil mMessagingUtil;
protected final Context mContext;
protected final HashMap<String, NotificationData.Entry> mPendingNotifications = new HashMap<>();
- protected final NotificationClicker mNotificationClicker = new NotificationClicker();
+ private final NotificationClicker mNotificationClicker = new NotificationClicker();
private final NotificationGroupManager mGroupManager =
Dependency.get(NotificationGroupManager.class);
@@ -145,14 +145,15 @@
private NotificationPresenter mPresenter;
private Callback mCallback;
protected PowerManager mPowerManager;
- protected NotificationListenerService.RankingMap mLatestRankingMap;
+ private NotificationListenerService.RankingMap mLatestRankingMap;
protected HeadsUpManager mHeadsUpManager;
protected NotificationData mNotificationData;
- protected ContentObserver mHeadsUpObserver;
+ private ContentObserver mHeadsUpObserver;
protected boolean mUseHeadsUp = false;
- protected boolean mDisableNotificationAlerts;
+ private boolean mDisableNotificationAlerts;
protected NotificationListContainer mListContainer;
- protected final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
+ @VisibleForTesting
+ final ArrayList<NotificationLifetimeExtender> mNotificationLifetimeExtenders
= new ArrayList<>();
private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
private NotificationViewHierarchyManager.StatusBarStateListener mStatusBarStateListener;
@@ -485,22 +486,6 @@
updateNotifications();
}
- /**
- * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
- * about the failure.
- *
- * WARNING: this will call back into us. Don't hold any locks.
- */
- void handleNotificationError(StatusBarNotification n, String message) {
- removeNotificationInternal(n.getKey(), null, true /* forceRemove */);
- try {
- mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
- n.getInitialPid(), message, n.getUserId());
- } catch (RemoteException ex) {
- // The end is nigh.
- }
- }
-
private void abortExistingInflation(String key) {
if (mPendingNotifications.containsKey(key)) {
NotificationData.Entry entry = mPendingNotifications.get(key);
@@ -513,13 +498,31 @@
}
}
+ /**
+ * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
+ * about the failure.
+ *
+ * WARNING: this will call back into us. Don't hold any locks.
+ */
@Override
- public void handleInflationException(StatusBarNotification notification, Exception e) {
- handleNotificationError(notification, e.getMessage());
+ public void handleInflationException(StatusBarNotification n, Exception e) {
+ removeNotificationInternal(n.getKey(), null, true /* forceRemove */);
+ try {
+ mBarService.onNotificationError(n.getPackageName(), n.getTag(), n.getId(), n.getUid(),
+ n.getInitialPid(), e.getMessage(), n.getUserId());
+ } catch (RemoteException ex) {
+ // The end is nigh.
+ }
}
private void addEntry(NotificationData.Entry shadeEntry) {
- addNotificationViews(shadeEntry);
+ if (shadeEntry == null) {
+ return;
+ }
+ // Add the expanded view and icon.
+ mNotificationData.add(shadeEntry);
+ tagForeground(shadeEntry.notification);
+ updateNotifications();
mCallback.onNotificationAdded(shadeEntry);
}
@@ -755,17 +758,7 @@
row.inflateViews();
}
- protected void addNotificationViews(NotificationData.Entry entry) {
- if (entry == null) {
- return;
- }
- // Add the expanded view and icon.
- mNotificationData.add(entry);
- tagForeground(entry.notification);
- updateNotifications();
- }
-
- protected NotificationData.Entry createNotificationViews(
+ private NotificationData.Entry createNotificationViews(
StatusBarNotification sbn, NotificationListenerService.Ranking ranking)
throws InflationException {
if (DEBUG) {
@@ -841,7 +834,7 @@
}
@VisibleForTesting
- protected void tagForeground(StatusBarNotification notification) {
+ void tagForeground(StatusBarNotification notification) {
ArraySet<Integer> activeOps = mForegroundServiceController.getAppOps(
notification.getUserId(), notification.getPackageName());
if (activeOps != null) {
@@ -1098,7 +1091,7 @@
* @param entry the entry to check
* @return true if the entry should ambient pulse, false otherwise
*/
- protected boolean shouldPulse(NotificationData.Entry entry) {
+ private boolean shouldPulse(NotificationData.Entry entry) {
StatusBarNotification sbn = entry.notification;
if (!getShadeController().isDozing()) {
@@ -1173,7 +1166,7 @@
return true;
}
- protected void setNotificationShown(StatusBarNotification n) {
+ private void setNotificationShown(StatusBarNotification n) {
setNotificationsShown(new String[]{n.getKey()});
}
@@ -1185,7 +1178,7 @@
}
}
- protected boolean isSnoozedPackage(StatusBarNotification sbn) {
+ private boolean isSnoozedPackage(StatusBarNotification sbn) {
return mHeadsUpManager.isSnoozed(sbn.getPackageName());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index b6d99b2..daec9c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -3145,8 +3145,10 @@
pw.print(", alpha: " + getAlpha());
pw.print(", translation: " + getTranslation());
pw.print(", removed: " + isRemoved());
- pw.print(", privateShowing: " + (getShowingLayout() == mPrivateLayout));
+ NotificationContentView showingLayout = getShowingLayout();
+ pw.print(", privateShowing: " + (showingLayout == mPrivateLayout));
pw.println();
+ showingLayout.dump(fd, pw, args);
pw.print(" ");
if (mNotificationViewState != null) {
mNotificationViewState.dump(fd, pw, args);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index bb9a341..88edc0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -55,6 +55,9 @@
import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.SmartReplyView;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collections;
import java.util.List;
/**
@@ -1322,6 +1325,10 @@
List<Notification.Action> appGeneratedSmartActions = notification.getContextualActions();
boolean appGeneratedSmartActionsExist = !appGeneratedSmartActions.isEmpty();
+ List<Notification.Action> sysGeneratedSmartActions =
+ notification.getAllowSystemGeneratedContextualActions()
+ ? entry.systemGeneratedSmartActions : Collections.emptyList();
+
if (appGeneratedSmartRepliesExist) {
return new SmartRepliesAndActions(remoteInputActionPair.first,
remoteInputActionPair.second.actionIntent,
@@ -1338,11 +1345,11 @@
return new SmartRepliesAndActions(freeformRemoteInputActionPair.first,
freeformRemoteInputActionPair.second.actionIntent,
entry.smartReplies,
- entry.systemGeneratedSmartActions,
+ sysGeneratedSmartActions,
freeformRemoteInputActionPair);
}
// App didn't generate anything, and there are no NAS-generated smart replies.
- return new SmartRepliesAndActions(null, null, null, entry.systemGeneratedSmartActions,
+ return new SmartRepliesAndActions(null, null, null, sysGeneratedSmartActions,
freeformRemoteInputActionPair);
}
@@ -1928,4 +1935,23 @@
mExpandedWrapper.setHeaderVisibleAmount(headerVisibleAmount);
}
}
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.print(" ");
+ pw.print("contentView visibility: " + getVisibility());
+ pw.print(", alpha: " + getAlpha());
+ pw.print(", clipBounds: " + getClipBounds());
+ pw.print(", contentHeight: " + mContentHeight);
+ pw.print(", visibleType: " + mVisibleType);
+ View view = getViewForVisibleType(mVisibleType);
+ pw.print(", visibleView ");
+ if (view != null) {
+ pw.print(" visibility: " + view.getVisibility());
+ pw.print(", alpha: " + view.getAlpha());
+ pw.print(", clipBounds: " + view.getClipBounds());
+ } else {
+ pw.print("null");
+ }
+ pw.println();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 3a7091b..0d36d2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -92,6 +92,7 @@
private String mPackageName;
private String mAppName;
private int mAppUid;
+ private String mDelegatePkg;
private int mNumUniqueChannelsInRow;
private NotificationChannel mSingleNotificationChannel;
private int mStartingChannelImportance;
@@ -235,6 +236,7 @@
(mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
mIsForBlockingHelper = isForBlockingHelper;
mAppUid = mSbn.getUid();
+ mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
mIsNoisy = isNoisy;
@@ -281,26 +283,8 @@
((ImageView) findViewById(R.id.pkgicon)).setImageDrawable(pkgicon);
((TextView) findViewById(R.id.pkgname)).setText(mAppName);
- // Set group information if this channel has an associated group.
- CharSequence groupName = null;
- if (mSingleNotificationChannel != null && mSingleNotificationChannel.getGroup() != null) {
- final NotificationChannelGroup notificationChannelGroup =
- mINotificationManager.getNotificationChannelGroupForPackage(
- mSingleNotificationChannel.getGroup(), mPackageName, mAppUid);
- if (notificationChannelGroup != null) {
- groupName = notificationChannelGroup.getName();
- }
- }
- TextView groupNameView = findViewById(R.id.group_name);
- TextView groupDividerView = findViewById(R.id.pkg_group_divider);
- if (groupName != null) {
- groupNameView.setText(groupName);
- groupNameView.setVisibility(View.VISIBLE);
- groupDividerView.setVisibility(View.VISIBLE);
- } else {
- groupNameView.setVisibility(View.GONE);
- groupDividerView.setVisibility(View.GONE);
- }
+ // Delegate
+ bindDelegate();
// Settings button.
final View settingsButton = findViewById(R.id.info);
@@ -320,9 +304,10 @@
}
}
- private void bindPrompt() {
+ private void bindPrompt() throws RemoteException {
final TextView blockPrompt = findViewById(R.id.block_prompt);
bindName();
+ bindGroup();
if (mIsNonblockable) {
blockPrompt.setText(R.string.notification_unblockable_desc);
} else {
@@ -345,6 +330,60 @@
}
}
+ private void bindDelegate() {
+ TextView delegateView = findViewById(R.id.delegate_name);
+ TextView dividerView = findViewById(R.id.pkg_divider);
+
+ CharSequence delegatePkg = null;
+ if (!TextUtils.equals(mPackageName, mDelegatePkg)) {
+ // this notification was posted by a delegate!
+ ApplicationInfo info;
+ try {
+ info = mPm.getApplicationInfo(
+ mDelegatePkg,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.MATCH_DISABLED_COMPONENTS
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
+ | PackageManager.MATCH_DIRECT_BOOT_AWARE);
+ if (info != null) {
+ delegatePkg = String.valueOf(mPm.getApplicationLabel(info));
+ }
+ } catch (PackageManager.NameNotFoundException e) { }
+ }
+ if (delegatePkg != null) {
+ delegateView.setText(mContext.getResources().getString(
+ R.string.notification_delegate_header, delegatePkg));
+ delegateView.setVisibility(View.VISIBLE);
+ dividerView.setVisibility(View.VISIBLE);
+ } else {
+ delegateView.setVisibility(View.GONE);
+ dividerView.setVisibility(View.GONE);
+ }
+ }
+
+ private void bindGroup() throws RemoteException {
+ // Set group information if this channel has an associated group.
+ CharSequence groupName = null;
+ if (mSingleNotificationChannel != null && mSingleNotificationChannel.getGroup() != null) {
+ final NotificationChannelGroup notificationChannelGroup =
+ mINotificationManager.getNotificationChannelGroupForPackage(
+ mSingleNotificationChannel.getGroup(), mPackageName, mAppUid);
+ if (notificationChannelGroup != null) {
+ groupName = notificationChannelGroup.getName();
+ }
+ }
+ TextView groupNameView = findViewById(R.id.group_name);
+ TextView groupDividerView = findViewById(R.id.pkg_group_divider);
+ if (groupName != null) {
+ groupNameView.setText(groupName);
+ groupNameView.setVisibility(View.VISIBLE);
+ groupDividerView.setVisibility(View.VISIBLE);
+ } else {
+ groupNameView.setVisibility(View.GONE);
+ groupDividerView.setVisibility(View.GONE);
+ }
+ }
+
@VisibleForTesting
void logBlockingHelperCounter(String counterTag) {
if (mIsForBlockingHelper) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index c0d1818..7d13679 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -227,6 +227,7 @@
mShowingSoon = false;
if (mExpansion == EXPANSION_VISIBLE) {
mKeyguardView.onResume();
+ mKeyguardView.resetSecurityContainer();
}
StatsLog.write(StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED,
StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 0cf1b3d..8657003 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -56,7 +56,6 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
-import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -863,16 +862,9 @@
public static View create(Context context, FragmentListener listener) {
final int displayId = context.getDisplay().getDisplayId();
- final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
- final int height = isDefaultDisplay
- ? LayoutParams.MATCH_PARENT
- : context.getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- LayoutParams.MATCH_PARENT, height,
- // TODO(b/117478341): Resolve one status bar/ navigation bar assumption
- isDefaultDisplay
- ? WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
- : WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -884,10 +876,6 @@
lp.setTitle("NavigationBar" + displayId);
lp.accessibilityTitle = context.getString(R.string.nav_bar);
lp.windowAnimations = 0;
- if (!isDefaultDisplay) {
- lp.flags |= LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
- lp.gravity = Gravity.BOTTOM;
- }
View navigationBarView = LayoutInflater.from(context).inflate(
R.layout.navigation_bar_window, null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 2f58ca1..5db43ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -904,6 +904,7 @@
boolean isRtl = (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL);
int navBarPos = 0;
try {
+ // TODO: Use WindowManagerService.getNavBarPosition(int displayId)
navBarPos = WindowManagerGlobal.getWindowManagerService().getNavBarPosition();
} catch (RemoteException e) {
Slog.e(TAG, "Failed to get nav bar position.", e);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 45e924f..bdddf5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2251,7 +2251,8 @@
private void notifyUiVisibilityChanged(int vis) {
try {
if (mLastDispatchedSystemUiVisibility != vis) {
- mWindowManagerService.statusBarVisibilityChanged(vis);
+ // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
+ mWindowManagerService.statusBarVisibilityChanged(Display.DEFAULT_DISPLAY, vis);
mLastDispatchedSystemUiVisibility = vis;
}
} catch (RemoteException ex) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index a6725b8..5e137a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -106,7 +106,8 @@
mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- // Smart replies
+ // Smart replies and actions
+ when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(true);
when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
mEntry = new NotificationData.Entry(mStatusBarNotification);
when(mSmartReplyConstants.isEnabled()).thenReturn(true);
@@ -299,6 +300,23 @@
assertThat(repliesAndActions.smartActions, equalTo(appGenSmartActions));
}
+ @Test
+ public void chooseSmartRepliesAndActions_disallowSysGenSmartActions() {
+ // Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
+ // actions.
+ setupAppGeneratedReplies(null);
+
+ when(mNotification.getAllowSystemGeneratedContextualActions()).thenReturn(false);
+
+ mEntry.systemGeneratedSmartActions =
+ createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
+ NotificationContentView.SmartRepliesAndActions repliesAndActions =
+ NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+
+ assertThat(repliesAndActions.smartReplies, equalTo(null));
+ assertThat(repliesAndActions.smartActions, is(empty()));
+ }
+
private Notification.Action.Builder createActionBuilder(String actionTitle) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
new Intent(TEST_ACTION), 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 1cc1c63..985827a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -134,7 +134,7 @@
.thenReturn(packageInfo);
final ApplicationInfo applicationInfo = new ApplicationInfo();
applicationInfo.uid = TEST_UID; // non-zero
- when(mMockPackageManager.getApplicationInfo(anyString(), anyInt())).thenReturn(
+ when(mMockPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME), anyInt())).thenReturn(
applicationInfo);
final PackageInfo systemPackageInfo = new PackageInfo();
systemPackageInfo.packageName = TEST_SYSTEM_PACKAGE_NAME;
@@ -206,6 +206,37 @@
}
@Test
+ public void testBindNotification_noDelegate() throws Exception {
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE);
+ final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
+ assertEquals(GONE, nameView.getVisibility());
+ final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider);
+ assertEquals(GONE, dividerView.getVisibility());
+ }
+
+ @Test
+ public void testBindNotification_delegate() throws Exception {
+ mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, "other", 0, null, TEST_UID, 0,
+ new Notification(), UserHandle.CURRENT, null, 0);
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = 7; // non-zero
+ when(mMockPackageManager.getApplicationInfo(eq("other"), anyInt())).thenReturn(
+ applicationInfo);
+ when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Other");
+
+ mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ false, IMPORTANCE_DEFAULT, NotificationInfo.ACTION_NONE);
+ final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
+ assertEquals(VISIBLE, nameView.getVisibility());
+ assertTrue(nameView.getText().toString().contains("Other"));
+ final TextView dividerView = mNotificationInfo.findViewById(R.id.pkg_divider);
+ assertEquals(VISIBLE, dividerView.getVisibility());
+ }
+
+ @Test
public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 17d8ea7..c56f31e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -18,11 +18,13 @@
import static android.Manifest.permission.MANAGE_AUTO_FILL;
import static android.content.Context.AUTOFILL_MANAGER_SERVICE;
+import static android.util.DebugUtils.flagsToString;
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sFullScreenMode;
import static com.android.server.autofill.Helper.sVerbose;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -72,9 +74,12 @@
import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.autofill.ui.AutoFillUI;
+import com.android.server.intelligence.IntelligenceManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -95,6 +100,27 @@
private static final Object sLock = AutofillManagerService.class;
+
+ /**
+ * IME supports Smart Suggestions.
+ */
+ // NOTE: must be public because of flagsToString()
+ public static final int FLAG_SMART_SUGGESTION_IME = 0x1;
+
+ /**
+ * System supports Smarts Suggestions (as a popup-window similar to standard Autofill).
+ */
+ // NOTE: must be public because of flagsToString()
+ public static final int FLAG_SMART_SUGGESTION_SYSTEM = 0x2;
+
+ /** @hide */
+ @IntDef(flag = true, prefix = { "FLAG_SMART_SUGGESTION_" }, value = {
+ FLAG_SMART_SUGGESTION_IME,
+ FLAG_SMART_SUGGESTION_SYSTEM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface SmartSuggestionMode {}
+
static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
private static final char COMPAT_PACKAGE_DELIMITER = ':';
@@ -102,7 +128,6 @@
private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_BEGIN = '[';
private static final char COMPAT_PACKAGE_URL_IDS_BLOCK_END = ']';
-
/**
* Maximum number of partitions that can be allowed in a session.
*
@@ -130,6 +155,7 @@
private final AutofillCompatState mAutofillCompatState = new AutofillCompatState();
private final LocalService mLocalService = new LocalService();
+ final IntelligenceManagerInternal mIntelligenceManagerInternal;
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -153,13 +179,21 @@
@GuardedBy("mLock")
private boolean mAllowInstantService;
+ /**
+ * Supported modes for Augmented Autofill Smart Suggestions.
+ */
+ @GuardedBy("mLock")
+ private int mSupportedSmartSuggestionModes;
+
public AutofillManagerService(Context context) {
super(context, UserManager.DISALLOW_AUTOFILL);
mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext());
+ mIntelligenceManagerInternal = LocalServices.getService(IntelligenceManagerInternal.class);
setLogLevelFromSettings();
setMaxPartitionsFromSettings();
setMaxVisibleDatasetsFromSettings();
+ setSmartSuggestionEmulationFromSettings();
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -186,6 +220,9 @@
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS), false, observer,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.Global.getUriFor(
+ Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS), false, observer,
+ UserHandle.USER_ALL);
}
@Override // from AbstractMasterSystemService
@@ -200,6 +237,9 @@
case Settings.Global.AUTOFILL_MAX_VISIBLE_DATASETS:
setMaxVisibleDatasetsFromSettings();
break;
+ case Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS:
+ setSmartSuggestionEmulationFromSettings();
+ break;
default:
Slog.w(TAG, "Unexpected property (" + property + "); updating cache instead");
// fall through
@@ -243,6 +283,10 @@
mUi.hideAll(null);
}
+ @SmartSuggestionMode int getSupportedSmartSuggestionModesLocked() {
+ return mSupportedSmartSuggestionModes;
+ }
+
// Called by Shell command.
void destroySessions(@UserIdInt int userId, IResultReceiver receiver) {
Slog.i(TAG, "destroySessions() for userId " + userId);
@@ -420,6 +464,19 @@
}
}
+ private void setSmartSuggestionEmulationFromSettings() {
+ final int flags = Settings.Global.getInt(getContext().getContentResolver(),
+ Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS, 0);
+ if (sDebug) {
+ Slog.d(TAG, "setSmartSuggestionEmulationFromSettings(): "
+ + smartSuggestionFlagsToString(flags));
+ }
+
+ synchronized (mLock) {
+ mSupportedSmartSuggestionModes = flags;
+ }
+ }
+
// Called by Shell command.
void getScore(@Nullable String algorithmName, @NonNull String value1,
@NonNull String value2, @NonNull RemoteCallback callback) {
@@ -610,6 +667,10 @@
}
}
+ static String smartSuggestionFlagsToString(int flags) {
+ return flagsToString(AutofillManagerService.class, "FLAG_SMART_SUGGESTION_", flags);
+ }
+
private final class LocalService extends AutofillManagerInternal {
@Override
public void onBackKeyPressed() {
@@ -1158,6 +1219,10 @@
pw.print("from settings: ");
pw.println(getWhitelistedCompatModePackagesFromSettings());
pw.print("Allow instant service: "); pw.println(mAllowInstantService);
+ if (mSupportedSmartSuggestionModes != 0) {
+ pw.print("Smart Suggestion modes: ");
+ pw.println(smartSuggestionFlagsToString(mSupportedSmartSuggestionModes));
+ }
if (showHistory) {
pw.println(); pw.println("Requests history:"); pw.println();
mRequestsHistory.reverseDump(fd, pw, args);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 67ccc9b..0df99d4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -73,6 +73,7 @@
import com.android.server.AbstractPerUserSystemService;
import com.android.server.LocalServices;
import com.android.server.autofill.AutofillManagerService.AutofillCompatState;
+import com.android.server.autofill.AutofillManagerService.SmartSuggestionMode;
import com.android.server.autofill.ui.AutoFillUI;
import java.io.PrintWriter;
@@ -268,8 +269,8 @@
pruneAbandonedSessionsLocked();
final Session newSession = createSessionByTokenLocked(activityToken, taskId, uid,
- appCallbackToken, hasCallback, componentName, compatMode, bindInstantServiceAllowed,
- flags);
+ appCallbackToken, hasCallback, componentName, compatMode,
+ bindInstantServiceAllowed, flags);
if (newSession == null) {
return NO_SESSION;
}
@@ -823,6 +824,12 @@
return true;
}
+ @GuardedBy("mLock")
+ @SmartSuggestionMode int getSupportedSmartSuggestionModesLocked() {
+ // TODO(b/111330312): once we support IME, we need to set it per-user (OR'ed with master)
+ return mMaster.getSupportedSmartSuggestionModesLocked();
+ }
+
@Override
@GuardedBy("mLock")
protected void dumpLocked(String prefix, PrintWriter pw) {
@@ -962,6 +969,9 @@
if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id);
session.forceRemoveSelfLocked();
}
+ else {
+ session.destroyAugmentedAutofillWindowsLocked();
+ }
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 1ff1acd..8676f7f 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -25,6 +25,9 @@
import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import static com.android.server.autofill.AutofillManagerService.FLAG_SMART_SUGGESTION_IME;
+import static com.android.server.autofill.AutofillManagerService.FLAG_SMART_SUGGESTION_SYSTEM;
+import static com.android.server.autofill.AutofillManagerService.smartSuggestionFlagsToString;
import static com.android.server.autofill.Helper.getNumericValue;
import static com.android.server.autofill.Helper.sDebug;
import static com.android.server.autofill.Helper.sVerbose;
@@ -93,8 +96,11 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import com.android.server.AbstractRemoteService;
+import com.android.server.autofill.AutofillManagerService.SmartSuggestionMode;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.autofill.ui.PendingUi;
+import com.android.server.intelligence.IntelligenceManagerInternal;
+import com.android.server.intelligence.IntelligenceManagerInternal.AugmentedAutofillCallback;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -242,6 +248,10 @@
@GuardedBy("mLock")
private final SparseArray<LogMaker> mRequestLogs = new SparseArray<>(1);
+ @GuardedBy("mLock")
+ @Nullable
+ private AugmentedAutofillCallback mAugmentedAutofillCallback;
+
/**
* Receiver of assist data from the app's {@link Activity}.
*/
@@ -2497,15 +2507,83 @@
processResponseLocked(newResponse, newClientState, 0);
}
+ @GuardedBy("mLock")
private void processNullResponseLocked(int flags) {
- if (sVerbose) Slog.v(TAG, "canceling session " + id + " when server returned null");
if ((flags & FLAG_MANUAL_REQUEST) != 0) {
getUiForShowing().showError(R.string.autofill_error_cannot_autofill, this);
}
mService.resetLastResponse();
- // Nothing to be done, but need to notify client.
- notifyUnavailableToClient(AutofillManager.STATE_FINISHED);
- removeSelf();
+
+ // The default autofill service cannot fullfill the request, let's check if the intelligence
+ // service can.
+ mAugmentedAutofillCallback = triggerAugmentedAutofillLocked();
+ if (mAugmentedAutofillCallback == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "canceling session " + id + " when server returned null and there is no"
+ + " AugmentedAutofill for user");
+ }
+ // Nothing to be done, but need to notify client.
+ notifyUnavailableToClient(AutofillManager.STATE_FINISHED);
+ removeSelf();
+ } else {
+ // TODO(b/111330312, b/119638958): must set internal state so when user focus other
+ // fields it does not generate a new call to the standard autofill service (right now
+ // it does). Must also add CTS tests to exercise this scenario.
+ if (sVerbose) {
+ Slog.v(TAG, "keeping session " + id + " when server returned null but "
+ + "there is an AugmentedAutofill for user");
+ }
+ }
+ }
+
+ /**
+ * Tries to trigger Augmented Autofill when the standard service could not fulfill a request.
+ *
+ * @return callback to the Augmented Autofill service, or {@code null} if not supported.
+ */
+ // TODO(b/111330312): might need to call it in other places, like when the service returns a
+ // non-null response but without datasets (for example, just SaveInfo)
+ @GuardedBy("mLock")
+ private AugmentedAutofillCallback triggerAugmentedAutofillLocked() {
+ // Check if Smart Suggestions is supported...
+ final @SmartSuggestionMode int supportedModes = mService
+ .getSupportedSmartSuggestionModesLocked();
+ if (supportedModes == 0) return null;
+
+ // ...then if the service is set for the user
+ final IntelligenceManagerInternal intelligenceManagerInternal = mService
+ .getMaster().mIntelligenceManagerInternal;
+ if (intelligenceManagerInternal == null) return null;
+
+ // Define which mode will be used
+ final int mode;
+ if ((supportedModes & FLAG_SMART_SUGGESTION_IME) != 0) {
+ // TODO(b/111330312): support it :-)
+ Slog.w(TAG, "Smart Suggestions on IME not supported yet");
+ return null;
+ } else if ((supportedModes & FLAG_SMART_SUGGESTION_SYSTEM) != 0) {
+ mode = FLAG_SMART_SUGGESTION_SYSTEM;
+ } else {
+ Slog.w(TAG, "Unsupported Smart Suggestion Mode: " + supportedModes);
+ return null;
+ }
+
+ if (mCurrentViewId == null) {
+ Slog.w(TAG, "triggerAugmentedAutofillLocked(): no view currently focused");
+ return null;
+ }
+
+ if (sVerbose) {
+ Slog.v(TAG, "calling IntelligenseService on view " + mCurrentViewId
+ + " using suggestion mode " + smartSuggestionFlagsToString(mode)
+ + " when server returned null for session " + this.id);
+ }
+
+ // TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize
+ // furgher AFM -> AFMS calls.
+ // TODO(b/119638958): add CTS tests
+ return intelligenceManagerInternal.requestAutofill(mService.getUserId(), mClient,
+ mActivityToken, this.id, mCurrentViewId);
}
@GuardedBy("mLock")
@@ -2786,6 +2864,9 @@
pw.print(prefix); pw.print("mSaveOnAllViewsInvisible: "); pw.println(
mSaveOnAllViewsInvisible);
pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds);
+ if (mAugmentedAutofillCallback != null) {
+ pw.print(prefix); pw.println("has AugmentedAutofillCallback");
+ }
mRemoteFillService.dump(prefix, pw);
}
@@ -2957,6 +3038,14 @@
Slog.e(TAG, "Error notifying client to finish session", e);
}
}
+ destroyAugmentedAutofillWindowsLocked();
+ }
+
+ @GuardedBy("mLock")
+ void destroyAugmentedAutofillWindowsLocked() {
+ if (mAugmentedAutofillCallback != null) {
+ mAugmentedAutofillCallback.destroy();
+ }
}
/**
diff --git a/services/core/java/com/android/server/AbstractPerUserSystemService.java b/services/core/java/com/android/server/AbstractPerUserSystemService.java
index b37888f..71d261c 100644
--- a/services/core/java/com/android/server/AbstractPerUserSystemService.java
+++ b/services/core/java/com/android/server/AbstractPerUserSystemService.java
@@ -163,6 +163,20 @@
}
/**
+ * Gets the user associated with this service.
+ */
+ public final @UserIdInt int getUserId() {
+ return mUserId;
+ }
+
+ /**
+ * Gets the master service.
+ */
+ public final M getMaster() {
+ return mMaster;
+ }
+
+ /**
* Gets this UID of the remote service this service binds to, or {@code -1} if the service is
* disabled.
*/
diff --git a/services/core/java/com/android/server/AbstractRemoteService.java b/services/core/java/com/android/server/AbstractRemoteService.java
index 181d7fd..73a34d6 100644
--- a/services/core/java/com/android/server/AbstractRemoteService.java
+++ b/services/core/java/com/android/server/AbstractRemoteService.java
@@ -205,6 +205,9 @@
protected void scheduleUnbind() {
cancelScheduledUnbind();
+ // TODO(b/111276913): implement "permanent binding"
+ // TODO(b/117779333): make sure it's unbound if the service settings changing (right now
+ // it's not)
mHandler.sendMessageDelayed(obtainMessage(AbstractRemoteService::handleUnbind, this)
.setWhat(MSG_UNBIND), getTimeoutIdleBindMillis());
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 74c8023..564d35a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -894,10 +894,18 @@
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(
- mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
+ mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM,
new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);
+ // Listen to package add and removal events for all users.
+ intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addDataScheme("package");
+ mContext.registerReceiverAsUser(
+ mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
+
try {
mNMS.registerObserver(mTethering);
mNMS.registerObserver(mDataActivityObserver);
@@ -4155,6 +4163,7 @@
}
private void onUserAdded(int userId) {
+ mPermissionMonitor.onUserAdded(userId);
synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
@@ -4165,6 +4174,7 @@
}
private void onUserRemoved(int userId) {
+ mPermissionMonitor.onUserRemoved(userId);
synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
@@ -4174,6 +4184,22 @@
}
}
+ private void onPackageAdded(String packageName, int uid) {
+ if (TextUtils.isEmpty(packageName) || uid < 0) {
+ Slog.wtf(TAG, "Invalid package in onPackageAdded: " + packageName + " | " + uid);
+ return;
+ }
+ mPermissionMonitor.onPackageAdded(packageName, uid);
+ }
+
+ private void onPackageRemoved(String packageName, int uid) {
+ if (TextUtils.isEmpty(packageName) || uid < 0) {
+ Slog.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
+ return;
+ }
+ mPermissionMonitor.onPackageRemoved(uid);
+ }
+
private void onUserUnlocked(int userId) {
synchronized (mVpns) {
// User present may be sent because of an unlock, which might mean an unlocked keystore.
@@ -4185,11 +4211,15 @@
}
}
- private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
+ private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final Uri packageData = intent.getData();
+ final String packageName =
+ packageData != null ? packageData.getSchemeSpecificPart() : null;
if (userId == UserHandle.USER_NULL) return;
if (Intent.ACTION_USER_STARTED.equals(action)) {
@@ -4202,6 +4232,10 @@
onUserRemoved(userId);
} else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
onUserUnlocked(userId);
+ } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+ onPackageAdded(packageName, uid);
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ onPackageRemoved(packageName, uid);
}
}
};
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 8c25917..7ee3d3b 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -24,6 +24,7 @@
import static android.system.OsConstants.EINVAL;
import static android.system.OsConstants.IPPROTO_UDP;
import static android.system.OsConstants.SOCK_DGRAM;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.NonNull;
@@ -62,6 +63,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
+import libcore.io.IoUtils;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
@@ -73,8 +76,6 @@
import java.util.ArrayList;
import java.util.List;
-import libcore.io.IoUtils;
-
/**
* A service to manage multiple clients that want to access the IpSec API. The service is
* responsible for maintaining a list of clients and managing the resources (and related quotas)
@@ -621,7 +622,8 @@
mConfig.getDestinationAddress(),
spi,
mConfig.getMarkValue(),
- mConfig.getMarkMask());
+ mConfig.getMarkMask(),
+ mConfig.getXfrmInterfaceId());
} catch (RemoteException | ServiceSpecificException e) {
Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e);
}
@@ -683,7 +685,8 @@
mSrvConfig
.getNetdInstance()
.ipSecDeleteSecurityAssociation(
- uid, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
+ uid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */,
+ 0 /* mask */, 0 /* if_id */);
}
} catch (ServiceSpecificException | RemoteException e) {
Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e);
@@ -795,6 +798,8 @@
private final int mIkey;
private final int mOkey;
+ private final int mIfId;
+
TunnelInterfaceRecord(
int resourceId,
String interfaceName,
@@ -802,7 +807,8 @@
String localAddr,
String remoteAddr,
int ikey,
- int okey) {
+ int okey,
+ int intfId) {
super(resourceId);
mInterfaceName = interfaceName;
@@ -811,6 +817,7 @@
mRemoteAddress = remoteAddr;
mIkey = ikey;
mOkey = okey;
+ mIfId = intfId;
}
/** always guarded by IpSecService#this */
@@ -821,7 +828,7 @@
// Delete global policies
try {
final INetd netd = mSrvConfig.getNetdInstance();
- netd.removeVirtualTunnelInterface(mInterfaceName);
+ netd.ipSecRemoveTunnelInterface(mInterfaceName);
for (int selAddrFamily : ADDRESS_FAMILIES) {
netd.ipSecDeleteSecurityPolicy(
@@ -829,13 +836,15 @@
selAddrFamily,
IpSecManager.DIRECTION_OUT,
mOkey,
- 0xffffffff);
+ 0xffffffff,
+ mIfId);
netd.ipSecDeleteSecurityPolicy(
uid,
selAddrFamily,
IpSecManager.DIRECTION_IN,
mIkey,
- 0xffffffff);
+ 0xffffffff,
+ mIfId);
}
} catch (ServiceSpecificException | RemoteException e) {
Log.e(
@@ -877,6 +886,10 @@
return mOkey;
}
+ public int getIfId() {
+ return mIfId;
+ }
+
@Override
protected ResourceTracker getResourceTracker() {
return getUserRecord().mTunnelQuotaTracker;
@@ -1286,7 +1299,7 @@
// Add inbound/outbound global policies
// (use reqid = 0)
final INetd netd = mSrvConfig.getNetdInstance();
- netd.addVirtualTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey);
+ netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId);
for (int selAddrFamily : ADDRESS_FAMILIES) {
// Always send down correct local/remote addresses for template.
@@ -1298,7 +1311,8 @@
remoteAddr,
0,
okey,
- 0xffffffff);
+ 0xffffffff,
+ resourceId);
netd.ipSecAddSecurityPolicy(
callerUid,
selAddrFamily,
@@ -1307,7 +1321,8 @@
localAddr,
0,
ikey,
- 0xffffffff);
+ 0xffffffff,
+ resourceId);
}
userRecord.mTunnelInterfaceRecords.put(
@@ -1320,7 +1335,8 @@
localAddr,
remoteAddr,
ikey,
- okey),
+ okey,
+ resourceId),
binder));
return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
} catch (RemoteException e) {
@@ -1523,6 +1539,9 @@
throw new IllegalArgumentException(
"Invalid IpSecTransform.mode: " + config.getMode());
}
+
+ config.setMarkValue(0);
+ config.setMarkMask(0);
}
private static final String TUNNEL_OP = AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS;
@@ -1584,7 +1603,8 @@
(authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0,
encapType,
encapLocalPort,
- encapRemotePort);
+ encapRemotePort,
+ c.getXfrmInterfaceId());
}
/**
@@ -1740,27 +1760,48 @@
: tunnelInterfaceInfo.getIkey();
try {
- c.setMarkValue(mark);
- c.setMarkMask(0xffffffff);
+ // Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip
+ // SPI matching as part of the template resolution.
+ int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
+ c.setXfrmInterfaceId(tunnelInterfaceInfo.getIfId());
+
+ // TODO: enable this when UPDSA supports updating marks. Adding kernel support upstream
+ // (and backporting) would allow us to narrow the mark space, and ensure that the SA
+ // and SPs have matching marks (as VTI are meant to be built).
+ // Currently update does nothing with marks. Leave empty (defaulting to 0) to ensure the
+ // config matches the actual allocated resources in the kernel.
+ // All SAs will have zero marks (from creation time), and any policy that matches the
+ // same src/dst could match these SAs. Non-IpSecService governed processes that
+ // establish floating policies with the same src/dst may result in undefined
+ // behavior. This is generally limited to vendor code due to the permissions
+ // (CAP_NET_ADMIN) required.
+ //
+ // c.setMarkValue(mark);
+ // c.setMarkMask(0xffffffff);
if (direction == IpSecManager.DIRECTION_OUT) {
// Set output mark via underlying network (output only)
c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork());
- // If outbound, also add SPI to the policy.
- for (int selAddrFamily : ADDRESS_FAMILIES) {
- mSrvConfig
- .getNetdInstance()
- .ipSecUpdateSecurityPolicy(
- callingUid,
- selAddrFamily,
- direction,
- tunnelInterfaceInfo.getLocalAddress(),
- tunnelInterfaceInfo.getRemoteAddress(),
- transformInfo.getSpiRecord().getSpi(),
- mark,
- 0xffffffff);
- }
+ // Set outbound SPI only. We want inbound to use any valid SA (old, new) on rekeys,
+ // but want to guarantee outbound packets are sent over the new SA.
+ spi = transformInfo.getSpiRecord().getSpi();
+ }
+
+ // Always update the policy with the relevant XFRM_IF_ID
+ for (int selAddrFamily : ADDRESS_FAMILIES) {
+ mSrvConfig
+ .getNetdInstance()
+ .ipSecUpdateSecurityPolicy(
+ callingUid,
+ selAddrFamily,
+ direction,
+ transformInfo.getConfig().getSourceAddress(),
+ transformInfo.getConfig().getDestinationAddress(),
+ spi, // If outbound, also add SPI to the policy.
+ mark, // Must always set policy mark; ikey/okey for VTIs
+ 0xffffffff,
+ c.getXfrmInterfaceId());
}
// Update SA with tunnel mark (ikey or okey based on direction)
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 046442a..e5275e5 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -17,6 +17,7 @@
package com.android.server;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS;
import android.Manifest;
import android.annotation.NonNull;
@@ -2990,7 +2991,7 @@
ArrayList<Receiver> deadReceivers = null;
ArrayList<UpdateRecord> deadUpdateRecords = null;
- // Broadcast location or status to all listeners
+ // Broadcast location to all listeners
for (UpdateRecord r : records) {
Receiver receiver = r.mReceiver;
boolean receiverDead = false;
@@ -3049,14 +3050,19 @@
}
}
- long prevStatusUpdateTime = r.mLastStatusBroadcast;
- if ((newStatusUpdateTime > prevStatusUpdateTime) &&
- (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
+ // TODO: location provider status callbacks have been disabled and deprecated, and are
+ // guarded behind this setting now. should be removed completely post-Q
+ if (Settings.Global.getInt(mContext.getContentResolver(),
+ LOCATION_DISABLE_STATUS_CALLBACKS, 1) == 0) {
+ long prevStatusUpdateTime = r.mLastStatusBroadcast;
+ if ((newStatusUpdateTime > prevStatusUpdateTime)
+ && (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
- r.mLastStatusBroadcast = newStatusUpdateTime;
- if (!receiver.callStatusChangedLocked(provider, status, extras)) {
- receiverDead = true;
- Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
+ r.mLastStatusBroadcast = newStatusUpdateTime;
+ if (!receiver.callStatusChangedLocked(provider, status, extras)) {
+ receiverDead = true;
+ Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
+ }
}
}
@@ -3276,7 +3282,6 @@
// we don't leave anything dangling.
clearTestProviderEnabled(provider, opPackageName);
clearTestProviderLocation(provider, opPackageName);
- clearTestProviderStatus(provider, opPackageName);
MockProvider mockProvider = mMockProviders.remove(provider);
if (mockProvider == null) {
@@ -3409,21 +3414,6 @@
}
@Override
- public void clearTestProviderStatus(String provider, String opPackageName) {
- if (!canCallerAccessMockLocation(opPackageName)) {
- return;
- }
-
- synchronized (mLock) {
- MockProvider mockProvider = mMockProviders.get(provider);
- if (mockProvider == null) {
- throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
- }
- mockProvider.clearStatus();
- }
- }
-
- @Override
public PendingIntent createManageLocationPermissionIntent(String packageName,
String permission) {
Preconditions.checkNotNull(packageName);
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index 2dee3a0..c563ad2 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -141,6 +141,7 @@
if (mEnabled != enabled) {
mEnabled = enabled;
mStats.reset();
+ mStats.setAddDebugEntries(enabled);
Looper.setObserver(enabled ? mStats : null);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7e9e83c..5f9e349 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -497,6 +497,18 @@
private static final int MINIMUM_MEMORY_GROWTH_THRESHOLD = 10 * 1000; // 10 MB
/**
+ * The number of binder proxies we need to have before we start warning and
+ * dumping debug info.
+ */
+ private static final int BINDER_PROXY_HIGH_WATERMARK = 6000;
+
+ /**
+ * Low watermark that needs to be met before we consider dumping info again,
+ * after already hitting the high watermark.
+ */
+ private static final int BINDER_PROXY_LOW_WATERMARK = 5500;
+
+ /**
* State indicating that there is no need for any blocking for network.
*/
@VisibleForTesting
@@ -8477,7 +8489,8 @@
mAtmInternal.resumeTopActivities(false /* scheduleIdle */);
mUserController.sendUserSwitchBroadcasts(-1, currentUserId);
- BinderInternal.nSetBinderProxyCountWatermarks(6000,5500);
+ BinderInternal.nSetBinderProxyCountWatermarks(BINDER_PROXY_HIGH_WATERMARK,
+ BINDER_PROXY_LOW_WATERMARK);
BinderInternal.nSetBinderProxyCountEnabled(true);
BinderInternal.setBinderProxyCountCallback(
new BinderInternal.BinderProxyLimitListener() {
@@ -9217,11 +9230,6 @@
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
- dumpBinderProxies(pw);
- pw.println();
- if (dumpAll) {
- pw.println("-------------------------------------------------------------------------------");
- }
dumpLmkLocked(pw);
}
pw.println();
@@ -9235,6 +9243,19 @@
}
dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
}
+ if (dumpPackage == null) {
+ // Intentionally dropping the lock for this, because dumpBinderProxies() will make many
+ // outgoing binder calls to retrieve interface descriptors; while that is system code,
+ // there is nothing preventing an app from overriding this implementation by talking to
+ // the binder driver directly, and hang up system_server in the process. So, dump
+ // without locks held, and even then only when there is an unreasonably large number of
+ // proxies in the first place.
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ dumpBinderProxies(pw, BINDER_PROXY_HIGH_WATERMARK /* minToDump */);
+ }
}
/**
@@ -9373,7 +9394,7 @@
cmd, fd, pw, args, opti, true /* dumpAll */, dumpClient, dumpPackage);
} else if ("binder-proxies".equals(cmd)) {
if (opti >= args.length) {
- dumpBinderProxies(pw);
+ dumpBinderProxies(pw, 0 /* minToDump */);
} else {
String uid = args[opti];
opti++;
@@ -9714,10 +9735,17 @@
return false;
}
- void dumpBinderProxies(PrintWriter pw) {
+ void dumpBinderProxies(PrintWriter pw, int minCountToDumpInterfaces) {
pw.println("ACTIVITY MANAGER BINDER PROXY STATE (dumpsys activity binder-proxies)");
- dumpBinderProxyInterfaceCounts(pw,
- " Top proxy interface names held by SYSTEM");
+ final int proxyCount = BinderProxy.getProxyCount();
+ if (proxyCount >= minCountToDumpInterfaces) {
+ dumpBinderProxyInterfaceCounts(pw,
+ "Top proxy interface names held by SYSTEM");
+ } else {
+ pw.print("Not dumping proxy interface counts because size ("
+ + Integer.toString(proxyCount) + ") looks reasonable");
+ pw.println();
+ }
dumpBinderProxiesCounts(pw,
" Counts of Binder Proxies held by SYSTEM");
}
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index 4fe7d03..09df7e20 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -222,11 +222,11 @@
receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i);
receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, numActivities);
boolean result = requestAutofillData
- ? ActivityTaskManager.getService().requestAssistContextExtras(
+ ? ActivityTaskManager.getService().requestAutofillData(this,
+ receiverExtras, topActivity, 0 /* flags */)
+ : ActivityTaskManager.getService().requestAssistContextExtras(
ASSIST_CONTEXT_FULL, this, receiverExtras, topActivity,
- /* focused= */ i == 0, /* newSessionId= */ i == 0)
- : ActivityTaskManager.getService().requestAutofillData(this,
- receiverExtras, topActivity, 0 /* flags */);
+ /* focused= */ i == 0, /* newSessionId= */ i == 0);
if (result) {
mPendingDataCount++;
} else if (i == 0) {
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 94c94a5..420b23e 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -27,10 +27,7 @@
import static android.os.Process.SYSTEM_UID;
import android.annotation.NonNull;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -42,7 +39,6 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -64,15 +60,14 @@
public class PermissionMonitor {
private static final String TAG = "PermissionMonitor";
private static final boolean DBG = true;
- private static final Boolean SYSTEM = Boolean.TRUE;
- private static final Boolean NETWORK = Boolean.FALSE;
+ protected static final Boolean SYSTEM = Boolean.TRUE;
+ protected static final Boolean NETWORK = Boolean.FALSE;
private static final int VERSION_Q = Build.VERSION_CODES.Q;
private final Context mContext;
private final PackageManager mPackageManager;
private final UserManager mUserManager;
private final INetworkManagementService mNetd;
- private final BroadcastReceiver mIntentReceiver;
// Values are User IDs.
private final Set<Integer> mUsers = new HashSet<>();
@@ -85,26 +80,6 @@
mPackageManager = context.getPackageManager();
mUserManager = UserManager.get(context);
mNetd = netd;
- mIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- int appUid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID);
- Uri appData = intent.getData();
- String appName = appData != null ? appData.getSchemeSpecificPart() : null;
-
- if (Intent.ACTION_USER_ADDED.equals(action)) {
- onUserAdded(user);
- } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
- onUserRemoved(user);
- } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
- onAppAdded(appName, appUid);
- } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- onAppRemoved(appUid);
- }
- }
- };
}
// Intended to be called only once at startup, after the system is ready. Installs a broadcast
@@ -112,17 +87,6 @@
public synchronized void startMonitoring() {
log("Monitoring");
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_ADDED);
- intentFilter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
-
- intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
- intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- intentFilter.addDataScheme("package");
- mContext.registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, intentFilter, null, null);
-
List<PackageInfo> apps = mPackageManager.getInstalledPackages(GET_PERMISSIONS);
if (apps == null) {
loge("No apps");
@@ -260,7 +224,14 @@
}
}
- private synchronized void onUserAdded(int user) {
+ /**
+ * Called when a user is added. See {link #ACTION_USER_ADDED}.
+ *
+ * @param user The integer userHandle of the added user. See {@link #EXTRA_USER_HANDLE}.
+ *
+ * @hide
+ */
+ public synchronized void onUserAdded(int user) {
if (user < 0) {
loge("Invalid user in onUserAdded: " + user);
return;
@@ -272,7 +243,14 @@
update(users, mApps, true);
}
- private synchronized void onUserRemoved(int user) {
+ /**
+ * Called when an user is removed. See {link #ACTION_USER_REMOVED}.
+ *
+ * @param user The integer userHandle of the removed user. See {@link #EXTRA_USER_HANDLE}.
+ *
+ * @hide
+ */
+ public synchronized void onUserRemoved(int user) {
if (user < 0) {
loge("Invalid user in onUserRemoved: " + user);
return;
@@ -284,8 +262,8 @@
update(users, mApps, false);
}
-
- private Boolean highestPermissionForUid(Boolean currentPermission, String name) {
+ @VisibleForTesting
+ protected Boolean highestPermissionForUid(Boolean currentPermission, String name) {
if (currentPermission == SYSTEM) {
return currentPermission;
}
@@ -303,33 +281,39 @@
return currentPermission;
}
- private synchronized void onAppAdded(String appName, int appUid) {
- if (TextUtils.isEmpty(appName) || appUid < 0) {
- loge("Invalid app in onAppAdded: " + appName + " | " + appUid);
- return;
- }
-
+ /**
+ * Called when a package is added. See {link #ACTION_PACKAGE_ADDED}.
+ *
+ * @param packageName The name of the new package.
+ * @param uid The uid of the new package.
+ *
+ * @hide
+ */
+ public synchronized void onPackageAdded(String packageName, int uid) {
// If multiple packages share a UID (cf: android:sharedUserId) and ask for different
// permissions, don't downgrade (i.e., if it's already SYSTEM, leave it as is).
- final Boolean permission = highestPermissionForUid(mApps.get(appUid), appName);
- if (permission != mApps.get(appUid)) {
- mApps.put(appUid, permission);
+ final Boolean permission = highestPermissionForUid(mApps.get(uid), packageName);
+ if (permission != mApps.get(uid)) {
+ mApps.put(uid, permission);
Map<Integer, Boolean> apps = new HashMap<>();
- apps.put(appUid, permission);
+ apps.put(uid, permission);
update(mUsers, apps, true);
}
}
- private synchronized void onAppRemoved(int appUid) {
- if (appUid < 0) {
- loge("Invalid app in onAppRemoved: " + appUid);
- return;
- }
+ /**
+ * Called when a package is removed. See {link #ACTION_PACKAGE_REMOVED}.
+ *
+ * @param uid containing the integer uid previously assigned to the package.
+ *
+ * @hide
+ */
+ public synchronized void onPackageRemoved(int uid) {
Map<Integer, Boolean> apps = new HashMap<>();
Boolean permission = null;
- String[] packages = mPackageManager.getPackagesForUid(appUid);
+ String[] packages = mPackageManager.getPackagesForUid(uid);
if (packages != null && packages.length > 0) {
for (String name : packages) {
permission = highestPermissionForUid(permission, name);
@@ -341,16 +325,16 @@
}
}
}
- if (permission == mApps.get(appUid)) {
+ if (permission == mApps.get(uid)) {
// The permissions of this UID have not changed. Nothing to do.
return;
} else if (permission != null) {
- mApps.put(appUid, permission);
- apps.put(appUid, permission);
+ mApps.put(uid, permission);
+ apps.put(uid, permission);
update(mUsers, apps, true);
} else {
- mApps.remove(appUid);
- apps.put(appUid, NETWORK); // doesn't matter which permission we pick here
+ mApps.remove(uid);
+ apps.put(uid, NETWORK); // doesn't matter which permission we pick here
update(mUsers, apps, false);
}
}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index a8f7259..3c14393 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -23,24 +23,18 @@
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
-import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER;
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
-import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
-import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE;
-import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
-import static android.net.ConnectivityManager.EXTRA_SET_ALARM;
-import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
-import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
import static android.net.ConnectivityManager.TETHERING_INVALID;
import static android.net.ConnectivityManager.TETHERING_USB;
import static android.net.ConnectivityManager.TETHERING_WIFI;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
@@ -50,6 +44,7 @@
import static android.net.wifi.WifiManager.IFACE_IP_MODE_UNSPECIFIED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+
import static com.android.server.ConnectivityService.SHORT_ARG;
import android.app.Notification;
@@ -60,7 +55,6 @@
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProfile.ServiceListener;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -68,7 +62,6 @@
import android.hardware.usb.UsbManager;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
-import android.net.ip.IpServer;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -76,7 +69,7 @@
import android.net.NetworkInfo;
import android.net.NetworkState;
import android.net.NetworkUtils;
-import android.net.RouteInfo;
+import android.net.ip.IpServer;
import android.net.util.InterfaceSet;
import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
@@ -89,15 +82,12 @@
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
-import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
-import android.provider.Settings;
-import android.telephony.CarrierConfigManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -113,6 +103,7 @@
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.server.LocalServices;
+import com.android.server.connectivity.tethering.EntitlementManager;
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
import com.android.server.connectivity.tethering.OffloadController;
import com.android.server.connectivity.tethering.TetheringConfiguration;
@@ -123,8 +114,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
@@ -145,18 +134,12 @@
private final static boolean DBG = false;
private final static boolean VDBG = false;
- protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
-
private static final Class[] messageClasses = {
Tethering.class, TetherMasterSM.class, IpServer.class
};
private static final SparseArray<String> sMagicDecoderRing =
MessageUtils.findMessageNames(messageClasses);
- // {@link ComponentName} of the Service used to run tether provisioning.
- private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources
- .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
-
private static class TetherState {
public final IpServer ipServer;
public int lastState;
@@ -191,7 +174,6 @@
private final INetworkStatsService mStatsService;
private final INetworkPolicyManager mPolicyManager;
private final Looper mLooper;
- private final MockableSystemProperties mSystemProperties;
private final StateMachine mTetherMasterSM;
private final OffloadController mOffloadController;
private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
@@ -200,6 +182,7 @@
private final HashSet<IpServer> mForwardedDownstreams;
private final VersionedBroadcastListener mCarrierConfigChange;
private final TetheringDependencies mDeps;
+ private final EntitlementManager mEntitlementMgr;
private volatile TetheringConfiguration mConfig;
private InterfaceSet mCurrentUpstreamIfaceSet;
@@ -220,7 +203,6 @@
mStatsService = statsService;
mPolicyManager = policyManager;
mLooper = looper;
- mSystemProperties = systemProperties;
mDeps = deps;
mPublicSync = new Object();
@@ -241,12 +223,13 @@
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
+ mEntitlementMgr = mDeps.getEntitlementManager(mContext, mLog, systemProperties);
mCarrierConfigChange = new VersionedBroadcastListener(
"CarrierConfigChangeListener", mContext, smHandler, filter,
(Intent ignored) -> {
mLog.log("OBSERVED carrier config change");
updateConfiguration();
- reevaluateSimCardProvisioning();
+ mEntitlementMgr.reevaluateSimCardProvisioning();
});
mStateReceiver = new StateReceiver();
@@ -289,6 +272,7 @@
private void updateConfiguration() {
mConfig = new TetheringConfiguration(mContext, mLog);
mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
+ mEntitlementMgr.updateConfiguration(mConfig);
}
private void maybeUpdateConfiguration() {
@@ -354,83 +338,54 @@
}
public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
- if (!isTetherProvisioningRequired()) {
+ mEntitlementMgr.startTethering(type);
+ if (!mEntitlementMgr.isTetherProvisioningRequired()) {
enableTetheringInternal(type, true, receiver);
return;
}
+ final ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
if (showProvisioningUi) {
- runUiTetherProvisioningAndEnable(type, receiver);
+ mEntitlementMgr.runUiTetherProvisioningAndEnable(type, proxyReceiver);
} else {
- runSilentTetherProvisioningAndEnable(type, receiver);
+ mEntitlementMgr.runSilentTetherProvisioningAndEnable(type, proxyReceiver);
}
}
public void stopTethering(int type) {
enableTetheringInternal(type, false, null);
- if (isTetherProvisioningRequired()) {
- cancelTetherProvisioningRechecks(type);
+ mEntitlementMgr.stopTethering(type);
+ if (mEntitlementMgr.isTetherProvisioningRequired()) {
+ // There are lurking bugs where the notion of "provisioning required" or
+ // "tethering supported" may change without notifying tethering properly, then
+ // tethering can't shutdown correctly.
+ // TODO: cancel re-check all the time
+ if (mDeps.isTetheringSupported()) {
+ mEntitlementMgr.cancelTetherProvisioningRechecks(type);
+ }
}
}
/**
- * Check if the device requires a provisioning check in order to enable tethering.
- *
- * @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
- */
- @VisibleForTesting
- protected boolean isTetherProvisioningRequired() {
- final TetheringConfiguration cfg = mConfig;
- if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
- || cfg.provisioningApp.length == 0) {
- return false;
- }
- if (carrierConfigAffirmsEntitlementCheckNotRequired()) {
- return false;
- }
- return (cfg.provisioningApp.length == 2);
- }
-
- // The logic here is aimed solely at confirming that a CarrierConfig exists
- // and affirms that entitlement checks are not required.
- //
- // TODO: find a better way to express this, or alter the checking process
- // entirely so that this is more intuitive.
- private boolean carrierConfigAffirmsEntitlementCheckNotRequired() {
- // Check carrier config for entitlement checks
- final CarrierConfigManager configManager = (CarrierConfigManager) mContext
- .getSystemService(Context.CARRIER_CONFIG_SERVICE);
- if (configManager == null) return false;
-
- final PersistableBundle carrierConfig = configManager.getConfig();
- if (carrierConfig == null) return false;
-
- // A CarrierConfigManager was found and it has a config.
- final boolean isEntitlementCheckRequired = carrierConfig.getBoolean(
- CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
- return !isEntitlementCheckRequired;
- }
-
- /**
* Enables or disables tethering for the given type. This should only be called once
* provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
* for the specified interface.
*/
private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
- boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
+ boolean isProvisioningRequired = enable && mEntitlementMgr.isTetherProvisioningRequired();
int result;
switch (type) {
case TETHERING_WIFI:
result = setWifiTethering(enable);
if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
- scheduleProvisioningRechecks(type);
+ mEntitlementMgr.scheduleProvisioningRechecks(type);
}
sendTetherResult(receiver, result);
break;
case TETHERING_USB:
result = setUsbTethering(enable);
if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
- scheduleProvisioningRechecks(type);
+ mEntitlementMgr.scheduleProvisioningRechecks(type);
}
sendTetherResult(receiver, result);
break;
@@ -489,32 +444,14 @@
? TETHER_ERROR_NO_ERROR
: TETHER_ERROR_MASTER_ERROR;
sendTetherResult(receiver, result);
- if (enable && isTetherProvisioningRequired()) {
- scheduleProvisioningRechecks(TETHERING_BLUETOOTH);
+ if (enable && mEntitlementMgr.isTetherProvisioningRequired()) {
+ mEntitlementMgr.scheduleProvisioningRechecks(TETHERING_BLUETOOTH);
}
adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
}
}, BluetoothProfile.PAN);
}
- private void runUiTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
- ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
- sendUiTetherProvisionIntent(type, proxyReceiver);
- }
-
- private void sendUiTetherProvisionIntent(int type, ResultReceiver receiver) {
- Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
- intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
- intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- final long ident = Binder.clearCallingIdentity();
- try {
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
/**
* Creates a proxy {@link ResultReceiver} which enables tethering if the provisioning result
* is successful before firing back up to the wrapped receiver.
@@ -546,62 +483,6 @@
return receiverForSending;
}
- private void scheduleProvisioningRechecks(int type) {
- Intent intent = new Intent();
- intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
- intent.putExtra(EXTRA_SET_ALARM, true);
- intent.setComponent(TETHER_SERVICE);
- final long ident = Binder.clearCallingIdentity();
- try {
- mContext.startServiceAsUser(intent, UserHandle.CURRENT);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- private void runSilentTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
- ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
- sendSilentTetherProvisionIntent(type, proxyReceiver);
- }
-
- private void sendSilentTetherProvisionIntent(int type, ResultReceiver receiver) {
- Intent intent = new Intent();
- intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
- intent.putExtra(EXTRA_RUN_PROVISION, true);
- intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
- intent.setComponent(TETHER_SERVICE);
- final long ident = Binder.clearCallingIdentity();
- try {
- mContext.startServiceAsUser(intent, UserHandle.CURRENT);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- private void cancelTetherProvisioningRechecks(int type) {
- if (mDeps.isTetheringSupported()) {
- Intent intent = new Intent();
- intent.putExtra(EXTRA_REM_TETHER_TYPE, type);
- intent.setComponent(TETHER_SERVICE);
- final long ident = Binder.clearCallingIdentity();
- try {
- mContext.startServiceAsUser(intent, UserHandle.CURRENT);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
- }
-
- // Used by the SIM card change observation code.
- // TODO: De-duplicate with above code, where possible.
- private void startProvisionIntent(int tetherType) {
- final Intent startProvIntent = new Intent();
- startProvIntent.putExtra(EXTRA_ADD_TETHER_TYPE, tetherType);
- startProvIntent.putExtra(EXTRA_RUN_PROVISION, true);
- startProvIntent.setComponent(TETHER_SERVICE);
- mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
- }
-
public int tether(String iface) {
return tether(iface, IpServer.STATE_TETHERED);
}
@@ -1166,30 +1047,6 @@
return false;
}
- private void reevaluateSimCardProvisioning() {
- if (!mConfig.hasMobileHotspotProvisionApp()) return;
- if (carrierConfigAffirmsEntitlementCheckNotRequired()) return;
-
- ArrayList<Integer> tethered = new ArrayList<>();
- synchronized (mPublicSync) {
- for (int i = 0; i < mTetherStates.size(); i++) {
- TetherState tetherState = mTetherStates.valueAt(i);
- if (tetherState.lastState != IpServer.STATE_TETHERED) {
- continue; // Skip interfaces that aren't tethered.
- }
- String iface = mTetherStates.keyAt(i);
- int interfaceType = ifaceNameToType(iface);
- if (interfaceType != TETHERING_INVALID) {
- tethered.add(interfaceType);
- }
- }
- }
-
- for (int tetherType : tethered) {
- startProvisionIntent(tetherType);
- }
- }
-
class TetherMasterSM extends StateMachine {
private static final int BASE_MASTER = Protocol.BASE_TETHERING;
// an interface SM has requested Tethering/Local Hotspot
diff --git a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
new file mode 100644
index 0000000..a4e3e1d
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
+import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
+import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE;
+import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
+import static android.net.ConnectivityManager.EXTRA_SET_ALARM;
+
+import static com.android.internal.R.string.config_wifi_tether_enable;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.net.util.SharedLog;
+import android.os.Binder;
+import android.os.PersistableBundle;
+import android.os.ResultReceiver;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.connectivity.MockableSystemProperties;
+
+/**
+ * This class encapsulates entitlement/provisioning mechanics
+ * provisioning check only applies to the use of the mobile network as an upstream
+ *
+ * @hide
+ */
+public class EntitlementManager {
+ private static final String TAG = EntitlementManager.class.getSimpleName();
+
+ // {@link ComponentName} of the Service used to run tether provisioning.
+ private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(
+ Resources.getSystem().getString(config_wifi_tether_enable));
+ protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
+
+ // The ArraySet contains enabled downstream types, ex:
+ // {@link ConnectivityManager.TETHERING_WIFI}
+ // {@link ConnectivityManager.TETHERING_USB}
+ // {@link ConnectivityManager.TETHERING_BLUETOOTH}
+ @GuardedBy("mCurrentTethers")
+ private final ArraySet<Integer> mCurrentTethers;
+ private final Context mContext;
+ private final MockableSystemProperties mSystemProperties;
+ private final SharedLog mLog;
+ @Nullable
+ private TetheringConfiguration mConfig;
+
+ public EntitlementManager(Context ctx, SharedLog log,
+ MockableSystemProperties systemProperties) {
+ mContext = ctx;
+ mLog = log;
+ mCurrentTethers = new ArraySet<Integer>();
+ mSystemProperties = systemProperties;
+ }
+
+ /**
+ * Pass a new TetheringConfiguration instance each time when
+ * Tethering#updateConfiguration() is called.
+ */
+ public void updateConfiguration(TetheringConfiguration conf) {
+ mConfig = conf;
+ }
+
+ /**
+ * Tell EntitlementManager that a given type of tethering has been enabled
+ *
+ * @param type Tethering type
+ */
+ public void startTethering(int type) {
+ synchronized (mCurrentTethers) {
+ mCurrentTethers.add(type);
+ }
+ }
+
+ /**
+ * Tell EntitlementManager that a given type of tethering has been disabled
+ *
+ * @param type Tethering type
+ */
+ public void stopTethering(int type) {
+ synchronized (mCurrentTethers) {
+ mCurrentTethers.remove(type);
+ }
+ }
+
+ /**
+ * Check if the device requires a provisioning check in order to enable tethering.
+ *
+ * @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
+ */
+ @VisibleForTesting
+ public boolean isTetherProvisioningRequired() {
+ if (mSystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
+ || mConfig.provisioningApp.length == 0) {
+ return false;
+ }
+ if (carrierConfigAffirmsEntitlementCheckNotRequired()) {
+ return false;
+ }
+ return (mConfig.provisioningApp.length == 2);
+ }
+
+ /**
+ * Re-check tethering provisioning for enabled downstream tether types.
+ * Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
+ */
+ public void reevaluateSimCardProvisioning() {
+ if (!mConfig.hasMobileHotspotProvisionApp()) return;
+ if (carrierConfigAffirmsEntitlementCheckNotRequired()) return;
+
+ final ArraySet<Integer> reevaluateType;
+ synchronized (mCurrentTethers) {
+ reevaluateType = new ArraySet<Integer>(mCurrentTethers);
+ }
+ for (Integer type : reevaluateType) {
+ startProvisionIntent(type);
+ }
+ }
+
+ // The logic here is aimed solely at confirming that a CarrierConfig exists
+ // and affirms that entitlement checks are not required.
+ //
+ // TODO: find a better way to express this, or alter the checking process
+ // entirely so that this is more intuitive.
+ private boolean carrierConfigAffirmsEntitlementCheckNotRequired() {
+ // Check carrier config for entitlement checks
+ final CarrierConfigManager configManager = (CarrierConfigManager) mContext
+ .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (configManager == null) return false;
+
+ final PersistableBundle carrierConfig = configManager.getConfig();
+ if (carrierConfig == null) return false;
+
+ // A CarrierConfigManager was found and it has a config.
+ final boolean isEntitlementCheckRequired = carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
+ return !isEntitlementCheckRequired;
+ }
+
+ public void runSilentTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
+ Intent intent = new Intent();
+ intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_RUN_PROVISION, true);
+ intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
+ intent.setComponent(TETHER_SERVICE);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mContext.startServiceAsUser(intent, UserHandle.CURRENT);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ public void runUiTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
+ Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
+ intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ // Used by the SIM card change observation code.
+ // TODO: De-duplicate with above code, where possible.
+ private void startProvisionIntent(int tetherType) {
+ final Intent startProvIntent = new Intent();
+ startProvIntent.putExtra(EXTRA_ADD_TETHER_TYPE, tetherType);
+ startProvIntent.putExtra(EXTRA_RUN_PROVISION, true);
+ startProvIntent.setComponent(TETHER_SERVICE);
+ mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
+ }
+
+ public void scheduleProvisioningRechecks(int type) {
+ Intent intent = new Intent();
+ intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_SET_ALARM, true);
+ intent.setComponent(TETHER_SERVICE);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mContext.startServiceAsUser(intent, UserHandle.CURRENT);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ public void cancelTetherProvisioningRechecks(int type) {
+ Intent intent = new Intent();
+ intent.putExtra(EXTRA_REM_TETHER_TYPE, type);
+ intent.setComponent(TETHER_SERVICE);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mContext.startServiceAsUser(intent, UserHandle.CURRENT);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index 8b40069..d56b167 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -17,19 +17,13 @@
package com.android.server.connectivity.tethering;
import android.content.Context;
-import android.net.INetd;
import android.net.NetworkRequest;
-import android.net.dhcp.DhcpServer;
-import android.net.dhcp.DhcpServingParams;
import android.net.ip.IpServer;
-import android.net.ip.RouterAdvertisementDaemon;
-import android.net.util.InterfaceParams;
-import android.net.util.NetdService;
-import android.os.Handler;
import android.net.util.SharedLog;
-import android.os.Looper;
+import android.os.Handler;
import com.android.internal.util.StateMachine;
+import com.android.server.connectivity.MockableSystemProperties;
import java.util.ArrayList;
@@ -65,4 +59,9 @@
public NetworkRequest getDefaultNetworkRequest() {
return null;
}
+
+ public EntitlementManager getEntitlementManager(Context ctx, SharedLog log,
+ MockableSystemProperties systemProperties) {
+ return new EntitlementManager(ctx, log, systemProperties);
+ }
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e70460a..d04fa23 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -247,9 +247,6 @@
// device).
private Point mStableDisplaySize = new Point();
- // Whether the system has finished booting or not.
- private boolean mSystemReady;
-
// The top inset of the default display.
// This gets persisted so that the boot animation knows how to transition from the display's
// full size to the size configured by the user. Right now we only persist and animate the top
@@ -322,8 +319,6 @@
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
mCurrentUserId = UserHandle.USER_SYSTEM;
-
- mSystemReady = false;
}
public void setupSchedulerPolicies() {
@@ -413,10 +408,6 @@
synchronized (mSyncRoot) {
mSafeMode = safeMode;
mOnlyCore = onlyCore;
- mSystemReady = true;
- // Just in case the top inset changed before the system was ready. At this point, any
- // relevant configuration should be in place.
- recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY));
}
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
@@ -1065,10 +1056,7 @@
}
private void recordTopInsetLocked(@Nullable LogicalDisplay d) {
- // We must only persist the inset after boot has completed, otherwise we will end up
- // overwriting the persisted value before the masking flag has been loaded from the
- // resource overlay.
- if (!mSystemReady || d == null) {
+ if (d == null) {
return;
}
int topInset = d.getInsets().top;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 6f726e6..9566598 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -57,8 +57,6 @@
* </p>
*/
final class LogicalDisplay {
- private static final String PROP_MASKING_INSET_TOP = "persist.sys.displayinset.top";
-
private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
// The layer stack we use when the display has been blanked to prevent any
diff --git a/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java b/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java
index aac83b6..6fe6324 100644
--- a/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java
+++ b/services/core/java/com/android/server/intelligence/IntelligenceManagerInternal.java
@@ -19,6 +19,8 @@
import android.annotation.UserIdInt;
import android.os.Bundle;
import android.os.IBinder;
+import android.view.autofill.AutofillId;
+import android.view.autofill.IAutoFillManagerClient;
/**
* Intelligence Manager local system service interface.
@@ -41,4 +43,37 @@
*/
public abstract boolean sendActivityAssistData(@UserIdInt int userId,
@NonNull IBinder activityToken, @NonNull Bundle data);
+
+ /**
+ * Asks the intelligence service to provide Augmented Autofill for a given activity.
+ *
+ * @param userId user handle
+ * @param client binder used to communicate with the activity that originated this request.
+ * @param activityToken activity that originated this request.
+ * @param autofillSessionId autofill session id (must be used on {@code client} calls.
+ * @param focusedId id of the the field that triggered this request.
+ *
+ * @return {@code false} if the service cannot handle this request, {@code true} otherwise.
+ * <b>NOTE: </b> it must return right away; typically it will return {@code false} if the
+ * service is disabled (or the activity blacklisted).
+ */
+ public abstract AugmentedAutofillCallback requestAutofill(@UserIdInt int userId,
+ @NonNull IAutoFillManagerClient client, @NonNull IBinder activityToken,
+ int autofillSessionId, @NonNull AutofillId focusedId);
+
+ /**
+ * Callback used by the Autofill Session to communicate with the Augmented Autofill service.
+ */
+ public interface AugmentedAutofillCallback {
+ // TODO(b/111330312): this method is calling when the Autofill session is destroyed, the
+ // main reason being the cases where user tap HOME.
+ // Right now it's completely destroying the UI, but we need to decide whether / how to
+ // properly recover it later (for example, if the user switches back to the activity,
+ // should it be restored? Right not it kind of is, because Autofill's Session trigger a
+ // new FillRequest, which in turn triggers the Augmented Autofill request again)
+ /**
+ * Destroys the Autofill UI.
+ */
+ void destroy();
+ }
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 9e6e381..d5e4681 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -97,8 +97,8 @@
*
* {@hide}
*/
-public class GnssLocationProvider implements LocationProviderInterface, InjectNtpTimeCallback,
- GnssSatelliteBlacklistCallback {
+public class GnssLocationProvider extends LocationProviderInterface
+ implements InjectNtpTimeCallback, GnssSatelliteBlacklistCallback {
private static final String TAG = "GnssLocationProvider";
diff --git a/services/core/java/com/android/server/location/LocationProviderInterface.java b/services/core/java/com/android/server/location/LocationProviderInterface.java
index 6f09232..6785964 100644
--- a/services/core/java/com/android/server/location/LocationProviderInterface.java
+++ b/services/core/java/com/android/server/location/LocationProviderInterface.java
@@ -16,33 +16,63 @@
package com.android.server.location;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
+import android.location.LocationProvider;
+import android.os.Bundle;
+import android.os.WorkSource;
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
-
-import android.os.Bundle;
-import android.os.WorkSource;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
/**
* Location Manager's interface for location providers.
* @hide
*/
-public interface LocationProviderInterface {
- public String getName();
+public abstract class LocationProviderInterface {
- public void enable();
- public void disable();
- public boolean isEnabled();
- public void setRequest(ProviderRequest request, WorkSource source);
+ /** Get name. */
+ public abstract String getName();
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args);
+ /** Enable. */
+ public abstract void enable();
- // --- deprecated (but still supported) ---
- public ProviderProperties getProperties();
- public int getStatus(Bundle extras);
- public long getStatusUpdateTime();
- public boolean sendExtraCommand(String command, Bundle extras);
+ /** Disable. */
+ public abstract void disable();
+
+ /** Is enabled. */
+ public abstract boolean isEnabled();
+
+ /** Set request. */
+ public abstract void setRequest(ProviderRequest request, WorkSource source);
+
+ /** dump. */
+ public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
+
+ /** Get properties. */
+ public abstract ProviderProperties getProperties();
+
+ /**
+ * Get status.
+ *
+ * @deprecated Will be removed in a future release.
+ */
+ @Deprecated
+ public int getStatus(Bundle extras) {
+ return LocationProvider.AVAILABLE;
+ }
+
+ /**
+ * Get status update time.
+ *
+ * @deprecated Will be removed in a future release.
+ */
+ @Deprecated
+ public long getStatusUpdateTime() {
+ return 0;
+ }
+
+ /** Send extra command. */
+ public abstract boolean sendExtraCommand(String command, Bundle extras);
}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index bb86b48..b408414 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -41,7 +41,7 @@
/**
* Proxy for ILocationProvider implementations.
*/
-public class LocationProviderProxy implements LocationProviderInterface {
+public class LocationProviderProxy extends LocationProviderInterface {
private static final String TAG = "LocationProviderProxy";
private static final boolean D = LocationManagerService.D;
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index 8578761..145aee3 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -25,31 +25,31 @@
import android.util.Log;
import android.util.PrintWriterPrinter;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
-
/**
* A mock location provider used by LocationManagerService to implement test providers.
*
* {@hide}
*/
-public class MockProvider implements LocationProviderInterface {
+public class MockProvider extends LocationProviderInterface {
private final String mName;
private final ProviderProperties mProperties;
private final ILocationManager mLocationManager;
private final Location mLocation;
- private final Bundle mExtras = new Bundle();
+
+ private boolean mHasLocation;
+ private boolean mEnabled;
+
private int mStatus;
private long mStatusUpdateTime;
- private boolean mHasLocation;
- private boolean mHasStatus;
- private boolean mEnabled;
+ private Bundle mExtras;
private static final String TAG = "MockProvider";
@@ -61,6 +61,10 @@
mLocationManager = locationManager;
mProperties = properties;
mLocation = new Location(name);
+
+ mStatus = LocationProvider.AVAILABLE;
+ mStatusUpdateTime = 0L;
+ mExtras = null;
}
@Override
@@ -90,13 +94,12 @@
@Override
public int getStatus(Bundle extras) {
- if (mHasStatus) {
+ if (mExtras != null) {
extras.clear();
extras.putAll(mExtras);
- return mStatus;
- } else {
- return LocationProvider.AVAILABLE;
}
+
+ return mStatus;
}
@Override
@@ -120,19 +123,14 @@
mHasLocation = false;
}
+ /**
+ * @deprecated Will be removed in a future release.
+ */
+ @Deprecated
public void setStatus(int status, Bundle extras, long updateTime) {
mStatus = status;
mStatusUpdateTime = updateTime;
- mExtras.clear();
- if (extras != null) {
- mExtras.putAll(extras);
- }
- mHasStatus = true;
- }
-
- public void clearStatus() {
- mHasStatus = false;
- mStatusUpdateTime = 0;
+ mExtras = extras;
}
@Override
@@ -145,9 +143,6 @@
pw.println(prefix + "mHasLocation=" + mHasLocation);
pw.println(prefix + "mLocation:");
mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
- pw.println(prefix + "mHasStatus=" + mHasStatus);
- pw.println(prefix + "mStatus=" + mStatus);
- pw.println(prefix + "mStatusUpdateTime=" + mStatusUpdateTime);
pw.println(prefix + "mExtras=" + mExtras);
}
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
index 71bae07..99c9214 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveProvider.java
@@ -16,22 +16,20 @@
package com.android.server.location;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-import com.android.internal.location.ProviderProperties;
-import com.android.internal.location.ProviderRequest;
-
import android.location.Criteria;
import android.location.ILocationManager;
import android.location.Location;
import android.location.LocationManager;
-import android.location.LocationProvider;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.WorkSource;
import android.util.Log;
+import com.android.internal.location.ProviderProperties;
+import com.android.internal.location.ProviderRequest;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
/**
* A passive location provider reports locations received from other providers
@@ -40,7 +38,7 @@
*
* {@hide}
*/
-public class PassiveProvider implements LocationProviderInterface {
+public class PassiveProvider extends LocationProviderInterface {
private static final String TAG = "PassiveProvider";
private static final ProviderProperties PROPERTIES = new ProviderProperties(
@@ -78,20 +76,6 @@
}
@Override
- public int getStatus(Bundle extras) {
- if (mReportLocation) {
- return LocationProvider.AVAILABLE;
- } else {
- return LocationProvider.TEMPORARILY_UNAVAILABLE;
- }
- }
-
- @Override
- public long getStatusUpdateTime() {
- return -1;
- }
-
- @Override
public void setRequest(ProviderRequest request, WorkSource source) {
mReportLocation = request.reportLocation;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4da29e4..2048d5f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -246,6 +246,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import java.util.function.BiConsumer;
import java.util.function.Predicate;
/** {@hide} */
@@ -887,6 +888,7 @@
EventLogTags.writeNotificationExpansion(key,
userAction ? 1 : 0, expanded ? 1 : 0,
r.getLifespanMs(now), r.getFreshnessMs(now), r.getExposureMs(now));
+ mAssistants.notifyAssistantExpansionChangedLocked(r.sbn, userAction, expanded);
}
}
}
@@ -902,6 +904,7 @@
.setCategory(MetricsEvent.NOTIFICATION_DIRECT_REPLY_ACTION)
.setType(MetricsEvent.TYPE_ACTION));
reportUserInteraction(r);
+ mAssistants.notifyAssistantNotificationDirectReplyLocked(r.sbn);
}
}
}
@@ -4398,19 +4401,20 @@
*
* Has side effects.
*/
- private boolean checkDisqualifyingFeatures(int userId, int callingUid, int id, String tag,
+ private boolean checkDisqualifyingFeatures(int userId, int uid, int id, String tag,
NotificationRecord r, boolean isAutogroup) {
final String pkg = r.sbn.getPackageName();
final boolean isSystemNotification =
- isUidSystemOrPhone(callingUid) || ("android".equals(pkg));
+ isUidSystemOrPhone(uid) || ("android".equals(pkg));
final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg);
// Limit the number of notifications that any given package except the android
// package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks.
if (!isSystemNotification && !isNotificationFromListener) {
synchronized (mNotificationLock) {
+ final int callingUid = Binder.getCallingUid();
if (mNotificationsByKey.get(r.sbn.getKey()) == null
- && isCallerInstantApp(pkg, Binder.getCallingUid(), userId)) {
+ && isCallerInstantApp(callingUid, userId)) {
// Ephemeral apps have some special constraints for notifications.
// They are not allowed to create new notifications however they are allowed to
// update notifications created by the system (e.g. a foreground service
@@ -4729,7 +4733,7 @@
mRankingHelper.extractSignals(r);
// tell the assistant service about the notification
if (mAssistants.isEnabled()) {
- mAssistants.onNotificationEnqueued(r);
+ mAssistants.onNotificationEnqueuedLocked(r);
mHandler.postDelayed(new PostNotificationRunnable(r.getKey()),
DELAY_FOR_ASSISTANT_TIME);
} else {
@@ -6521,24 +6525,28 @@
}
@VisibleForTesting
- boolean isCallerInstantApp(String pkg, int callingUid, int userId) {
+ boolean isCallerInstantApp(int callingUid, int userId) {
// System is always allowed to act for ephemeral apps.
if (isUidSystemOrPhone(callingUid)) {
return false;
}
- mAppOps.checkPackage(callingUid, pkg);
-
try {
+ final String[] pkgs = mPackageManager.getPackagesForUid(callingUid);
+ if (pkgs == null) {
+ throw new SecurityException("Unknown uid " + callingUid);
+ }
+ final String pkg = pkgs[0];
+ mAppOps.checkPackage(callingUid, pkg);
+
ApplicationInfo ai = mPackageManager.getApplicationInfo(pkg, 0, userId);
if (ai == null) {
throw new SecurityException("Unknown package " + pkg);
}
return ai.isInstantApp();
} catch (RemoteException re) {
- throw new SecurityException("Unknown package " + pkg, re);
+ throw new SecurityException("Unknown uid " + callingUid, re);
}
-
}
private void checkCallerIsSameApp(String pkg) {
@@ -6842,69 +6850,104 @@
}
}
- public void onNotificationEnqueued(final NotificationRecord r) {
+ @GuardedBy("mNotificationLock")
+ private void onNotificationEnqueuedLocked(final NotificationRecord r) {
final StatusBarNotification sbn = r.sbn;
- TrimCache trimCache = new TrimCache(sbn);
-
- // There should be only one, but it's a list, so while we enforce
- // singularity elsewhere, we keep it general here, to avoid surprises.
- for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
- boolean sbnVisible = isVisibleToListener(sbn, info)
- && info.isSameUser(r.getUserId());
- if (!sbnVisible) {
- continue;
- }
-
- final StatusBarNotification sbnToPost = trimCache.ForListener(info);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- notifyEnqueued(info, sbnToPost, r.getChannel());
- }
- });
- }
+ notifyAssistantLocked(
+ sbn,
+ true /* sameUserOnly */,
+ (assistant, sbnHolder) -> {
+ try {
+ assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel());
+ } catch (RemoteException ex) {
+ Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
+ }
+ });
}
- private void notifyEnqueued(final ManagedServiceInfo info,
- final StatusBarNotification sbn, final NotificationChannel channel) {
- final INotificationListener assistant = (INotificationListener) info.service;
- StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
- try {
- assistant.onNotificationEnqueuedWithChannel(sbnHolder, channel);
- } catch (RemoteException ex) {
- Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
- }
+ @GuardedBy("mNotificationLock")
+ void notifyAssistantExpansionChangedLocked(
+ final StatusBarNotification sbn,
+ final boolean isUserAction,
+ final boolean isExpanded) {
+ final String key = sbn.getKey();
+ notifyAssistantLocked(
+ sbn,
+ false /* sameUserOnly */,
+ (assistant, sbnHolder) -> {
+ try {
+ assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
+ }
+ });
}
+ @GuardedBy("mNotificationLock")
+ void notifyAssistantNotificationDirectReplyLocked(
+ final StatusBarNotification sbn) {
+ final String key = sbn.getKey();
+ notifyAssistantLocked(
+ sbn,
+ false /* sameUserOnly */,
+ (assistant, sbnHolder) -> {
+ try {
+ assistant.onNotificationDirectReply(key);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
+ }
+ });
+ }
+
+
/**
* asynchronously notify the assistant that a notification has been snoozed until a
* context
*/
@GuardedBy("mNotificationLock")
- public void notifyAssistantSnoozedLocked(final StatusBarNotification sbn,
- final String snoozeCriterionId) {
- TrimCache trimCache = new TrimCache(sbn);
- for (final ManagedServiceInfo info : getServices()) {
- boolean sbnVisible = isVisibleToListener(sbn, info);
- if (!sbnVisible) {
- continue;
- }
- final StatusBarNotification sbnToPost = trimCache.ForListener(info);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final INotificationListener assistant =
- (INotificationListener) info.service;
- StatusBarNotificationHolder sbnHolder
- = new StatusBarNotificationHolder(sbnToPost);
+ private void notifyAssistantSnoozedLocked(
+ final StatusBarNotification sbn, final String snoozeCriterionId) {
+ notifyAssistantLocked(
+ sbn,
+ false /* sameUserOnly */,
+ (assistant, sbnHolder) -> {
try {
assistant.onNotificationSnoozedUntilContext(
sbnHolder, snoozeCriterionId);
} catch (RemoteException ex) {
Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
}
- }
- });
+ });
+ }
+
+ /**
+ * Notifies the assistant something about the specified notification, only assistant
+ * that is visible to the notification will be notified.
+ *
+ * @param sbn the notification object that the update is about.
+ * @param sameUserOnly should the update be sent to the assistant in the same user only.
+ * @param callback the callback that provides the assistant to be notified, executed
+ * in WorkerHandler.
+ */
+ @GuardedBy("mNotificationLock")
+ private void notifyAssistantLocked(
+ final StatusBarNotification sbn,
+ boolean sameUserOnly,
+ BiConsumer<INotificationListener, StatusBarNotificationHolder> callback) {
+ TrimCache trimCache = new TrimCache(sbn);
+ // There should be only one, but it's a list, so while we enforce
+ // singularity elsewhere, we keep it general here, to avoid surprises.
+ for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
+ boolean sbnVisible = isVisibleToListener(sbn, info)
+ && (!sameUserOnly || info.isSameUser(sbn.getUserId()));
+ if (!sbnVisible) {
+ continue;
+ }
+ final INotificationListener assistant = (INotificationListener) info.service;
+ final StatusBarNotification sbnToPost = trimCache.ForListener(info);
+ final StatusBarNotificationHolder sbnHolder =
+ new StatusBarNotificationHolder(sbnToPost);
+ mHandler.post(() -> callback.accept(assistant, sbnHolder));
}
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index f1b03d1..d471904 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -22,14 +22,11 @@
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
-import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
-import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.SIGNATURE_MATCH;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
-import android.app.ActivityThread;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -37,7 +34,6 @@
import android.content.IntentFilter;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
-import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManagerInternal;
@@ -59,11 +55,9 @@
import android.util.Slog;
import android.util.SparseArray;
-import com.android.internal.util.ConcurrentUtils;
import com.android.server.FgThread;
import com.android.server.IoThread;
import com.android.server.LocalServices;
-import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
import com.android.server.pm.Installer;
import com.android.server.pm.UserManagerService;
@@ -84,8 +78,6 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -228,8 +220,6 @@
private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false);
- private Future<?> mInitCompleteSignal;
-
public OverlayManagerService(@NonNull final Context context,
@NonNull final Installer installer) {
super(context);
@@ -241,29 +231,28 @@
mSettings = new OverlayManagerSettings();
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
getDefaultOverlayPackages(), new OverlayChangeListener());
- mInitCompleteSignal = SystemServerInitThreadPool.get().submit(() -> {
- final IntentFilter packageFilter = new IntentFilter();
- packageFilter.addAction(ACTION_PACKAGE_ADDED);
- packageFilter.addAction(ACTION_PACKAGE_CHANGED);
- packageFilter.addAction(ACTION_PACKAGE_REMOVED);
- packageFilter.addDataScheme("package");
- getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
- packageFilter, null, null);
- final IntentFilter userFilter = new IntentFilter();
- userFilter.addAction(ACTION_USER_ADDED);
- userFilter.addAction(ACTION_USER_REMOVED);
- getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
- userFilter, null, null);
+ final IntentFilter packageFilter = new IntentFilter();
+ packageFilter.addAction(ACTION_PACKAGE_ADDED);
+ packageFilter.addAction(ACTION_PACKAGE_CHANGED);
+ packageFilter.addAction(ACTION_PACKAGE_REMOVED);
+ packageFilter.addDataScheme("package");
+ getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
+ packageFilter, null, null);
- restoreSettings();
+ final IntentFilter userFilter = new IntentFilter();
+ userFilter.addAction(ACTION_USER_ADDED);
+ userFilter.addAction(ACTION_USER_REMOVED);
+ getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
+ userFilter, null, null);
- initIfNeeded();
- onSwitchUser(UserHandle.USER_SYSTEM);
+ restoreSettings();
- publishBinderService(Context.OVERLAY_SERVICE, mService);
- publishLocalService(OverlayManagerService.class, this);
- }, "Init OverlayManagerService");
+ initIfNeeded();
+ onSwitchUser(UserHandle.USER_SYSTEM);
+
+ publishBinderService(Context.OVERLAY_SERVICE, mService);
+ publishLocalService(OverlayManagerService.class, this);
}
@Override
@@ -271,32 +260,6 @@
// Intentionally left empty.
}
- @Override
- public void onBootPhase(int phase) {
- if (phase == PHASE_SYSTEM_SERVICES_READY && mInitCompleteSignal != null) {
- ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
- "Wait for OverlayManagerService init");
- mInitCompleteSignal = null;
- }
- }
-
- public void updateSystemUiContext() {
- if (mInitCompleteSignal != null) {
- ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
- "Wait for OverlayManagerService init");
- mInitCompleteSignal = null;
- }
-
- final ApplicationInfo ai;
- try {
- ai = mPackageManager.mPackageManager.getApplicationInfo("android",
- GET_SHARED_LIBRARY_FILES, UserHandle.USER_SYSTEM);
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
- ActivityThread.currentActivityThread().handleSystemApplicationInfoChanged(ai);
- }
-
private void initIfNeeded() {
final UserManager um = getContext().getSystemService(UserManager.class);
final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 59c6d0a..3ba1155 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -20,13 +20,7 @@
import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
import static android.app.AppOpsManager.OP_TOAST_WINDOW;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Context.CONTEXT_RESTRICTED;
import static android.content.Context.DISPLAY_SERVICE;
import static android.content.Context.WINDOW_SERVICE;
@@ -35,61 +29,28 @@
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.res.Configuration.EMPTY;
-import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
-import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.O;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Display.STATE_OFF;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.LAST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
-import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
-import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
-import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
-import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
-import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
import static android.view.WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -106,19 +67,13 @@
import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE;
import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
-import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.LayoutParams.isSystemAlertWindowType;
@@ -132,25 +87,15 @@
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.CAMERA_LENS_UNCOVERED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_CLOSED;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN;
-import static com.android.server.wm.WindowManagerPolicyProto.FOCUSED_APP_TOKEN;
-import static com.android.server.wm.WindowManagerPolicyProto.FOCUSED_WINDOW;
-import static com.android.server.wm.WindowManagerPolicyProto.FORCE_STATUS_BAR;
-import static com.android.server.wm.WindowManagerPolicyProto.FORCE_STATUS_BAR_FROM_KEYGUARD;
import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_DELEGATE;
import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_DRAW_COMPLETE;
import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_OCCLUDED;
import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_OCCLUDED_CHANGED;
import static com.android.server.wm.WindowManagerPolicyProto.KEYGUARD_OCCLUDED_PENDING;
-import static com.android.server.wm.WindowManagerPolicyProto.LAST_SYSTEM_UI_FLAGS;
-import static com.android.server.wm.WindowManagerPolicyProto.NAVIGATION_BAR;
import static com.android.server.wm.WindowManagerPolicyProto.ORIENTATION;
-import static com.android.server.wm.WindowManagerPolicyProto.ORIENTATION_LISTENER;
import static com.android.server.wm.WindowManagerPolicyProto.ROTATION;
import static com.android.server.wm.WindowManagerPolicyProto.ROTATION_MODE;
import static com.android.server.wm.WindowManagerPolicyProto.SCREEN_ON_FULLY;
-import static com.android.server.wm.WindowManagerPolicyProto.STATUS_BAR;
-import static com.android.server.wm.WindowManagerPolicyProto.TOP_FULLSCREEN_OPAQUE_OR_DIMMING_WINDOW;
-import static com.android.server.wm.WindowManagerPolicyProto.TOP_FULLSCREEN_OPAQUE_WINDOW;
import static com.android.server.wm.WindowManagerPolicyProto.WINDOW_MANAGER_DRAW_COMPLETE;
import android.annotation.Nullable;
@@ -158,12 +103,10 @@
import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
-import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.IUiModeManager;
import android.app.ProgressDialog;
import android.app.SearchManager;
-import android.app.StatusBarManager;
import android.app.UiModeManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
@@ -181,15 +124,12 @@
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.PixelFormat;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPlaybackClient;
import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
-import android.hardware.input.InputManager;
import android.hardware.input.InputManagerInternal;
-import android.hardware.power.V1_0.PowerHint;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioManagerInternal;
@@ -202,7 +142,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.IDeviceIdleController;
-import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
@@ -224,7 +163,6 @@
import android.service.vr.IPersistentVrStateCallbacks;
import android.speech.RecognizerIntent;
import android.telecom.TelecomManager;
-import android.util.ArraySet;
import android.util.EventLog;
import android.util.Log;
import android.util.LongSparseArray;
@@ -234,21 +172,13 @@
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
-import android.view.DisplayCutout;
-import android.view.Gravity;
import android.view.HapticFeedbackConstants;
-import android.view.IApplicationToken;
import android.view.IWindowManager;
-import android.view.InputChannel;
import android.view.InputDevice;
-import android.view.InputEvent;
-import android.view.InputEventReceiver;
import android.view.KeyCharacterMap;
import android.view.KeyCharacterMap.FallbackAction;
import android.view.KeyEvent;
import android.view.MotionEvent;
-import android.view.PointerIcon;
-import android.view.Surface;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
@@ -263,8 +193,6 @@
import com.android.internal.R;
import com.android.internal.accessibility.AccessibilityShortcutController;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -272,7 +200,6 @@
import com.android.internal.policy.PhoneWindow;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.ScreenShapeHelper;
import com.android.internal.util.ScreenshotHelper;
import com.android.internal.widget.PointerLocationView;
import com.android.server.ExtconStateObserver;
@@ -289,19 +216,17 @@
import com.android.server.wm.ActivityTaskManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
import com.android.server.wm.AppTransition;
-import com.android.server.wm.DisplayFrames;
import com.android.server.wm.DisplayPolicy;
import com.android.server.wm.DisplayRotation;
-import com.android.server.wm.WindowFrames;
import com.android.server.wm.WindowManagerInternal;
import com.android.server.wm.WindowManagerInternal.AppTransitionListener;
-import com.android.server.wm.utils.InsetUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.HashSet;
import java.util.List;
/**
@@ -313,11 +238,9 @@
*/
public class PhoneWindowManager implements WindowManagerPolicy {
static final String TAG = "WindowManager";
- static final boolean DEBUG = false;
static final boolean localLOGV = false;
static final boolean DEBUG_INPUT = false;
static final boolean DEBUG_KEYGUARD = false;
- static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_SPLASH_SCREEN = false;
static final boolean DEBUG_WAKEUP = false;
static final boolean SHOW_SPLASH_SCREENS = true;
@@ -329,8 +252,6 @@
// Whether to allow devices placed in vr headset viewers to have an alternative Home intent.
static final boolean ENABLE_VR_HEADSET_HOME_CAPTURE = true;
- static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
-
static final int SHORT_PRESS_POWER_NOTHING = 0;
static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1;
static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
@@ -372,13 +293,6 @@
static final int PENDING_KEY_NULL = -1;
- // Controls navigation bar opacity depending on which workspace stacks are currently
- // visible.
- // Nav bar is always opaque when either the freeform stack or docked stack is visible.
- static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
- // Nav bar is always translucent when the freeform stack is visible, otherwise always opaque.
- static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
-
static public final String SYSTEM_DIALOG_REASON_KEY = "reason";
static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
@@ -386,33 +300,11 @@
static public final String SYSTEM_DIALOG_REASON_ASSIST = "assist";
static public final String SYSTEM_DIALOG_REASON_SCREENSHOT = "screenshot";
- /**
- * These are the system UI flags that, when changing, can cause the layout
- * of the screen to change.
- */
- static final int SYSTEM_UI_CHANGING_LAYOUT =
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.STATUS_BAR_TRANSLUCENT
- | View.NAVIGATION_BAR_TRANSLUCENT
- | View.STATUS_BAR_TRANSPARENT
- | View.NAVIGATION_BAR_TRANSPARENT;
-
private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
- // The panic gesture may become active only after the keyguard is dismissed and the immersive
- // app shows again. If that doesn't happen for 30s we drop the gesture.
- private static final long PANIC_GESTURE_EXPIRATION = 30000;
-
- private static final String SYSUI_PACKAGE = "com.android.systemui";
- private static final String SYSUI_SCREENSHOT_SERVICE =
- "com.android.systemui.screenshot.TakeScreenshotService";
- private static final String SYSUI_SCREENSHOT_ERROR_RECEIVER =
- "com.android.systemui.screenshot.ScreenshotServiceErrorReceiver";
-
/**
* Keyguard stuff
*/
@@ -501,16 +393,7 @@
private AccessibilityShortcutController mAccessibilityShortcutController;
boolean mSafeMode;
- private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
- WindowState mStatusBar = null;
- private final int[] mStatusBarHeightForRotation = new int[4];
- WindowState mNavigationBar = null;
- @NavigationBarPosition
- int mNavigationBarPosition = NAV_BAR_BOTTOM;
- int[] mNavigationBarHeightForRotationDefault = new int[4];
- int[] mNavigationBarWidthForRotationDefault = new int[4];
- int[] mNavigationBarHeightForRotationInCarMode = new int[4];
- int[] mNavigationBarWidthForRotationInCarMode = new int[4];
+ private WindowState mKeyguardCandidate = null;
private LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>();
@@ -591,7 +474,6 @@
int mShortPressOnSleepBehavior;
int mShortPressOnWindowBehavior;
boolean mHasSoftInput = false;
- boolean mTranslucentDecorEnabled = true;
boolean mUseTvRouting;
int mVeryLongPressTimeout;
boolean mAllowStartActivityForLongPressOnPowerDuringSetup;
@@ -600,74 +482,12 @@
private boolean mHandleVolumeKeysInWM;
int mPointerLocationMode = 0; // guarded by mLock
-
- // The windows we were told about in focusChanged.
- WindowState mFocusedWindow;
- WindowState mLastFocusedWindow;
-
- IApplicationToken mFocusedApp;
-
PointerLocationView mPointerLocationView;
- // During layout, the layer at which the doc window is placed.
- int mDockLayer;
- // During layout, this is the layer of the status bar.
- int mStatusBarLayer;
- int mLastSystemUiFlags;
- // Bits that we are in the process of clearing, so we want to prevent
- // them from being set by applications until everything has been updated
- // to have them clear.
- int mResettingSystemUiFlags = 0;
- // Bits that we are currently always keeping cleared.
- int mForceClearedSystemUiFlags = 0;
- int mLastFullscreenStackSysUiFlags;
- int mLastDockedStackSysUiFlags;
- final Rect mNonDockedStackBounds = new Rect();
- final Rect mDockedStackBounds = new Rect();
- final Rect mLastNonDockedStackBounds = new Rect();
- final Rect mLastDockedStackBounds = new Rect();
-
- // What we last reported to system UI about whether the compatibility
- // menu needs to be displayed.
- boolean mLastFocusNeedsMenu = false;
- // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
- private long mPendingPanicGestureUptime;
-
- InputConsumer mInputConsumer = null;
-
- private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
- private static final Rect sTmpRect = new Rect();
- private static final Rect sTmpDockedFrame = new Rect();
- private static final Rect sTmpNavFrame = new Rect();
- private static final Rect sTmpLastParentFrame = new Rect();
-
- WindowState mTopFullscreenOpaqueWindowState;
- WindowState mTopFullscreenOpaqueOrDimmingWindowState;
- WindowState mTopDockedOpaqueWindowState;
- WindowState mTopDockedOpaqueOrDimmingWindowState;
- boolean mTopIsFullscreen;
- boolean mForceStatusBar;
- boolean mForceStatusBarFromKeyguard;
- private boolean mForceStatusBarTransparent;
- int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
- boolean mForcingShowNavBar;
- int mForcingShowNavBarLayer;
-
private boolean mPendingKeyguardOccluded;
private boolean mKeyguardOccludedChanged;
private boolean mNotifyUserActivity;
- boolean mShowingDream;
- private boolean mLastShowingDream;
- boolean mDreamingLockscreen;
- boolean mDreamingSleepTokenNeeded;
- private boolean mWindowSleepTokenNeeded;
- private boolean mLastWindowSleepTokenNeeded;
-
- @GuardedBy("mHandler")
- private SleepToken mWindowSleepToken;
-
- SleepToken mDreamingSleepToken;
SleepToken mScreenOffSleepToken;
volatile boolean mKeyguardOccluded;
Intent mHomeIntent;
@@ -680,10 +500,9 @@
boolean mPendingCapsLockToggle;
int mMetaState;
int mInitialMetaState;
- boolean mForceShowSystemBars;
// support for activating the lock screen while the screen is on
- boolean mAllowLockscreenWhenOn;
+ private HashSet<Integer> mAllowLockscreenWhenOnDisplays = new HashSet<>();
int mLockScreenTimeout;
boolean mLockScreenTimerActive;
@@ -704,7 +523,6 @@
Display mDefaultDisplay;
DisplayRotation mDefaultDisplayRotation;
DisplayPolicy mDefaultDisplayPolicy;
- WindowOrientationListener mDefaultOrientationListener;
// What we do when the user long presses on home
private int mLongPressOnHomeBehavior;
@@ -781,10 +599,6 @@
private boolean mAodShowing;
- // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
- private NavigationBarExperiments mExperiments = new NavigationBarExperiments();
- // EXPERIMENT END
-
private static final int MSG_ENABLE_POINTER_LOCATION = 1;
private static final int MSG_DISABLE_POINTER_LOCATION = 2;
private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
@@ -798,25 +612,19 @@
private static final int MSG_LAUNCH_VOICE_ASSIST_WITH_WAKE_LOCK = 12;
private static final int MSG_POWER_DELAYED_PRESS = 13;
private static final int MSG_POWER_LONG_PRESS = 14;
- private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 15;
- private static final int MSG_REQUEST_TRANSIENT_BARS = 16;
- private static final int MSG_SHOW_PICTURE_IN_PICTURE_MENU = 17;
- private static final int MSG_BACK_LONG_PRESS = 18;
- private static final int MSG_DISPOSE_INPUT_CONSUMER = 19;
- private static final int MSG_ACCESSIBILITY_SHORTCUT = 20;
- private static final int MSG_BUGREPORT_TV = 21;
- private static final int MSG_ACCESSIBILITY_TV = 22;
- private static final int MSG_DISPATCH_BACK_KEY_TO_AUTOFILL = 23;
- private static final int MSG_SYSTEM_KEY_PRESS = 24;
- private static final int MSG_HANDLE_ALL_APPS = 25;
- private static final int MSG_LAUNCH_ASSIST = 26;
- private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 27;
- private static final int MSG_POWER_VERY_LONG_PRESS = 28;
- private static final int MSG_NOTIFY_USER_ACTIVITY = 29;
- private static final int MSG_RINGER_TOGGLE_CHORD = 30;
-
- private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
- private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
+ private static final int MSG_SHOW_PICTURE_IN_PICTURE_MENU = 15;
+ private static final int MSG_BACK_LONG_PRESS = 16;
+ private static final int MSG_ACCESSIBILITY_SHORTCUT = 17;
+ private static final int MSG_BUGREPORT_TV = 18;
+ private static final int MSG_ACCESSIBILITY_TV = 19;
+ private static final int MSG_DISPATCH_BACK_KEY_TO_AUTOFILL = 20;
+ private static final int MSG_SYSTEM_KEY_PRESS = 21;
+ private static final int MSG_HANDLE_ALL_APPS = 22;
+ private static final int MSG_LAUNCH_ASSIST = 23;
+ private static final int MSG_LAUNCH_ASSIST_LONG_PRESS = 24;
+ private static final int MSG_POWER_VERY_LONG_PRESS = 25;
+ private static final int MSG_NOTIFY_USER_ACTIVITY = 26;
+ private static final int MSG_RINGER_TOGGLE_CHORD = 27;
private class PolicyHandler extends Handler {
@Override
@@ -876,25 +684,12 @@
case MSG_POWER_VERY_LONG_PRESS:
powerVeryLongPress();
break;
- case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
- updateDreamingSleepToken(msg.arg1 != 0);
- break;
- case MSG_REQUEST_TRANSIENT_BARS:
- WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS) ?
- mStatusBar : mNavigationBar;
- if (targetBar != null) {
- requestTransientBars(targetBar);
- }
- break;
case MSG_SHOW_PICTURE_IN_PICTURE_MENU:
showPictureInPictureMenuInternal();
break;
case MSG_BACK_LONG_PRESS:
backLongPress();
break;
- case MSG_DISPOSE_INPUT_CONSUMER:
- disposeInputConsumer((InputConsumer) msg.obj);
- break;
case MSG_ACCESSIBILITY_SHORTCUT:
accessibilityShortcutActivated();
break;
@@ -966,14 +761,8 @@
Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS), false, this,
- UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.VOLUME_HUSH_GESTURE), false, this,
UserHandle.USER_ALL);
- resolver.registerContentObserver(Settings.Global.getUriFor(
- Settings.Global.POLICY_CONTROL), false, this,
- UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED), false, this,
UserHandle.USER_ALL);
@@ -1012,45 +801,6 @@
}
};
- private final StatusBarController mStatusBarController = new StatusBarController();
-
- private final BarController mNavigationBarController = new BarController("NavigationBar",
- View.NAVIGATION_BAR_TRANSIENT,
- View.NAVIGATION_BAR_UNHIDE,
- View.NAVIGATION_BAR_TRANSLUCENT,
- StatusBarManager.WINDOW_NAVIGATION_BAR,
- FLAG_TRANSLUCENT_NAVIGATION,
- View.NAVIGATION_BAR_TRANSPARENT);
-
- private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
- new BarController.OnBarVisibilityChangedListener() {
- @Override
- public void onBarVisibilityChanged(boolean visible) {
- mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
- }
- };
-
- private final Runnable mAcquireSleepTokenRunnable = () -> {
- if (mWindowSleepToken != null) {
- return;
- }
- mWindowSleepToken = mActivityTaskManagerInternal.acquireSleepToken("WindowSleepToken",
- DEFAULT_DISPLAY);
- };
-
- private final Runnable mReleaseSleepTokenRunnable = () -> {
- if (mWindowSleepToken == null) {
- return;
- }
- mWindowSleepToken.release();
- mWindowSleepToken = null;
- };
-
- private ImmersiveModeConfirmation mImmersiveModeConfirmation;
-
- @VisibleForTesting
- SystemGesturesPointerEventListener mSystemGestures;
-
private void handleRingerChordGesture() {
if (mRingerToggleChord == VOLUME_HUSH_OFF) {
return;
@@ -1150,14 +900,7 @@
mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);
}
- // Detect user pressing the power button in panic when an application has
- // taken over the whole screen.
- boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive,
- SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
- isNavBarEmpty(mLastSystemUiFlags));
- if (panic) {
- mHandler.post(mHiddenNavPanic);
- }
+ mWindowManagerFuncs.onPowerKeyDown(interactive);
// Abort possibly stuck animations.
mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe);
@@ -1500,12 +1243,6 @@
mAccessibilityShortcutController.performAccessibilityShortcut();
}
- private void disposeInputConsumer(InputConsumer inputConsumer) {
- if (inputConsumer != null) {
- inputConsumer.dismiss();
- }
- }
-
private void sleepPress() {
if (mShortPressOnSleepBehavior == SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME) {
launchHomeFromHotKey(DEFAULT_DISPLAY, false /* awakenDreams */,
@@ -1643,9 +1380,7 @@
@Override
public void run() {
- mScreenshotHelper.takeScreenshot(mScreenshotType,
- mStatusBar != null && mStatusBar.isVisibleLw(),
- mNavigationBar != null && mNavigationBar.isVisibleLw(), mHandler);
+ mDefaultDisplayPolicy.takeScreenshot(mScreenshotType);
}
}
@@ -1673,7 +1408,8 @@
mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
}
- boolean isUserSetupComplete() {
+ @Override
+ public boolean isUserSetupComplete() {
boolean isSetupComplete = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
if (mHasFeatureLeanback) {
@@ -1931,7 +1667,6 @@
mDefaultDisplay = displayContentInfo.getDisplay();
mDefaultDisplayRotation = displayContentInfo.getDisplayRotation();
mDefaultDisplayPolicy = mDefaultDisplayRotation.getDisplayPolicy();
- mDefaultOrientationListener = mDefaultDisplayRotation.getOrientationListener();
}
/** {@inheritDoc} */
@@ -2028,8 +1763,6 @@
com.android.internal.R.bool.config_lidControlsScreenLock);
mLidControlsSleep = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_lidControlsSleep);
- mTranslucentDecorEnabled = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_enableTranslucentDecor);
mAllowTheaterModeWakeFromKey = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowTheaterModeWakeFromKey);
@@ -2107,76 +1840,6 @@
filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
context.registerReceiver(mMultiuserReceiver, filter);
- // monitor for system gestures
- // TODO(multi-display): Needs to be display specific.
- mSystemGestures = new SystemGesturesPointerEventListener(context,
- new SystemGesturesPointerEventListener.Callbacks() {
- @Override
- public void onSwipeFromTop() {
- if (mStatusBar != null) {
- requestTransientBars(mStatusBar);
- }
- }
- @Override
- public void onSwipeFromBottom() {
- if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
- requestTransientBars(mNavigationBar);
- }
- }
- @Override
- public void onSwipeFromRight() {
- if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_RIGHT) {
- requestTransientBars(mNavigationBar);
- }
- }
- @Override
- public void onSwipeFromLeft() {
- if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_LEFT) {
- requestTransientBars(mNavigationBar);
- }
- }
- @Override
- public void onFling(int duration) {
- if (mPowerManagerInternal != null) {
- mPowerManagerInternal.powerHint(
- PowerHint.INTERACTION, duration);
- }
- }
- @Override
- public void onDebug() {
- // no-op
- }
- @Override
- public void onDown() {
- mDefaultOrientationListener.onTouchStart();
- }
- @Override
- public void onUpOrCancel() {
- mDefaultOrientationListener.onTouchEnd();
- }
- @Override
- public void onMouseHoverAtTop() {
- mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
- Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
- msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
- mHandler.sendMessageDelayed(msg, 500);
- }
- @Override
- public void onMouseHoverAtBottom() {
- mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
- Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
- msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
- mHandler.sendMessageDelayed(msg, 500);
- }
- @Override
- public void onMouseLeaveFromEdge() {
- mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
- }
- });
- mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext);
- //TODO (b/111365687) : make system context per display.
- mWindowManagerFuncs.registerPointerEventListener(mSystemGestures, DEFAULT_DISPLAY);
-
mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
mLongPressVibePattern = getLongIntArray(mContext.getResources(),
com.android.internal.R.array.config_longPressVibePattern);
@@ -2199,8 +1862,6 @@
finishedGoingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
}
- mWindowManagerInternal.registerAppTransitionListener(
- mStatusBarController.getAppTransitionListener());
mWindowManagerInternal.registerAppTransitionListener(new AppTransitionListener() {
@Override
public int onAppTransitionStartingLocked(int transit, IBinder openToken,
@@ -2255,16 +1916,6 @@
if (mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
mShortPressOnWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE;
}
-
- mNavBarOpacityMode = res.getInteger(
- com.android.internal.R.integer.config_navBarOpacityMode);
- }
-
- /**
- * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
- */
- private boolean canHideNavigationBar() {
- return mDefaultDisplayPolicy.hasNavigationBar();
}
public void updateSettings() {
@@ -2322,12 +1973,6 @@
mHasSoftInput = hasSoftInput;
updateRotation = true;
}
- if (mImmersiveModeConfirmation != null) {
- mImmersiveModeConfirmation.loadSetting(mCurrentUserId);
- }
- }
- synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
- PolicyControl.reloadFromSetting(mContext);
}
if (updateRotation) {
updateRotation(true);
@@ -2536,84 +2181,6 @@
return mContext.checkCallingOrSelfPermission(INTERNAL_SYSTEM_WINDOW) != PERMISSION_GRANTED;
}
- @Override
- public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
- boolean hasStatusBarServicePermission) {
-
- final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
- if (mScreenDecorWindows.contains(win)) {
- if (!isScreenDecor) {
- // No longer has the flag set, so remove from the set.
- mScreenDecorWindows.remove(win);
- }
- } else if (isScreenDecor && hasStatusBarServicePermission) {
- mScreenDecorWindows.add(win);
- }
-
- switch (attrs.type) {
- case TYPE_SYSTEM_OVERLAY:
- case TYPE_SECURE_SYSTEM_OVERLAY:
- // These types of windows can't receive input events.
- attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
- attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
- break;
- case TYPE_DREAM:
- case TYPE_WALLPAPER:
- // Dreams and wallpapers don't have an app window token and can thus not be
- // letterboxed. Hence always let them extend under the cutout.
- attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- break;
- case TYPE_STATUS_BAR:
-
- // If the Keyguard is in a hidden state (occluded by another window), we force to
- // remove the wallpaper and keyguard flag so that any change in-flight after setting
- // the keyguard as occluded wouldn't set these flags again.
- // See {@link #processKeyguardSetHiddenResultLw}.
- if (mKeyguardOccluded) {
- attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
- attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
- }
- break;
-
- case TYPE_SCREENSHOT:
- attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- break;
-
- case TYPE_TOAST:
- // While apps should use the dedicated toast APIs to add such windows
- // it possible legacy apps to add the window directly. Therefore, we
- // make windows added directly by the app behave as a toast as much
- // as possible in terms of timeout and animation.
- if (attrs.hideTimeoutMilliseconds < 0
- || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
- attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
- }
- attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
- break;
- }
-
- if (attrs.type != TYPE_STATUS_BAR) {
- // The status bar is the only window allowed to exhibit keyguard behavior.
- attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
- }
- }
-
- private int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
- int impliedFlags = 0;
- if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
- impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
- }
- final boolean forceWindowDrawsStatusBarBackground =
- (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
- if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
- || forceWindowDrawsStatusBarBackground
- && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT) {
- impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- }
- return impliedFlags;
- }
-
void readLidState() {
mDefaultDisplayPolicy.setLidState(mWindowManagerFuncs.getLidState());
}
@@ -2660,161 +2227,10 @@
}
@Override
- public void onOverlayChangedLw(DisplayContentInfo displayContentInfo) {
- onConfigurationChanged(displayContentInfo);
- }
-
- @Override
- public void onConfigurationChanged(DisplayContentInfo displayContentInfo) {
- final DisplayRotation displayRotation = displayContentInfo.getDisplayRotation();
- // TODO(multi-display): Define policy for secondary displays.
- if (!displayRotation.isDefaultDisplay) {
- return;
- }
-
- final Context uiContext = getSystemUiContext();
- final Resources res = uiContext.getResources();
- final int portraitRotation = displayRotation.getPortraitRotation();
- final int upsideDownRotation = displayRotation.getUpsideDownRotation();
- final int landscapeRotation = displayRotation.getLandscapeRotation();
- final int seascapeRotation = displayRotation.getSeascapeRotation();
-
- mStatusBarHeightForRotation[portraitRotation] =
- mStatusBarHeightForRotation[upsideDownRotation] = res.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height_portrait);
- mStatusBarHeightForRotation[landscapeRotation] =
- mStatusBarHeightForRotation[seascapeRotation] = res.getDimensionPixelSize(
- com.android.internal.R.dimen.status_bar_height_landscape);
-
- // Height of the navigation bar when presented horizontally at bottom
- mNavigationBarHeightForRotationDefault[portraitRotation] =
- mNavigationBarHeightForRotationDefault[upsideDownRotation] =
- res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
- mNavigationBarHeightForRotationDefault[landscapeRotation] =
- mNavigationBarHeightForRotationDefault[seascapeRotation] = res.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_height_landscape);
-
- // Width of the navigation bar when presented vertically along one side
- mNavigationBarWidthForRotationDefault[portraitRotation] =
- mNavigationBarWidthForRotationDefault[upsideDownRotation] =
- mNavigationBarWidthForRotationDefault[landscapeRotation] =
- mNavigationBarWidthForRotationDefault[seascapeRotation] =
- res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
-
- if (ALTERNATE_CAR_MODE_NAV_SIZE) {
- // Height of the navigation bar when presented horizontally at bottom
- mNavigationBarHeightForRotationInCarMode[portraitRotation] =
- mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
- res.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_height_car_mode);
- mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
- mNavigationBarHeightForRotationInCarMode[seascapeRotation] = res.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);
-
- // Width of the navigation bar when presented vertically along one side
- mNavigationBarWidthForRotationInCarMode[portraitRotation] =
- mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
- mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
- mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
- res.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_width_car_mode);
- }
-
- // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
- mExperiments.onConfigurationChanged(uiContext);
- // EXPERIMENT END
- }
-
- @VisibleForTesting
- Context getSystemUiContext() {
- return ActivityThread.currentActivityThread().getSystemUiContext();
- }
-
- @Override
public int getMaxWallpaperLayer() {
return getWindowLayerFromTypeLw(TYPE_STATUS_BAR);
}
- private int getNavigationBarWidth(int rotation, int uiMode) {
- if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
- return mNavigationBarWidthForRotationInCarMode[rotation];
- } else {
- return mNavigationBarWidthForRotationDefault[rotation];
- }
- }
-
- @Override
- public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
- int displayId, DisplayCutout displayCutout) {
- int width = fullWidth;
- // TODO(multi-display): Support navigation bar on secondary displays.
- if (displayId == DEFAULT_DISPLAY && mDefaultDisplayPolicy.hasNavigationBar()) {
- // For a basic navigation bar, when we are in landscape mode we place
- // the navigation bar to the side.
- if (mDefaultDisplayPolicy.navigationBarCanMove() && fullWidth > fullHeight) {
- width -= getNavigationBarWidth(rotation, uiMode);
- }
- }
- if (displayCutout != null) {
- width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
- }
- return width;
- }
-
- private int getNavigationBarHeight(int rotation, int uiMode) {
- if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
- return mNavigationBarHeightForRotationInCarMode[rotation];
- } else {
- return mNavigationBarHeightForRotationDefault[rotation];
- }
- }
-
- @Override
- public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
- int displayId, DisplayCutout displayCutout) {
- int height = fullHeight;
- // TODO(multi-display): Support navigation bar on secondary displays.
- if (displayId == DEFAULT_DISPLAY && mDefaultDisplayPolicy.hasNavigationBar()) {
- // For a basic navigation bar, when we are in portrait mode we place
- // the navigation bar to the bottom.
- if (!mDefaultDisplayPolicy.navigationBarCanMove() || fullWidth < fullHeight) {
- height -= getNavigationBarHeight(rotation, uiMode);
- }
- }
- if (displayCutout != null) {
- height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
- }
- return height;
- }
-
- @Override
- public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
- int displayId, DisplayCutout displayCutout) {
- return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayId,
- displayCutout);
- }
-
- @Override
- public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
- int displayId, DisplayCutout displayCutout) {
- // There is a separate status bar at the top of the display. We don't count that as part
- // of the fixed decor, since it can hide; however, for purposes of configurations,
- // we do want to exclude it since applications can't generally use that part
- // of the screen.
- // TODO(multi-display): Support status bars on secondary displays.
- if (displayId == DEFAULT_DISPLAY) {
- int statusBarHeight = mStatusBarHeightForRotation[rotation];
- if (displayCutout != null) {
- // If there is a cutout, it may already have accounted for some part of the status
- // bar height.
- statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
- }
- return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayId,
- displayCutout) - statusBarHeight;
- }
- return fullHeight;
- }
-
@Override
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
return attrs.type == TYPE_STATUS_BAR;
@@ -3054,251 +2470,6 @@
return context.createDisplayContext(targetDisplay);
}
- /**
- * Preflight adding a window to the system.
- *
- * Currently enforces that three window types are singletons:
- * <ul>
- * <li>STATUS_BAR_TYPE</li>
- * <li>KEYGUARD_TYPE</li>
- * </ul>
- *
- * @param win The window to be added
- * @param attrs Information about the window to be added
- *
- * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
- * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
- */
- @Override
- public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
-
- if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.STATUS_BAR_SERVICE,
- "PhoneWindowManager");
- mScreenDecorWindows.add(win);
- }
-
- switch (attrs.type) {
- case TYPE_STATUS_BAR:
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.STATUS_BAR_SERVICE,
- "PhoneWindowManager");
- if (mStatusBar != null) {
- if (mStatusBar.isAlive()) {
- return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
- }
- }
- mStatusBar = win;
- mStatusBarController.setWindow(win);
- setKeyguardOccludedLw(mKeyguardOccluded, true /* force */);
- break;
- case TYPE_NAVIGATION_BAR:
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.STATUS_BAR_SERVICE,
- "PhoneWindowManager");
- if (mNavigationBar != null) {
- if (mNavigationBar.isAlive()) {
- return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
- }
- }
- mNavigationBar = win;
- mNavigationBarController.setWindow(win);
- mNavigationBarController.setOnBarVisibilityChangedListener(
- mNavBarVisibilityListener, true);
- if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
- break;
- case TYPE_NAVIGATION_BAR_PANEL:
- case TYPE_STATUS_BAR_PANEL:
- case TYPE_STATUS_BAR_SUB_PANEL:
- case TYPE_VOICE_INTERACTION_STARTING:
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.STATUS_BAR_SERVICE,
- "PhoneWindowManager");
- break;
- }
- return ADD_OKAY;
- }
-
- /** {@inheritDoc} */
- @Override
- public void removeWindowLw(WindowState win) {
- if (mStatusBar == win) {
- mStatusBar = null;
- mStatusBarController.setWindow(null);
- } else if (mNavigationBar == win) {
- mNavigationBar = null;
- mNavigationBarController.setWindow(null);
- }
- if (mLastFocusedWindow == win) {
- mLastFocusedWindow = null;
- }
- mScreenDecorWindows.remove(win);
- }
-
- static final boolean PRINT_ANIM = false;
-
- /** {@inheritDoc} */
- @Override
- public int selectAnimationLw(WindowState win, int transit) {
- if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win
- + ": transit=" + transit);
- if (win == mStatusBar) {
- final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
- final boolean expanded = win.getAttrs().height == MATCH_PARENT
- && win.getAttrs().width == MATCH_PARENT;
- if (isKeyguard || expanded) {
- return -1;
- }
- if (transit == TRANSIT_EXIT
- || transit == TRANSIT_HIDE) {
- return R.anim.dock_top_exit;
- } else if (transit == TRANSIT_ENTER
- || transit == TRANSIT_SHOW) {
- return R.anim.dock_top_enter;
- }
- } else if (win == mNavigationBar) {
- if (win.getAttrs().windowAnimations != 0) {
- return 0;
- }
- // This can be on either the bottom or the right or the left.
- if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
- if (transit == TRANSIT_EXIT
- || transit == TRANSIT_HIDE) {
- if (isKeyguardShowingAndNotOccluded()) {
- return R.anim.dock_bottom_exit_keyguard;
- } else {
- return R.anim.dock_bottom_exit;
- }
- } else if (transit == TRANSIT_ENTER
- || transit == TRANSIT_SHOW) {
- return R.anim.dock_bottom_enter;
- }
- } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
- if (transit == TRANSIT_EXIT
- || transit == TRANSIT_HIDE) {
- return R.anim.dock_right_exit;
- } else if (transit == TRANSIT_ENTER
- || transit == TRANSIT_SHOW) {
- return R.anim.dock_right_enter;
- }
- } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
- if (transit == TRANSIT_EXIT
- || transit == TRANSIT_HIDE) {
- return R.anim.dock_left_exit;
- } else if (transit == TRANSIT_ENTER
- || transit == TRANSIT_SHOW) {
- return R.anim.dock_left_enter;
- }
- }
- } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
- return selectDockedDividerAnimationLw(win, transit);
- }
-
- if (transit == TRANSIT_PREVIEW_DONE) {
- if (win.hasAppShownWindows()) {
- if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT");
- return com.android.internal.R.anim.app_starting_exit;
- }
- } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
- && transit == TRANSIT_ENTER) {
- // Special case: we are animating in a dream, while the keyguard
- // is shown. We don't want an animation on the dream, because
- // we need it shown immediately with the keyguard animating away
- // to reveal it.
- return -1;
- }
-
- return 0;
- }
-
- private int selectDockedDividerAnimationLw(WindowState win, int transit) {
- int insets = mWindowManagerFuncs.getDockedDividerInsetsLw();
-
- // If the divider is behind the navigation bar, don't animate.
- final Rect frame = win.getFrameLw();
- final boolean behindNavBar = mNavigationBar != null
- && ((mNavigationBarPosition == NAV_BAR_BOTTOM
- && frame.top + insets >= mNavigationBar.getFrameLw().top)
- || (mNavigationBarPosition == NAV_BAR_RIGHT
- && frame.left + insets >= mNavigationBar.getFrameLw().left)
- || (mNavigationBarPosition == NAV_BAR_LEFT
- && frame.right - insets <= mNavigationBar.getFrameLw().right));
- final boolean landscape = frame.height() > frame.width();
- final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
- || frame.left + insets >= win.getDisplayFrameLw().right);
- final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
- || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
- final boolean offscreen = offscreenLandscape || offscreenPortrait;
- if (behindNavBar || offscreen) {
- return 0;
- }
- if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
- return R.anim.fade_in;
- } else if (transit == TRANSIT_EXIT) {
- return R.anim.fade_out;
- } else {
- return 0;
- }
- }
-
- @Override
- public void selectRotationAnimationLw(int anim[]) {
- // If the screen is off or non-interactive, force a jumpcut.
- final boolean forceJumpcut = !mDefaultDisplayPolicy.isScreenOnFully() || !okToAnimate();
- if (PRINT_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
- + mTopFullscreenOpaqueWindowState + " rotationAnimation="
- + (mTopFullscreenOpaqueWindowState == null ?
- "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation)
- + " forceJumpcut=" + forceJumpcut);
- if (forceJumpcut) {
- anim[0] = R.anim.rotation_animation_jump_exit;
- anim[1] = R.anim.rotation_animation_enter;
- return;
- }
- if (mTopFullscreenOpaqueWindowState != null) {
- int animationHint = mTopFullscreenOpaqueWindowState.getRotationAnimationHint();
- if (animationHint < 0 && mTopIsFullscreen) {
- animationHint = mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation;
- }
- switch (animationHint) {
- case ROTATION_ANIMATION_CROSSFADE:
- case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless.
- anim[0] = R.anim.rotation_animation_xfade_exit;
- anim[1] = R.anim.rotation_animation_enter;
- break;
- case ROTATION_ANIMATION_JUMPCUT:
- anim[0] = R.anim.rotation_animation_jump_exit;
- anim[1] = R.anim.rotation_animation_enter;
- break;
- case ROTATION_ANIMATION_ROTATE:
- default:
- anim[0] = anim[1] = 0;
- break;
- }
- } else {
- anim[0] = anim[1] = 0;
- }
- }
-
- @Override
- public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
- boolean forceDefault) {
- switch (exitAnimId) {
- case R.anim.rotation_animation_xfade_exit:
- case R.anim.rotation_animation_jump_exit:
- // These are the only cases that matter.
- if (forceDefault) {
- return false;
- }
- int anim[] = new int[2];
- selectRotationAnimationLw(anim);
- return (exitAnimId == anim[0] && enterAnimId == anim[1]);
- default:
- return true;
- }
- }
-
@Override
public Animation createHiddenByKeyguardExit(boolean onWallpaper,
boolean goingToNotificationShade) {
@@ -4173,77 +3344,6 @@
}
}
- private final Runnable mClearHideNavigationFlag = new Runnable() {
- @Override
- public void run() {
- synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
- // Clear flags.
- mForceClearedSystemUiFlags &=
- ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
- }
- mWindowManagerFuncs.reevaluateStatusBarVisibility();
- }
- };
-
- /**
- * Input handler used while nav bar is hidden. Captures any touch on the screen,
- * to determine when the nav bar should be shown and prevent applications from
- * receiving those touches.
- */
- final class HideNavInputEventReceiver extends InputEventReceiver {
- public HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
- super(inputChannel, looper);
- }
-
- @Override
- public void onInputEvent(InputEvent event) {
- boolean handled = false;
- try {
- if (event instanceof MotionEvent
- && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
- final MotionEvent motionEvent = (MotionEvent)event;
- if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
- // When the user taps down, we re-show the nav bar.
- boolean changed = false;
- synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
- if (mInputConsumer == null) {
- return;
- }
- // Any user activity always causes us to show the
- // navigation controls, if they had been hidden.
- // We also clear the low profile and only content
- // flags so that tapping on the screen will atomically
- // restore all currently hidden screen decorations.
- int newVal = mResettingSystemUiFlags |
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
- View.SYSTEM_UI_FLAG_LOW_PROFILE |
- View.SYSTEM_UI_FLAG_FULLSCREEN;
- if (mResettingSystemUiFlags != newVal) {
- mResettingSystemUiFlags = newVal;
- changed = true;
- }
- // We don't allow the system's nav bar to be hidden
- // again for 1 second, to prevent applications from
- // spamming us and keeping it from being shown.
- newVal = mForceClearedSystemUiFlags |
- View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
- if (mForceClearedSystemUiFlags != newVal) {
- mForceClearedSystemUiFlags = newVal;
- changed = true;
- mHandler.postDelayed(mClearHideNavigationFlag, 1000);
- }
- }
- if (changed) {
- mWindowManagerFuncs.reevaluateStatusBarVisibility();
- }
- }
- }
- } finally {
- finishInputEvent(event, handled);
- }
- }
- }
-
@Override
public void setRecentsVisibilityLw(boolean visible) {
mRecentsVisible = visible;
@@ -4259,1177 +3359,9 @@
mNavBarVirtualKeyHapticFeedbackEnabled = enabled;
}
- @Override
- public int adjustSystemUiVisibilityLw(int visibility) {
- mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
- mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
-
- // Reset any bits in mForceClearingStatusBarVisibility that
- // are now clear.
- mResettingSystemUiFlags &= visibility;
- // Clear any bits in the new visibility that are currently being
- // force cleared, before reporting it.
- return visibility & ~mResettingSystemUiFlags
- & ~mForceClearedSystemUiFlags;
- }
-
- @Override
- // TODO: Should probably be moved into DisplayFrames.
- public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
- DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
- Rect outContentInsets, Rect outStableInsets,
- Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
- final int fl = PolicyControl.getWindowFlags(null, attrs);
- final int pfl = attrs.privateFlags;
- final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
- final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
- final int displayRotation = displayFrames.mRotation;
-
- final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
- if (useOutsets) {
- int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
- if (outset > 0) {
- if (displayRotation == Surface.ROTATION_0) {
- outOutsets.bottom += outset;
- } else if (displayRotation == Surface.ROTATION_90) {
- outOutsets.right += outset;
- } else if (displayRotation == Surface.ROTATION_180) {
- outOutsets.top += outset;
- } else if (displayRotation == Surface.ROTATION_270) {
- outOutsets.left += outset;
- }
- }
- }
-
- final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
- final boolean layoutInScreenAndInsetDecor = layoutInScreen &&
- (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
- final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
-
- if (layoutInScreenAndInsetDecor && !screenDecor) {
- if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
- outFrame.set(displayFrames.mUnrestricted);
- } else {
- outFrame.set(displayFrames.mRestricted);
- }
-
- final Rect sf;
- if (floatingStack) {
- sf = null;
- } else {
- sf = displayFrames.mStable;
- }
-
- final Rect cf;
- if (floatingStack) {
- cf = null;
- } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
- if ((fl & FLAG_FULLSCREEN) != 0) {
- cf = displayFrames.mStableFullscreen;
- } else {
- cf = displayFrames.mStable;
- }
- } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
- cf = displayFrames.mOverscan;
- } else {
- cf = displayFrames.mCurrent;
- }
-
- if (taskBounds != null) {
- outFrame.intersect(taskBounds);
- }
- InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
- InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
- outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
- .getDisplayCutout());
- return mForceShowSystemBars;
- } else {
- if (layoutInScreen) {
- outFrame.set(displayFrames.mUnrestricted);
- } else {
- outFrame.set(displayFrames.mStable);
- }
- if (taskBounds != null) {
- outFrame.intersect(taskBounds);
- }
-
- outContentInsets.setEmpty();
- outStableInsets.setEmpty();
- outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
- return mForceShowSystemBars;
- }
- }
-
- private boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
- return attrs.type == TYPE_WALLPAPER || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0;
- }
-
/** {@inheritDoc} */
@Override
- public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
- displayFrames.onBeginLayout();
- // TODO(multi-display): This doesn't seem right...Maybe only apply to default display?
- mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
- mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
- mDockLayer = 0x10000000;
- mStatusBarLayer = -1;
-
- if (displayFrames.mDisplayId == DEFAULT_DISPLAY) {
- // For purposes of putting out fake window up to steal focus, we will
- // drive nav being hidden only by whether it is requested.
- final int sysui = mLastSystemUiFlags;
- boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
- boolean navTranslucent = (sysui
- & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
- boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
- boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
- boolean navAllowedHidden = immersive || immersiveSticky;
- navTranslucent &= !immersiveSticky; // transient trumps translucent
- boolean isKeyguardShowing = isStatusBarKeyguard() && !mKeyguardOccluded;
- if (!isKeyguardShowing) {
- navTranslucent &= areTranslucentBarsAllowed();
- }
- boolean statusBarForcesShowingNavigation = !isKeyguardShowing && mStatusBar != null
- && (mStatusBar.getAttrs().privateFlags
- & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
-
- // When the navigation bar isn't visible, we put up a fake input window to catch all
- // touch events. This way we can detect when the user presses anywhere to bring back the
- // nav bar and ensure the application doesn't see the event.
- if (navVisible || navAllowedHidden) {
- if (mInputConsumer != null) {
- mHandler.sendMessage(
- mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
- mInputConsumer = null;
- }
- } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
- mInputConsumer = mWindowManagerFuncs.createInputConsumer(mHandler.getLooper(),
- INPUT_CONSUMER_NAVIGATION,
- (channel, looper) -> new HideNavInputEventReceiver(channel, looper),
- displayFrames.mDisplayId);
- // As long as mInputConsumer is active, hover events are not dispatched to the app
- // and the pointer icon is likely to become stale. Hide it to avoid confusion.
- InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
- }
-
- // For purposes of positioning and showing the nav bar, if we have decided that it can't
- // be hidden (because of the screen aspect ratio), then take that into account.
- navVisible |= !canHideNavigationBar();
-
- boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
- navTranslucent, navAllowedHidden, statusBarForcesShowingNavigation);
- if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
- updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
- if (updateSysUiVisibility) {
- updateSystemUiVisibilityLw();
- }
- }
- layoutScreenDecorWindows(displayFrames);
-
- if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
- // Make sure that the zone we're avoiding for the cutout is at least as tall as the
- // status bar; otherwise fullscreen apps will end up cutting halfway into the status
- // bar.
- displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
- displayFrames.mStable.top);
- }
- }
-
- private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
- if (mScreenDecorWindows.isEmpty()) {
- return;
- }
-
- sTmpRect.setEmpty();
- sTmpDockedFrame.set(displayFrames.mDock);
-
- final int displayId = displayFrames.mDisplayId;
- final Rect dockFrame = displayFrames.mDock;
- final int displayHeight = displayFrames.mDisplayHeight;
- final int displayWidth = displayFrames.mDisplayWidth;
-
- for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
- final WindowState w = mScreenDecorWindows.valueAt(i);
- if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
- // Skip if not on the same display or not visible.
- continue;
- }
-
- w.getWindowFrames().setFrames(sTmpDockedFrame /* parentFrame */,
- sTmpDockedFrame /* displayFrame */, sTmpDockedFrame /* overscanFrame */,
- sTmpDockedFrame /* contentFrame */, sTmpDockedFrame /* visibleFrame */,
- sTmpRect /* decorFrame */, sTmpDockedFrame /* stableFrame */,
- sTmpDockedFrame /* outsetFrame */);
- w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
- w.computeFrameLw();
- final Rect frame = w.getFrameLw();
-
- if (frame.left <= 0 && frame.top <= 0) {
- // Docked at left or top.
- if (frame.bottom >= displayHeight) {
- // Docked left.
- dockFrame.left = Math.max(frame.right, dockFrame.left);
- } else if (frame.right >= displayWidth ) {
- // Docked top.
- dockFrame.top = Math.max(frame.bottom, dockFrame.top);
- } else {
- Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
- + " not docked on left or top of display. frame=" + frame
- + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
- }
- } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
- // Docked at right or bottom.
- if (frame.top <= 0) {
- // Docked right.
- dockFrame.right = Math.min(frame.left, dockFrame.right);
- } else if (frame.left <= 0) {
- // Docked bottom.
- dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
- } else {
- Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
- + " not docked on right or bottom" + " of display. frame=" + frame
- + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
- }
- } else {
- // Screen decor windows are required to be docked on one of the sides of the screen.
- Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
- + " not docked on one of the sides of the display. frame=" + frame
- + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
- }
- }
-
- displayFrames.mRestricted.set(dockFrame);
- displayFrames.mCurrent.set(dockFrame);
- displayFrames.mVoiceContent.set(dockFrame);
- displayFrames.mSystem.set(dockFrame);
- displayFrames.mContent.set(dockFrame);
- displayFrames.mRestrictedOverscan.set(dockFrame);
- }
-
- private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
- boolean isKeyguardShowing) {
- // decide where the status bar goes ahead of time
- if (mStatusBar == null) {
- return false;
- }
- // apply any navigation bar insets
- sTmpRect.setEmpty();
- mStatusBar.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
- displayFrames.mUnrestricted /* displayFrame */,
- displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
- displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
- displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
- mStatusBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
- mStatusBarLayer = mStatusBar.getSurfaceLayer();
-
- // Let the status bar determine its size.
- mStatusBar.computeFrameLw();
-
- // For layout, the status bar is always at the top with our fixed height.
- displayFrames.mStable.top = displayFrames.mUnrestricted.top
- + mStatusBarHeightForRotation[displayFrames.mRotation];
- // Make sure the status bar covers the entire cutout height
- displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
- displayFrames.mDisplayCutoutSafe.top);
-
- // Tell the bar controller where the collapsed status bar content is
- sTmpRect.set(mStatusBar.getContentFrameLw());
- sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
- sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
- sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
- mStatusBarController.setContentFrame(sTmpRect);
-
- boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
- boolean statusBarTranslucent = (sysui
- & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
- if (!isKeyguardShowing) {
- statusBarTranslucent &= areTranslucentBarsAllowed();
- }
-
- // If the status bar is hidden, we don't want to cause windows behind it to scroll.
- if (mStatusBar.isVisibleLw() && !statusBarTransient) {
- // Status bar may go away, so the screen area it occupies is available to apps but just
- // covering them when the status bar is visible.
- final Rect dockFrame = displayFrames.mDock;
- dockFrame.top = displayFrames.mStable.top;
- displayFrames.mContent.set(dockFrame);
- displayFrames.mVoiceContent.set(dockFrame);
- displayFrames.mCurrent.set(dockFrame);
-
- if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
- "dock=%s content=%s cur=%s", dockFrame.toString(),
- displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
-
- if (!mStatusBar.isAnimatingLw() && !statusBarTranslucent
- && !mStatusBarController.wasRecentlyTranslucent()) {
- // If the opaque status bar is currently requested to be visible, and not in the
- // process of animating on or off, then we can tell the app that it is covered by it.
- displayFrames.mSystem.top = displayFrames.mStable.top;
- }
- }
- return mStatusBarController.checkHiddenLw();
- }
-
- private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
- boolean navTranslucent, boolean navAllowedHidden,
- boolean statusBarForcesShowingNavigation) {
- if (mNavigationBar == null) {
- return false;
- }
-
- final Rect navigationFrame = sTmpNavFrame;
- boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
- // Force the navigation bar to its appropriate place and size. We need to do this directly,
- // instead of relying on it to bubble up from the nav bar, because this needs to change
- // atomically with screen rotations.
- final int rotation = displayFrames.mRotation;
- final int displayHeight = displayFrames.mDisplayHeight;
- final int displayWidth = displayFrames.mDisplayWidth;
- final Rect dockFrame = displayFrames.mDock;
- mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
-
- final Rect cutoutSafeUnrestricted = sTmpRect;
- cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
- cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
-
- if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
- // It's a system nav bar or a portrait screen; nav bar goes on bottom.
- final int top = cutoutSafeUnrestricted.bottom
- - getNavigationBarHeight(rotation, uiMode);
- // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
- final int topNavBar = cutoutSafeUnrestricted.bottom
- - mExperiments.getNavigationBarFrameHeight();
- navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
- // EXPERIMENT END
- displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
- if (transientNavBarShowing) {
- mNavigationBarController.setBarShowingLw(true);
- } else if (navVisible) {
- mNavigationBarController.setBarShowingLw(true);
- dockFrame.bottom = displayFrames.mRestricted.bottom
- = displayFrames.mRestrictedOverscan.bottom = top;
- } else {
- // We currently want to hide the navigation UI - unless we expanded the status bar.
- mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
- }
- if (navVisible && !navTranslucent && !navAllowedHidden
- && !mNavigationBar.isAnimatingLw()
- && !mNavigationBarController.wasRecentlyTranslucent()) {
- // If the opaque nav bar is currently requested to be visible and not in the process
- // of animating on or off, then we can tell the app that it is covered by it.
- displayFrames.mSystem.bottom = top;
- }
- } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
- // Landscape screen; nav bar goes to the right.
- final int left = cutoutSafeUnrestricted.right
- - getNavigationBarWidth(rotation, uiMode);
- // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
- final int leftNavBar = cutoutSafeUnrestricted.right
- - mExperiments.getNavigationBarFrameWidth();
- navigationFrame.set(leftNavBar, 0, displayFrames.mUnrestricted.right, displayHeight);
- // EXPERIMENT END
- displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
- if (transientNavBarShowing) {
- mNavigationBarController.setBarShowingLw(true);
- } else if (navVisible) {
- mNavigationBarController.setBarShowingLw(true);
- dockFrame.right = displayFrames.mRestricted.right
- = displayFrames.mRestrictedOverscan.right = left;
- } else {
- // We currently want to hide the navigation UI - unless we expanded the status bar.
- mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
- }
- if (navVisible && !navTranslucent && !navAllowedHidden
- && !mNavigationBar.isAnimatingLw()
- && !mNavigationBarController.wasRecentlyTranslucent()) {
- // If the nav bar is currently requested to be visible, and not in the process of
- // animating on or off, then we can tell the app that it is covered by it.
- displayFrames.mSystem.right = left;
- }
- } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
- // Seascape screen; nav bar goes to the left.
- final int right = cutoutSafeUnrestricted.left
- + getNavigationBarWidth(rotation, uiMode);
- // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
- final int rightNavBar = cutoutSafeUnrestricted.left
- + mExperiments.getNavigationBarFrameWidth();
- navigationFrame.set(displayFrames.mUnrestricted.left, 0, rightNavBar, displayHeight);
- // EXPERIMENT END
- displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
- if (transientNavBarShowing) {
- mNavigationBarController.setBarShowingLw(true);
- } else if (navVisible) {
- mNavigationBarController.setBarShowingLw(true);
- dockFrame.left = displayFrames.mRestricted.left =
- displayFrames.mRestrictedOverscan.left = right;
- } else {
- // We currently want to hide the navigation UI - unless we expanded the status bar.
- mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
- }
- if (navVisible && !navTranslucent && !navAllowedHidden
- && !mNavigationBar.isAnimatingLw()
- && !mNavigationBarController.wasRecentlyTranslucent()) {
- // If the nav bar is currently requested to be visible, and not in the process of
- // animating on or off, then we can tell the app that it is covered by it.
- displayFrames.mSystem.left = right;
- }
- }
-
- // Make sure the content and current rectangles are updated to account for the restrictions
- // from the navigation bar.
- displayFrames.mCurrent.set(dockFrame);
- displayFrames.mVoiceContent.set(dockFrame);
- displayFrames.mContent.set(dockFrame);
- mStatusBarLayer = mNavigationBar.getSurfaceLayer();
- // And compute the final frame.
- sTmpRect.setEmpty();
- mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
- navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
- displayFrames.mDisplayCutoutSafe /* contentFrame */,
- navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
- navigationFrame /* stableFrame */,
- displayFrames.mDisplayCutoutSafe /* outsetFrame */);
- mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
- mNavigationBar.computeFrameLw();
- mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
-
- if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
- return mNavigationBarController.checkHiddenLw();
- }
-
- @NavigationBarPosition
- private int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
- if (mDefaultDisplayPolicy.navigationBarCanMove() && displayWidth > displayHeight) {
- if (displayRotation == Surface.ROTATION_270) {
- return NAV_BAR_LEFT;
- } else {
- return NAV_BAR_RIGHT;
- }
- }
- return NAV_BAR_BOTTOM;
- }
-
- /** {@inheritDoc} */
- @Override
- public int getSystemDecorLayerLw() {
- if (mStatusBar != null && mStatusBar.isVisibleLw()) {
- return mStatusBar.getSurfaceLayer();
- }
-
- if (mNavigationBar != null && mNavigationBar.isVisibleLw()) {
- return mNavigationBar.getSurfaceLayer();
- }
-
- return 0;
- }
-
- private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
- boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
- DisplayFrames displayFrames) {
- if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
- // Here's a special case: if the child window is not the 'dock window'
- // or input method target, and the window it is attached to is below
- // the dock window, then the frames we computed for the window it is
- // attached to can not be used because the dock is effectively part
- // of the underlying window and the attached window is floating on top
- // of the whole thing. So, we ignore the attached window and explicitly
- // compute the frames that would be appropriate without the dock.
- vf.set(displayFrames.mDock);
- cf.set(displayFrames.mDock);
- of.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- } else {
- // The effective display frame of the attached window depends on whether it is taking
- // care of insetting its content. If not, we need to use the parent's content frame so
- // that the entire window is positioned within that content. Otherwise we can use the
- // overscan frame and let the attached window take care of positioning its content
- // appropriately.
- if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- // Set the content frame of the attached window to the parent's decor frame
- // (same as content frame when IME isn't present) if specifically requested by
- // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
- // Otherwise, use the overscan frame.
- cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
- ? attached.getContentFrameLw() : attached.getOverscanFrameLw());
- } else {
- // If the window is resizing, then we want to base the content frame on our attached
- // content frame to resize...however, things can be tricky if the attached window is
- // NOT in resize mode, in which case its content frame will be larger.
- // Ungh. So to deal with that, make sure the content frame we end up using is not
- // covering the IM dock.
- cf.set(attached.getContentFrameLw());
- if (attached.isVoiceInteraction()) {
- cf.intersectUnchecked(displayFrames.mVoiceContent);
- } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
- cf.intersectUnchecked(displayFrames.mContent);
- }
- }
- df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
- of.set(insetDecors ? attached.getOverscanFrameLw() : cf);
- vf.set(attached.getVisibleFrameLw());
- }
- // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
- // positioned relative to its parent or the entire screen.
- pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
- }
-
- private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
- if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
- return;
- }
- // If app is requesting a stable layout, don't let the content insets go below the stable
- // values.
- if ((fl & FLAG_FULLSCREEN) != 0) {
- r.intersectUnchecked(displayFrames.mStableFullscreen);
- } else {
- r.intersectUnchecked(displayFrames.mStable);
- }
- }
-
- private boolean canReceiveInput(WindowState win) {
- boolean notFocusable =
- (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
- boolean altFocusableIm =
- (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
- boolean notFocusableForIm = notFocusable ^ altFocusableIm;
- return !notFocusableForIm;
- }
-
- /** {@inheritDoc} */
- @Override
- public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
- // We've already done the navigation bar, status bar, and all screen decor windows. If the
- // status bar can receive input, we need to layout it again to accommodate for the IME
- // window.
- if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
- || mScreenDecorWindows.contains(win)) {
- return;
- }
- final WindowManager.LayoutParams attrs = win.getAttrs();
- final boolean isDefaultDisplay = win.isDefaultDisplay();
-
- final int type = attrs.type;
- final int fl = PolicyControl.getWindowFlags(win, attrs);
- final int pfl = attrs.privateFlags;
- final int sim = attrs.softInputMode;
- final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
- final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
-
- final WindowFrames windowFrames = win.getWindowFrames();
-
- windowFrames.setHasOutsets(false);
- sTmpLastParentFrame.set(windowFrames.mParentFrame);
- final Rect pf = windowFrames.mParentFrame;
- final Rect df = windowFrames.mDisplayFrame;
- final Rect of = windowFrames.mOverscanFrame;
- final Rect cf = windowFrames.mContentFrame;
- final Rect vf = windowFrames.mVisibleFrame;
- final Rect dcf = windowFrames.mDecorFrame;
- final Rect sf = windowFrames.mStableFrame;
- dcf.setEmpty();
- windowFrames.setParentFrameWasClippedByDisplayCutout(false);
- windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
-
- final boolean hasNavBar = (isDefaultDisplay && mDefaultDisplayPolicy.hasNavigationBar()
- && mNavigationBar != null && mNavigationBar.isVisibleLw());
-
- final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
-
- final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
- || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
-
- final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
- final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
-
- sf.set(displayFrames.mStable);
-
- if (type == TYPE_INPUT_METHOD) {
- vf.set(displayFrames.mDock);
- cf.set(displayFrames.mDock);
- of.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- windowFrames.mParentFrame.set(displayFrames.mDock);
- // IM dock windows layout below the nav bar...
- pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
- // ...with content insets above the nav bar
- cf.bottom = vf.bottom = displayFrames.mStable.bottom;
- // TODO (b/111364446): Support showing IME on non-default displays
- if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
- // The status bar forces the navigation bar while it's visible. Make sure the IME
- // avoids the navigation bar in that case.
- if (mNavigationBarPosition == NAV_BAR_RIGHT) {
- pf.right = df.right = of.right = cf.right = vf.right =
- displayFrames.mStable.right;
- } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
- pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left;
- }
- }
-
- // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
- // Offset the ime to avoid overlapping with the nav bar
- mExperiments.offsetWindowFramesForNavBar(mNavigationBarPosition, win);
- // EXPERIMENT END
-
- // IM dock windows always go to the bottom of the screen.
- attrs.gravity = Gravity.BOTTOM;
- mDockLayer = win.getSurfaceLayer();
- } else if (type == TYPE_VOICE_INTERACTION) {
- of.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- } else if (type == TYPE_WALLPAPER) {
- layoutWallpaper(displayFrames, pf, df, of, cf);
- } else if (win == mStatusBar) {
- of.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- cf.set(displayFrames.mStable);
- vf.set(displayFrames.mStable);
-
- if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
- cf.bottom = displayFrames.mContent.bottom;
- } else {
- cf.bottom = displayFrames.mDock.bottom;
- vf.bottom = displayFrames.mContent.bottom;
- }
- } else {
- dcf.set(displayFrames.mSystem);
- final boolean inheritTranslucentDecor =
- (attrs.privateFlags & PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
- final boolean isAppWindow =
- type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
- final boolean topAtRest =
- win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
- if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
- if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
- && (fl & FLAG_FULLSCREEN) == 0
- && (fl & FLAG_TRANSLUCENT_STATUS) == 0
- && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
- && (pfl & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) == 0) {
- // Ensure policy decor includes status bar
- dcf.top = displayFrames.mStable.top;
- }
- if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
- && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
- && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
- // Ensure policy decor includes navigation bar
- dcf.bottom = displayFrames.mStable.bottom;
- dcf.right = displayFrames.mStable.right;
- }
- }
-
- if (layoutInScreen && layoutInsetDecor) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): IN_SCREEN, INSET_DECOR");
- // This is the case for a normal activity window: we want it to cover all of the
- // screen space, and it can take care of moving its contents to account for screen
- // decorations that intrude into that space.
- if (attached != null) {
- // If this window is attached to another, our display
- // frame is the same as the one we are attached to.
- setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf,
- displayFrames);
- } else {
- if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
- // Status bar panels are the only windows who can go on top of the status
- // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
- // have the same privileges as the status bar itself.
- //
- // However, they should still dodge the navigation bar if it exists.
-
- pf.left = df.left = of.left = hasNavBar
- ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
- pf.top = df.top = of.top = displayFrames.mUnrestricted.top;
- pf.right = df.right = of.right = hasNavBar
- ? displayFrames.mRestricted.right
- : displayFrames.mUnrestricted.right;
- pf.bottom = df.bottom = of.bottom = hasNavBar
- ? displayFrames.mRestricted.bottom
- : displayFrames.mUnrestricted.bottom;
-
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
- } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
- && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
- // Asking to layout into the overscan region, so give it that pure
- // unrestricted area.
- of.set(displayFrames.mOverscan);
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
- } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
- || type == TYPE_VOLUME_OVERLAY)) {
- // Asking for layout as if the nav bar is hidden, lets the application
- // extend into the unrestricted overscan screen area. We only do this for
- // application windows and certain system windows to ensure no window that
- // can be above the nav bar can do this.
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
- // We need to tell the app about where the frame inside the overscan is, so
- // it can inset its content by that amount -- it didn't ask to actually
- // extend itself into the overscan region.
- of.set(displayFrames.mUnrestricted);
- } else {
- df.set(displayFrames.mRestrictedOverscan);
- pf.set(displayFrames.mRestrictedOverscan);
- // We need to tell the app about where the frame inside the overscan
- // is, so it can inset its content by that amount -- it didn't ask
- // to actually extend itself into the overscan region.
- of.set(displayFrames.mUnrestricted);
- }
-
- if ((fl & FLAG_FULLSCREEN) == 0) {
- if (win.isVoiceInteraction()) {
- cf.set(displayFrames.mVoiceContent);
- } else {
- if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- }
- } else {
- // Full screen windows are always given a layout that is as if the status
- // bar and other transient decors are gone. This is to avoid bad states when
- // moving from a window that is not hiding the status bar to one that is.
- cf.set(displayFrames.mRestricted);
- }
- applyStableConstraints(sysUiFl, fl, cf, displayFrames);
- if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
-
- // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
- mExperiments.offsetWindowFramesForNavBar(mNavigationBarPosition, win);
- // EXPERIMENT END
- }
- } else if (layoutInScreen || (sysUiFl
- & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): IN_SCREEN");
- // A window that has requested to fill the entire screen just
- // gets everything, period.
- if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
- cf.set(displayFrames.mUnrestricted);
- of.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (hasNavBar) {
- pf.left = df.left = of.left = cf.left = displayFrames.mDock.left;
- pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right;
- pf.bottom = df.bottom = of.bottom = cf.bottom =
- displayFrames.mRestricted.bottom;
- }
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
- } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
- // The navigation bar has Real Ultimate Power.
- of.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
- } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
- && ((fl & FLAG_FULLSCREEN) != 0)) {
- // Fullscreen secure system overlays get what they ask for. Screenshot region
- // selection overlay should also expand to full screen.
- cf.set(displayFrames.mOverscan);
- of.set(displayFrames.mOverscan);
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
- } else if (type == TYPE_BOOT_PROGRESS) {
- // Boot progress screen always covers entire display.
- cf.set(displayFrames.mOverscan);
- of.set(displayFrames.mOverscan);
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
- } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
- && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
- // Asking to layout into the overscan region, so give it that pure unrestricted
- // area.
- cf.set(displayFrames.mOverscan);
- of.set(displayFrames.mOverscan);
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
- } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
- && (type == TYPE_STATUS_BAR
- || type == TYPE_TOAST
- || type == TYPE_DOCK_DIVIDER
- || type == TYPE_VOICE_INTERACTION_STARTING
- || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
- // Asking for layout as if the nav bar is hidden, lets the
- // application extend into the unrestricted screen area. We
- // only do this for application windows (or toasts) to ensure no window that
- // can be above the nav bar can do this.
- // XXX This assumes that an app asking for this will also
- // ask for layout in only content. We can't currently figure out
- // what the screen would be if only laying out to hide the nav bar.
- cf.set(displayFrames.mUnrestricted);
- of.set(displayFrames.mUnrestricted);
- df.set(displayFrames.mUnrestricted);
- pf.set(displayFrames.mUnrestricted);
- } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
- of.set(displayFrames.mRestricted);
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- }
- } else {
- cf.set(displayFrames.mRestricted);
- of.set(displayFrames.mRestricted);
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- }
-
- applyStableConstraints(sysUiFl, fl, cf,displayFrames);
-
- if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- } else if (attached != null) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
- + "): attached to " + attached);
- // A child window should be placed inside of the same visible
- // frame that its parent had.
- setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf,
- displayFrames);
- } else {
- if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() +
- "): normal window");
- // Otherwise, a normal window must be placed inside the content
- // of all screen decorations.
- if (type == TYPE_STATUS_BAR_PANEL) {
- // Status bar panels can go on
- // top of the status bar. They are protected by the STATUS_BAR_SERVICE
- // permission, so they have the same privileges as the status bar itself.
- cf.set(displayFrames.mRestricted);
- of.set(displayFrames.mRestricted);
- df.set(displayFrames.mRestricted);
- pf.set(displayFrames.mRestricted);
- } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
- // These dialogs are stable to interim decor changes.
- cf.set(displayFrames.mStable);
- of.set(displayFrames.mStable);
- df.set(displayFrames.mStable);
- pf.set(displayFrames.mStable);
- } else {
- pf.set(displayFrames.mContent);
- if (win.isVoiceInteraction()) {
- cf.set(displayFrames.mVoiceContent);
- of.set(displayFrames.mVoiceContent);
- df.set(displayFrames.mVoiceContent);
- } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
- cf.set(displayFrames.mDock);
- of.set(displayFrames.mDock);
- df.set(displayFrames.mDock);
- } else {
- cf.set(displayFrames.mContent);
- of.set(displayFrames.mContent);
- df.set(displayFrames.mContent);
- }
- if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
- vf.set(displayFrames.mCurrent);
- } else {
- vf.set(cf);
- }
- }
- }
- }
-
- final int cutoutMode = attrs.layoutInDisplayCutoutMode;
- final boolean attachedInParent = attached != null && !layoutInScreen;
- final boolean requestedHideNavigation =
- (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
-
- // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
- // cropped / shifted to the displayFrame in WindowState.
- final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
- && type != TYPE_BASE_APPLICATION;
-
- // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
- // the cutout safe zone.
- if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
- final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
- displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
- if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
- && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
- // At the top we have the status bar, so apps that are
- // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
- // already expect that there's an inset there and we don't need to exclude
- // the window from that area.
- displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
- }
- if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
- && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
- // Same for the navigation bar.
- switch (mNavigationBarPosition) {
- case NAV_BAR_BOTTOM:
- displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
- break;
- case NAV_BAR_RIGHT:
- displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
- break;
- case NAV_BAR_LEFT:
- displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
- break;
- }
- }
- if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
- // The IME can always extend under the bottom cutout if the navbar is there.
- displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
- }
- // Windows that are attached to a parent and laid out in said parent already avoid
- // the cutout according to that parent and don't need to be further constrained.
- // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
- // They will later be cropped or shifted using the displayFrame in WindowState,
- // which prevents overlap with the DisplayCutout.
- if (!attachedInParent && !floatingInScreenWindow) {
- sTmpRect.set(pf);
- pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
- windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
- }
- // Make sure that NO_LIMITS windows clipped to the display don't extend under the
- // cutout.
- df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
- }
-
- // Content should never appear in the cutout.
- cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
-
- // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
- // Also, we don't allow windows in multi-window mode to extend out of the screen.
- if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
- && !win.isInMultiWindowMode()) {
- df.left = df.top = -10000;
- df.right = df.bottom = 10000;
- if (type != TYPE_WALLPAPER) {
- of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
- of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
- }
- }
-
- // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
- // need to provide information to the clients that want to pretend that you can draw there.
- // We only want to apply outsets to certain types of windows. For example, we never want to
- // apply the outsets to floating dialogs, because they wouldn't make sense there.
- final boolean useOutsets = shouldUseOutsets(attrs, fl);
- if (isDefaultDisplay && useOutsets) {
- final Rect osf = windowFrames.mOutsetFrame;
- osf.set(cf.left, cf.top, cf.right, cf.bottom);
- windowFrames.setHasOutsets(true);
- int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
- if (outset > 0) {
- int rotation = displayFrames.mRotation;
- if (rotation == Surface.ROTATION_0) {
- osf.bottom += outset;
- } else if (rotation == Surface.ROTATION_90) {
- osf.right += outset;
- } else if (rotation == Surface.ROTATION_180) {
- osf.top -= outset;
- } else if (rotation == Surface.ROTATION_270) {
- osf.left -= outset;
- }
- if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset
- + " with rotation " + rotation + ", result: " + osf);
- }
- }
-
- if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
- + ": sim=#" + Integer.toHexString(sim)
- + " attach=" + attached + " type=" + type
- + String.format(" flags=0x%08x", fl)
- + " pf=" + pf.toShortString() + " df=" + df.toShortString()
- + " of=" + of.toShortString()
- + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
- + " dcf=" + dcf.toShortString()
- + " sf=" + sf.toShortString()
- + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
-
- if (!sTmpLastParentFrame.equals(pf)) {
- windowFrames.setContentChanged(true);
- }
-
- win.computeFrameLw();
- // Dock windows carve out the bottom of the screen, so normal windows
- // can't appear underneath them.
- if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
- && !win.getGivenInsetsPendingLw()) {
- offsetInputMethodWindowLw(win, displayFrames);
- }
- if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
- && !win.getGivenInsetsPendingLw()) {
- offsetVoiceInputWindowLw(win, displayFrames);
- }
- }
-
- private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) {
- // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area.
- df.set(displayFrames.mOverscan);
- pf.set(displayFrames.mOverscan);
- cf.set(displayFrames.mUnrestricted);
- of.set(displayFrames.mUnrestricted);
- }
-
- private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
- int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
- top += win.getGivenContentInsetsLw().top;
- displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
- displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
- top = win.getVisibleFrameLw().top;
- top += win.getGivenVisibleInsetsLw().top;
- displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
- if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
- + displayFrames.mDock.bottom + " mContentBottom="
- + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
- }
-
- private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
- int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
- top += win.getGivenContentInsetsLw().top;
- displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
- }
-
- /** {@inheritDoc} */
- @Override
- public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
- mTopFullscreenOpaqueWindowState = null;
- mTopFullscreenOpaqueOrDimmingWindowState = null;
- mTopDockedOpaqueWindowState = null;
- mTopDockedOpaqueOrDimmingWindowState = null;
- mForceStatusBar = false;
- mForceStatusBarFromKeyguard = false;
- mForceStatusBarTransparent = false;
- mForcingShowNavBar = false;
- mForcingShowNavBarLayer = -1;
-
- mAllowLockscreenWhenOn = false;
- mShowingDream = false;
- mWindowSleepTokenNeeded = false;
- }
-
- /** {@inheritDoc} */
- @Override
- public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
- WindowState attached, WindowState imeTarget) {
- final boolean affectsSystemUi = win.canAffectSystemUiFlags();
- if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
- applyKeyguardPolicyLw(win, imeTarget);
- final int fl = PolicyControl.getWindowFlags(win, attrs);
- if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
- && attrs.type == TYPE_INPUT_METHOD) {
- mForcingShowNavBar = true;
- mForcingShowNavBarLayer = win.getSurfaceLayer();
- }
- if (attrs.type == TYPE_STATUS_BAR) {
- if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
- mForceStatusBarFromKeyguard = true;
- }
- if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
- mForceStatusBarTransparent = true;
- }
- }
-
- boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
- && attrs.type < FIRST_SYSTEM_WINDOW;
- final int windowingMode = win.getWindowingMode();
- final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
- windowingMode == WINDOWING_MODE_FULLSCREEN
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
- if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
- if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
- mForceStatusBar = true;
- }
- if (attrs.type == TYPE_DREAM) {
- // If the lockscreen was showing when the dream started then wait
- // for the dream to draw before hiding the lockscreen.
- if (!mDreamingLockscreen
- || (win.isVisibleLw() && win.hasDrawnLw())) {
- mShowingDream = true;
- appWindow = true;
- }
- }
-
- // For app windows that are not attached, we decide if all windows in the app they
- // represent should be hidden or if we should hide the lockscreen. For attached app
- // windows we defer the decision to the window it is attached to.
- if (appWindow && attached == null) {
- if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
- mTopFullscreenOpaqueWindowState = win;
- if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
- mTopFullscreenOpaqueOrDimmingWindowState = win;
- }
- if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
- mAllowLockscreenWhenOn = true;
- }
- }
- }
- }
-
- // Voice interaction overrides both top fullscreen and top docked.
- if (affectsSystemUi && win.getAttrs().type == TYPE_VOICE_INTERACTION) {
- if (mTopFullscreenOpaqueWindowState == null) {
- mTopFullscreenOpaqueWindowState = win;
- if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
- mTopFullscreenOpaqueOrDimmingWindowState = win;
- }
- }
- if (mTopDockedOpaqueWindowState == null) {
- mTopDockedOpaqueWindowState = win;
- if (mTopDockedOpaqueOrDimmingWindowState == null) {
- mTopDockedOpaqueOrDimmingWindowState = win;
- }
- }
- }
-
- // Keep track of the window if it's dimming but not necessarily fullscreen.
- if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
- && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
- mTopFullscreenOpaqueOrDimmingWindowState = win;
- }
-
- // We need to keep track of the top "fullscreen" opaque window for the docked stack
- // separately, because both the "real fullscreen" opaque window and the one for the docked
- // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
- if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
- && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- mTopDockedOpaqueWindowState = win;
- if (mTopDockedOpaqueOrDimmingWindowState == null) {
- mTopDockedOpaqueOrDimmingWindowState = win;
- }
- }
-
- // Also keep track of any windows that are dimming but not necessarily fullscreen in the
- // docked stack.
- if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
- && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- mTopDockedOpaqueOrDimmingWindowState = win;
- }
-
- // Take note if a window wants to acquire a sleep token.
- if ((attrs.privateFlags & PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN) != 0
- && win.canAcquireSleepToken()) {
- mWindowSleepTokenNeeded = true;
- }
- }
-
- private void applyKeyguardPolicyLw(WindowState win, WindowState imeTarget) {
+ public void applyKeyguardPolicyLw(WindowState win, WindowState imeTarget) {
if (canBeHiddenByKeyguardLw(win)) {
if (shouldBeHiddenByKeyguard(win, imeTarget)) {
win.hideLw(false /* doAnimation */);
@@ -5441,148 +3373,9 @@
/** {@inheritDoc} */
@Override
- public int finishPostLayoutPolicyLw() {
- int changes = 0;
- boolean topIsFullscreen = false;
-
- final WindowManager.LayoutParams lp = (mTopFullscreenOpaqueWindowState != null)
- ? mTopFullscreenOpaqueWindowState.getAttrs()
- : null;
-
- // If we are not currently showing a dream then remember the current
- // lockscreen state. We will use this to determine whether the dream
- // started while the lockscreen was showing and remember this state
- // while the dream is showing.
- if (!mShowingDream) {
- mDreamingLockscreen = isKeyguardShowingAndNotOccluded();
- if (mDreamingSleepTokenNeeded) {
- mDreamingSleepTokenNeeded = false;
- mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
- }
- } else {
- if (!mDreamingSleepTokenNeeded) {
- mDreamingSleepTokenNeeded = true;
- mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
- }
- }
-
- if (mStatusBar != null) {
- if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
- + " forcefkg=" + mForceStatusBarFromKeyguard
- + " top=" + mTopFullscreenOpaqueWindowState);
- boolean shouldBeTransparent = mForceStatusBarTransparent
- && !mForceStatusBar
- && !mForceStatusBarFromKeyguard;
- if (!shouldBeTransparent) {
- mStatusBarController.setShowTransparent(false /* transparent */);
- } else if (!mStatusBar.isVisibleLw()) {
- mStatusBarController.setShowTransparent(true /* transparent */);
- }
-
- boolean statusBarForcesShowingNavigation
- = (mStatusBar.getAttrs().privateFlags
- & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
- boolean topAppHidesStatusBar = topAppHidesStatusBar();
- if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent
- || statusBarForcesShowingNavigation) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
- if (mStatusBarController.setBarShowingLw(true)) {
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
- // Maintain fullscreen layout until incoming animation is complete.
- topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
- // Transient status bar is not allowed if status bar is on lockscreen or status bar
- // is expecting the navigation keys from the user.
- if ((mForceStatusBarFromKeyguard || statusBarForcesShowingNavigation)
- && mStatusBarController.isTransientShowing()) {
- mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
- mLastSystemUiFlags, mLastSystemUiFlags);
- }
- } else if (mTopFullscreenOpaqueWindowState != null) {
- topIsFullscreen = topAppHidesStatusBar;
- // The subtle difference between the window for mTopFullscreenOpaqueWindowState
- // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
- // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
- // case though.
- if (mStatusBarController.isTransientShowing()) {
- if (mStatusBarController.setBarShowingLw(true)) {
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
- } else if (topIsFullscreen
- && !mWindowManagerInternal.isStackVisible(WINDOWING_MODE_FREEFORM)
- && !mWindowManagerInternal.isStackVisible(
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
- if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
- if (mStatusBarController.setBarShowingLw(false)) {
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- } else {
- if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
- }
- } else {
- if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
- if (mStatusBarController.setBarShowingLw(true)) {
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
- topAppHidesStatusBar = false;
- }
- }
- mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
- }
-
- if (mTopIsFullscreen != topIsFullscreen) {
- if (!topIsFullscreen) {
- // Force another layout when status bar becomes fully shown.
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
- mTopIsFullscreen = topIsFullscreen;
- }
-
- if ((updateSystemUiVisibilityLw()&SYSTEM_UI_CHANGING_LAYOUT) != 0) {
- // If the navigation bar has been hidden or shown, we need to do another
- // layout pass to update that window.
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- }
-
- if (mShowingDream != mLastShowingDream) {
- mLastShowingDream = mShowingDream;
- mWindowManagerFuncs.notifyShowingDreamChanged();
- }
-
- updateWindowSleepToken();
-
- // update since mAllowLockscreenWhenOn might have changed
- updateLockScreenTimeout();
- return changes;
- }
-
- private void updateWindowSleepToken() {
- if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
- mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
- mHandler.post(mAcquireSleepTokenRunnable);
- } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
- mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
- mHandler.post(mReleaseSleepTokenRunnable);
- }
- mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
- }
-
- /**
- * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
- * window.
- */
- private boolean topAppHidesStatusBar() {
- if (mTopFullscreenOpaqueWindowState == null) {
- return false;
- }
- final int fl = PolicyControl.getWindowFlags(null,
- mTopFullscreenOpaqueWindowState.getAttrs());
- if (localLOGV) {
- Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
- Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
- + " lp.flags=0x" + Integer.toHexString(fl));
- }
- return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
- || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
+ public void setKeyguardCandidateLw(WindowState win) {
+ mKeyguardCandidate = win;
+ setKeyguardOccludedLw(mKeyguardOccluded, true /* force */);
}
/**
@@ -5598,19 +3391,19 @@
if (!isOccluded && changed && showing) {
mKeyguardOccluded = false;
mKeyguardDelegate.setOccluded(false, true /* animate */);
- if (mStatusBar != null) {
- mStatusBar.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
+ if (mKeyguardCandidate != null) {
+ mKeyguardCandidate.getAttrs().privateFlags |= PRIVATE_FLAG_KEYGUARD;
if (!mKeyguardDelegate.hasLockscreenWallpaper()) {
- mStatusBar.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+ mKeyguardCandidate.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
}
}
return true;
} else if (isOccluded && changed && showing) {
mKeyguardOccluded = true;
mKeyguardDelegate.setOccluded(true, false /* animate */);
- if (mStatusBar != null) {
- mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
- mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
+ if (mKeyguardCandidate != null) {
+ mKeyguardCandidate.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
+ mKeyguardCandidate.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
}
return true;
} else if (changed) {
@@ -5622,28 +3415,6 @@
}
}
- private boolean isStatusBarKeyguard() {
- return mStatusBar != null
- && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
- }
-
- @Override
- public boolean allowAppAnimationsLw() {
- return !mShowingDream;
- }
-
- @Override
- public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
- mFocusedWindow = newFocus;
- mLastFocusedWindow = lastFocus;
- if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
- // If the navigation bar has been hidden or shown, we need to do another
- // layout pass to update that window.
- return FINISH_LAYOUT_REDO_LAYOUT;
- }
- return 0;
- }
-
/** {@inheritDoc} */
@Override
public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) {
@@ -6469,57 +4240,11 @@
// current user.
mSettingsObserver.onChange(false);
mDefaultDisplayRotation.onUserSwitch();
-
- // force a re-application of focused window sysui visibility.
- // the window may never have been shown for this user
- // e.g. the keyguard when going through the new-user setup flow
- synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
- mLastSystemUiFlags = 0;
- updateSystemUiVisibilityLw();
- }
+ mWindowManagerFuncs.onUserSwitched();
}
}
};
- private final Runnable mHiddenNavPanic = new Runnable() {
- @Override
- public void run() {
- synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
- if (!isUserSetupComplete()) {
- // Swipe-up for navigation bar is disabled during setup
- return;
- }
- mPendingPanicGestureUptime = SystemClock.uptimeMillis();
- if (!isNavBarEmpty(mLastSystemUiFlags)) {
- mNavigationBarController.showTransient();
- }
- }
- }
- };
-
- private void requestTransientBars(WindowState swipeTarget) {
- synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
- if (!isUserSetupComplete()) {
- // Swipe-up for navigation bar is disabled during setup
- return;
- }
- boolean sb = mStatusBarController.checkShowTransientBarLw();
- boolean nb = mNavigationBarController.checkShowTransientBarLw()
- && !isNavBarEmpty(mLastSystemUiFlags);
- if (sb || nb) {
- // Don't show status bar when swiping on already visible navigation bar
- if (!nb && swipeTarget == mNavigationBar) {
- if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
- return;
- }
- if (sb) mStatusBarController.showTransient();
- if (nb) mNavigationBarController.showTransient();
- mImmersiveModeConfirmation.confirmCurrentPrompt();
- updateSystemUiVisibilityLw();
- }
- }
- }
-
// Called on the PowerManager's Notifier thread.
@Override
public void startedGoingToSleep(int why) {
@@ -6852,11 +4577,6 @@
}
@Override
- public boolean isShowingDreamLw() {
- return mShowingDream;
- }
-
- @Override
public void startKeyguardExitAnimation(long startTime, long fadeoutDuration) {
if (mKeyguardDelegate != null) {
if (DEBUG_KEYGUARD) Slog.d(TAG, "PWM.startKeyguardExitAnimation");
@@ -6864,85 +4584,6 @@
}
}
- @Override
- public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
- DisplayCutout displayCutout, Rect outInsets) {
- outInsets.setEmpty();
-
- // Navigation bar and status bar.
- getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
- outInsets.top = Math.max(outInsets.top, mStatusBarHeightForRotation[displayRotation]);
- }
-
- @Override
- public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
- DisplayCutout displayCutout, Rect outInsets) {
- outInsets.setEmpty();
-
- // Only navigation bar
- if (mDefaultDisplayPolicy.hasNavigationBar()) {
- int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
- if (position == NAV_BAR_BOTTOM) {
- outInsets.bottom = getNavigationBarHeight(displayRotation, mUiMode);
- } else if (position == NAV_BAR_RIGHT) {
- outInsets.right = getNavigationBarWidth(displayRotation, mUiMode);
- } else if (position == NAV_BAR_LEFT) {
- outInsets.left = getNavigationBarWidth(displayRotation, mUiMode);
- }
- }
-
- if (displayCutout != null) {
- outInsets.left += displayCutout.getSafeInsetLeft();
- outInsets.top += displayCutout.getSafeInsetTop();
- outInsets.right += displayCutout.getSafeInsetRight();
- outInsets.bottom += displayCutout.getSafeInsetBottom();
- }
- }
-
- @Override
- public boolean isNavBarForcedShownLw(WindowState windowState) {
- return mForceShowSystemBars;
- }
-
- @Override
- public int getNavBarPosition() {
- // TODO(multi-display): Support system decor on secondary displays.
- return mNavigationBarPosition;
- }
-
- @Override
- public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
- int displayHeight, int displayRotation) {
- final int barPosition = navigationBarPosition(displayWidth, displayHeight, displayRotation);
- return isDockSideAllowed(dockSide, originalDockSide, barPosition,
- mDefaultDisplayPolicy.navigationBarCanMove());
- }
-
- @VisibleForTesting
- static boolean isDockSideAllowed(int dockSide, int originalDockSide,
- int navBarPosition, boolean navigationBarCanMove) {
- if (dockSide == DOCKED_TOP) {
- return true;
- }
-
- if (navigationBarCanMove) {
- // Only allow the dockside opposite to the nav bar position in landscape
- return dockSide == DOCKED_LEFT && navBarPosition == NAV_BAR_RIGHT
- || dockSide == DOCKED_RIGHT && navBarPosition == NAV_BAR_LEFT;
- }
-
- // Side is the same as original side
- if (dockSide == originalDockSide) {
- return true;
- }
-
- // Only if original docked side was top in portrait will allow left for landscape
- if (dockSide == DOCKED_LEFT && originalDockSide == DOCKED_TOP) {
- return true;
- }
- return false;
- }
-
void sendCloseSystemWindows() {
PhoneWindow.sendCloseSystemWindows(mContext, null);
}
@@ -7009,9 +4650,6 @@
}
}
- mSystemGestures.systemReady();
- mImmersiveModeConfirmation.systemReady();
-
mAutofillManagerInternal = LocalServices.getService(AutofillManagerInternal.class);
}
@@ -7173,10 +4811,22 @@
mHandler.post(mScreenLockTimeout);
}
+ // TODO (b/113840485): Move this logic to DisplayPolicy when lockscreen supports multi-display.
+ @Override
+ public void setAllowLockscreenWhenOn(int displayId, boolean allow) {
+ if (allow) {
+ mAllowLockscreenWhenOnDisplays.add(displayId);
+ } else {
+ mAllowLockscreenWhenOnDisplays.remove(displayId);
+ }
+ updateLockScreenTimeout();
+ }
+
private void updateLockScreenTimeout() {
synchronized (mScreenLockTimeout) {
- final boolean enable = (mAllowLockscreenWhenOn && mDefaultDisplayPolicy.isAwake() &&
- mKeyguardDelegate != null && mKeyguardDelegate.isSecure(mCurrentUserId));
+ final boolean enable = !mAllowLockscreenWhenOnDisplays.isEmpty()
+ && mDefaultDisplayPolicy.isAwake()
+ && mKeyguardDelegate != null && mKeyguardDelegate.isSecure(mCurrentUserId);
if (mLockScreenTimerActive != enable) {
if (enable) {
if (localLOGV) Log.v(TAG, "setting lockscreen timer");
@@ -7192,21 +4842,6 @@
}
// TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
- private void updateDreamingSleepToken(boolean acquire) {
- if (acquire) {
- if (mDreamingSleepToken == null) {
- mDreamingSleepToken = mActivityTaskManagerInternal.acquireSleepToken(
- "Dream", DEFAULT_DISPLAY);
- }
- } else {
- if (mDreamingSleepToken != null) {
- mDreamingSleepToken.release();
- mDreamingSleepToken = null;
- }
- }
- }
-
- // TODO (multidisplay): Support multiple displays in WindowManagerPolicy.
private void updateScreenOffSleepToken(boolean acquire) {
if (acquire) {
if (mScreenOffSleepToken == null) {
@@ -7254,6 +4889,11 @@
}
}
+ @Override
+ public int getUiMode() {
+ return mUiMode;
+ }
+
void updateRotation(boolean alwaysSendConfiguration) {
try {
// Set orientation on WindowManager.
@@ -7510,380 +5150,6 @@
}
}
- private int updateSystemUiVisibilityLw() {
- // If there is no window focused, there will be nobody to handle the events
- // anyway, so just hang on in whatever state we're in until things settle down.
- WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
- : mTopFullscreenOpaqueWindowState;
- if (winCandidate == null) {
- return 0;
- }
-
- // The immersive mode confirmation should never affect the system bar visibility, otherwise
- // it will unhide the navigation bar and hide itself.
- if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
-
- // The immersive mode confirmation took the focus from mLastFocusedWindow which was
- // controlling the system ui visibility. So if mLastFocusedWindow can still receive
- // keys, we let it keep controlling the visibility.
- final boolean lastFocusCanReceiveKeys =
- (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
- winCandidate = isStatusBarKeyguard() ? mStatusBar
- : lastFocusCanReceiveKeys ? mLastFocusedWindow
- : mTopFullscreenOpaqueWindowState;
- if (winCandidate == null) {
- return 0;
- }
- }
- final WindowState win = winCandidate;
- if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mKeyguardOccluded) {
- // We are updating at a point where the keyguard has gotten
- // focus, but we were last in a state where the top window is
- // hiding it. This is probably because the keyguard as been
- // shown while the top window was displayed, so we want to ignore
- // it here because this is just a very transient change and it
- // will quickly lose focus once it correctly gets hidden.
- return 0;
- }
-
- int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
- & ~mResettingSystemUiFlags
- & ~mForceClearedSystemUiFlags;
- if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
- tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
- }
-
- final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
- mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
- final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
- mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
- mWindowManagerFuncs.getStackBounds(
- WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds);
- mWindowManagerFuncs.getStackBounds(
- WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
- final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
- final int diff = visibility ^ mLastSystemUiFlags;
- final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
- final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
- final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
- if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
- && mFocusedApp == win.getAppToken()
- && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
- && mLastDockedStackBounds.equals(mDockedStackBounds)) {
- return 0;
- }
- mLastSystemUiFlags = visibility;
- mLastFullscreenStackSysUiFlags = fullscreenVisibility;
- mLastDockedStackSysUiFlags = dockedVisibility;
- mLastFocusNeedsMenu = needsMenu;
- mFocusedApp = win.getAppToken();
- final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
- final Rect dockedStackBounds = new Rect(mDockedStackBounds);
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
- if (statusbar != null) {
- statusbar.setSystemUiVisibility(visibility, fullscreenVisibility,
- dockedVisibility, 0xffffffff, fullscreenStackBounds,
- dockedStackBounds, win.toString());
- statusbar.topAppWindowChanged(needsMenu);
- }
- }
- });
- return diff;
- }
-
- private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
- final boolean onKeyguard = isStatusBarKeyguard() && !mKeyguardOccluded;
- final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming;
- if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
- // If the top fullscreen-or-dimming window is also the top fullscreen, respect
- // its light flag.
- vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
- vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
- & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
- } else if (statusColorWin != null && statusColorWin.isDimming()) {
- // Otherwise if it's dimming, clear the light flag.
- vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
- }
- return vis;
- }
-
- @VisibleForTesting
- @Nullable
- static WindowState chooseNavigationColorWindowLw(WindowState opaque,
- WindowState opaqueOrDimming, WindowState imeWindow,
- @NavigationBarPosition int navBarPosition) {
- // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
- // window can be navigation color window.
- final boolean imeWindowCanNavColorWindow = imeWindow != null
- && imeWindow.isVisibleLw()
- && navBarPosition == NAV_BAR_BOTTOM
- && (PolicyControl.getWindowFlags(imeWindow, null)
- & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
-
- if (opaque != null && opaqueOrDimming == opaque) {
- // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
- // unless IME window is also eligible, since currently the IME window is always show
- // above the opaque fullscreen app window, regardless of the IME target window.
- // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
- return imeWindowCanNavColorWindow ? imeWindow : opaque;
- }
-
- if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
- // No dimming window is involved. Determine the result only with the IME window.
- return imeWindowCanNavColorWindow ? imeWindow : null;
- }
-
- if (!imeWindowCanNavColorWindow) {
- // No IME window is involved. Determine the result only with opaqueOrDimming.
- return opaqueOrDimming;
- }
-
- // The IME window and the dimming window are competing. Check if the dimming window can be
- // IME target or not.
- if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
- // The IME window is above the dimming window.
- return imeWindow;
- } else {
- // The dimming window is above the IME window.
- return opaqueOrDimming;
- }
- }
-
- @VisibleForTesting
- static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
- WindowState imeWindow, WindowState navColorWin) {
-
- if (navColorWin != null) {
- if (navColorWin == imeWindow || navColorWin == opaque) {
- // Respect the light flag.
- vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
- vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
- & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
- } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
- // Clear the light flag for dimming window.
- vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
- }
- }
- return vis;
- }
-
- private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {
- final boolean dockedStackVisible =
- mWindowManagerInternal.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
- final boolean freeformStackVisible =
- mWindowManagerInternal.isStackVisible(WINDOWING_MODE_FREEFORM);
- final boolean resizing = mWindowManagerInternal.isDockedDividerResizing();
-
- // We need to force system bars when the docked stack is visible, when the freeform stack
- // is visible but also when we are resizing for the transitions when docked stack
- // visibility changes.
- mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
- final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
-
- // apply translucent bar vis flags
- WindowState fullscreenTransWin = isStatusBarKeyguard() && !mKeyguardOccluded
- ? mStatusBar
- : mTopFullscreenOpaqueWindowState;
- vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
- vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
- final int dockedVis = mStatusBarController.applyTranslucentFlagLw(
- mTopDockedOpaqueWindowState, 0, 0);
-
- final boolean fullscreenDrawsStatusBarBackground =
- drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
- final boolean dockedDrawsStatusBarBackground =
- drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
-
- // prevent status bar interaction from clearing certain flags
- int type = win.getAttrs().type;
- boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
- if (statusBarHasFocus && !isStatusBarKeyguard()) {
- int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_IMMERSIVE
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
- | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
- if (mKeyguardOccluded) {
- flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
- }
- vis = (vis & ~flags) | (oldVis & flags);
- }
-
- if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
- vis |= View.STATUS_BAR_TRANSPARENT;
- vis &= ~View.STATUS_BAR_TRANSLUCENT;
- } else if ((!areTranslucentBarsAllowed() && fullscreenTransWin != mStatusBar)
- || forceOpaqueStatusBar) {
- vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
- }
-
- vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing);
-
- // update status bar
- boolean immersiveSticky =
- (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
- final boolean hideStatusBarWM =
- mTopFullscreenOpaqueWindowState != null
- && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
- & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
- final boolean hideStatusBarSysui =
- (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
- final boolean hideNavBarSysui =
- (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
-
- final boolean transientStatusBarAllowed = mStatusBar != null
- && (statusBarHasFocus || (!mForceShowSystemBars
- && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
-
- final boolean transientNavBarAllowed = mNavigationBar != null
- && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
-
- final long now = SystemClock.uptimeMillis();
- final boolean pendingPanic = mPendingPanicGestureUptime != 0
- && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
- if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard()
- && mDefaultDisplayPolicy.isKeyguardDrawComplete()) {
- // The user performed the panic gesture recently, we're about to hide the bars,
- // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
- mPendingPanicGestureUptime = 0;
- mStatusBarController.showTransient();
- if (!isNavBarEmpty(vis)) {
- mNavigationBarController.showTransient();
- }
- }
-
- final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
- && !transientStatusBarAllowed && hideStatusBarSysui;
- final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
- && !transientNavBarAllowed;
- if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
- // clear the clearable flags instead
- clearClearableFlagsLw();
- vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
- }
-
- final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
- immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
- final boolean navAllowedHidden = immersive || immersiveSticky;
-
- if (hideNavBarSysui && !navAllowedHidden
- && getWindowLayerLw(win) > getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
- // We can't hide the navbar from this window otherwise the input consumer would not get
- // the input events.
- vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
- }
-
- vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
-
- // update navigation bar
- boolean oldImmersiveMode = isImmersiveMode(oldVis);
- boolean newImmersiveMode = isImmersiveMode(vis);
- if (win != null && oldImmersiveMode != newImmersiveMode) {
- final String pkg = win.getOwningPackage();
- mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
- isUserSetupComplete(), isNavBarEmpty(win.getSystemUiVisibility()));
- }
-
- vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
-
- final WindowState navColorWin = chooseNavigationColorWindowLw(
- mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
- mWindowManagerFuncs.getInputMethodWindowLw(), mNavigationBarPosition);
- vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
- mTopFullscreenOpaqueOrDimmingWindowState,
- mWindowManagerFuncs.getInputMethodWindowLw(), navColorWin);
-
- return vis;
- }
-
- private boolean drawsStatusBarBackground(int vis, WindowState win) {
- if (!mStatusBarController.isTransparentAllowed(win)) {
- return false;
- }
- if (win == null) {
- return true;
- }
-
- final boolean drawsSystemBars =
- (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
- final boolean forceDrawsSystemBars =
- (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
-
- return forceDrawsSystemBars || drawsSystemBars && (vis & View.STATUS_BAR_TRANSLUCENT) == 0;
- }
-
- /**
- * @return the current visibility flags with the nav-bar opacity related flags toggled based
- * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
- */
- private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
- boolean freeformStackVisible, boolean isDockedDividerResizing) {
- if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
- if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
- visibility = setNavBarOpaqueFlag(visibility);
- }
- } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
- if (isDockedDividerResizing) {
- visibility = setNavBarOpaqueFlag(visibility);
- } else if (freeformStackVisible) {
- visibility = setNavBarTranslucentFlag(visibility);
- } else {
- visibility = setNavBarOpaqueFlag(visibility);
- }
- }
-
- if (!areTranslucentBarsAllowed()) {
- visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
- }
- return visibility;
- }
-
- private int setNavBarOpaqueFlag(int visibility) {
- return visibility &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
- }
-
- private int setNavBarTranslucentFlag(int visibility) {
- visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
- return visibility |= View.NAVIGATION_BAR_TRANSLUCENT;
- }
-
- private void clearClearableFlagsLw() {
- int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
- if (newVal != mResettingSystemUiFlags) {
- mResettingSystemUiFlags = newVal;
- mWindowManagerFuncs.reevaluateStatusBarVisibility();
- }
- }
-
- private boolean isImmersiveMode(int vis) {
- final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
- return mNavigationBar != null
- && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
- && (vis & flags) != 0
- && canHideNavigationBar();
- }
-
- private static boolean isNavBarEmpty(int systemUiFlags) {
- final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
- | View.STATUS_BAR_DISABLE_BACK
- | View.STATUS_BAR_DISABLE_RECENT);
-
- return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
- }
-
- /**
- * @return whether the navigation or status bar can be made translucent
- *
- * This should return true unless touch exploration is not enabled or
- * R.boolean.config_enableTranslucentDecor is false.
- */
- private boolean areTranslucentBarsAllowed() {
- return mTranslucentDecorEnabled;
- }
-
// Use this instead of checking config_showNavigationBar so that it can be consistently
// overridden by qemu.hw.mainkeys in the emulator.
@Override
@@ -7926,44 +5192,8 @@
}
@Override
- public boolean shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation,
- int newRotation) {
- // For the upside down rotation we don't rotate seamlessly as the navigation
- // bar moves position.
- // Note most apps (using orientation:sensor or user as opposed to fullSensor)
- // will not enter the reverse portrait orientation, so actually the
- // orientation won't change at all.
- if (oldRotation == displayRotation.getUpsideDownRotation()
- || newRotation == displayRotation.getUpsideDownRotation()) {
- return false;
- }
- // If the navigation bar can't change sides, then it will
- // jump when we change orientations and we don't rotate
- // seamlessly.
- if (!displayRotation.getDisplayPolicy().navigationBarCanMove()) {
- return false;
- }
-
- final WindowState w = mTopFullscreenOpaqueWindowState;
- if (w != mFocusedWindow) {
- return false;
- }
-
- // We only enable seamless rotation if the top window has requested
- // it and is in the fullscreen opaque state. Seamless rotation
- // requires freezing various Surface states and won't work well
- // with animations, so we disable it in the animation case for now.
- if (w != null && !w.isAnimatingLw() &&
- w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) {
- return true;
- }
- return false;
- }
-
- @Override
public void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
- proto.write(LAST_SYSTEM_UI_FLAGS, mLastSystemUiFlags);
proto.write(ROTATION_MODE, mDefaultDisplayRotation.getUserRotationMode());
proto.write(ROTATION, mDefaultDisplayRotation.getUserRotation());
proto.write(ORIENTATION, mDefaultDisplayRotation.getCurrentAppOrientation());
@@ -7971,30 +5201,9 @@
proto.write(KEYGUARD_DRAW_COMPLETE, mDefaultDisplayPolicy.isKeyguardDrawComplete());
proto.write(WINDOW_MANAGER_DRAW_COMPLETE,
mDefaultDisplayPolicy.isWindowManagerDrawComplete());
- if (mFocusedApp != null) {
- proto.write(FOCUSED_APP_TOKEN, mFocusedApp.toString());
- }
- if (mFocusedWindow != null) {
- mFocusedWindow.writeIdentifierToProto(proto, FOCUSED_WINDOW);
- }
- if (mTopFullscreenOpaqueWindowState != null) {
- mTopFullscreenOpaqueWindowState.writeIdentifierToProto(
- proto, TOP_FULLSCREEN_OPAQUE_WINDOW);
- }
- if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
- mTopFullscreenOpaqueOrDimmingWindowState.writeIdentifierToProto(
- proto, TOP_FULLSCREEN_OPAQUE_OR_DIMMING_WINDOW);
- }
proto.write(KEYGUARD_OCCLUDED, mKeyguardOccluded);
proto.write(KEYGUARD_OCCLUDED_CHANGED, mKeyguardOccludedChanged);
proto.write(KEYGUARD_OCCLUDED_PENDING, mPendingKeyguardOccluded);
- proto.write(FORCE_STATUS_BAR, mForceStatusBar);
- proto.write(FORCE_STATUS_BAR_FROM_KEYGUARD, mForceStatusBarFromKeyguard);
- mStatusBarController.writeToProto(proto, STATUS_BAR);
- mNavigationBarController.writeToProto(proto, NAVIGATION_BAR);
- if (mDefaultOrientationListener != null) {
- mDefaultOrientationListener.writeToProto(proto, ORIENTATION_LISTENER);
- }
if (mKeyguardDelegate != null) {
mKeyguardDelegate.writeToProto(proto, KEYGUARD_DELEGATE);
}
@@ -8008,19 +5217,6 @@
pw.print(" mSystemBooted="); pw.println(mSystemBooted);
pw.print(prefix); pw.print("mCameraLensCoverState=");
pw.println(WindowManagerFuncs.cameraLensStateToString(mCameraLensCoverState));
- if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
- || mForceClearedSystemUiFlags != 0) {
- pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
- pw.print(Integer.toHexString(mLastSystemUiFlags));
- pw.print(" mResettingSystemUiFlags=0x");
- pw.print(Integer.toHexString(mResettingSystemUiFlags));
- pw.print(" mForceClearedSystemUiFlags=0x");
- pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
- }
- if (mLastFocusNeedsMenu) {
- pw.print(prefix); pw.print("mLastFocusNeedsMenu=");
- pw.println(mLastFocusNeedsMenu);
- }
pw.print(prefix); pw.print("mWakeGestureEnabledSetting=");
pw.println(mWakeGestureEnabledSetting);
@@ -8083,50 +5279,11 @@
final int key = mDisplayHomeButtonHandlers.keyAt(i);
pw.println(mDisplayHomeButtonHandlers.get(key));
}
- pw.print(prefix); pw.print("mDockLayer="); pw.print(mDockLayer);
- pw.print(" mStatusBarLayer="); pw.println(mStatusBarLayer);
- pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
- pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
- pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
- if (mStatusBar != null) {
- pw.print(prefix); pw.print("mStatusBar=");
- pw.print(mStatusBar); pw.print(" isStatusBarKeyguard=");
- pw.println(isStatusBarKeyguard());
- }
- if (mNavigationBar != null) {
- pw.print(prefix); pw.print("mNavigationBar=");
- pw.println(mNavigationBar);
- }
- if (mFocusedWindow != null) {
- pw.print(prefix); pw.print("mFocusedWindow=");
- pw.println(mFocusedWindow);
- }
- if (mFocusedApp != null) {
- pw.print(prefix); pw.print("mFocusedApp=");
- pw.println(mFocusedApp);
- }
- if (mTopFullscreenOpaqueWindowState != null) {
- pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
- pw.println(mTopFullscreenOpaqueWindowState);
- }
- if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
- pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
- pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
- }
- if (mForcingShowNavBar) {
- pw.print(prefix); pw.print("mForcingShowNavBar=");
- pw.println(mForcingShowNavBar); pw.print( "mForcingShowNavBarLayer=");
- pw.println(mForcingShowNavBarLayer);
- }
- pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
- pw.print(" mKeyguardOccluded="); pw.println(mKeyguardOccluded);
- pw.print(prefix);
- pw.print("mKeyguardOccludedChanged="); pw.print(mKeyguardOccludedChanged);
+ pw.print(prefix); pw.print("mKeyguardOccluded="); pw.print(mKeyguardOccluded);
+ pw.print(" mKeyguardOccludedChanged="); pw.print(mKeyguardOccludedChanged);
pw.print(" mPendingKeyguardOccluded="); pw.println(mPendingKeyguardOccluded);
- pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
- pw.print(" mForceStatusBarFromKeyguard=");
- pw.println(mForceStatusBarFromKeyguard);
- pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
+ pw.print(prefix); pw.print("mAllowLockscreenWhenOnDisplays=");
+ pw.print(!mAllowLockscreenWhenOnDisplays.isEmpty());
pw.print(" mLockScreenTimeout="); pw.print(mLockScreenTimeout);
pw.print(" mLockScreenTimerActive="); pw.println(mLockScreenTimerActive);
if (mHasFeatureLeanback) {
@@ -8139,16 +5296,10 @@
}
mGlobalKeyManager.dump(prefix, pw);
- mStatusBarController.dump(pw, prefix);
- mNavigationBarController.dump(pw, prefix);
- PolicyControl.dump(prefix, pw);
if (mWakeGestureListener != null) {
mWakeGestureListener.dump(pw, prefix);
}
- if (mDefaultOrientationListener != null) {
- mDefaultOrientationListener.dump(pw, prefix);
- }
if (mBurnInProtectionHelper != null) {
mBurnInProtectionHelper.dump(prefix, pw);
}
@@ -8310,11 +5461,6 @@
}
@Override
- public void onLockTaskStateChangedLw(int lockTaskState) {
- mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
- }
-
- @Override
public boolean setAodShowing(boolean aodShowing) {
if (mAodShowing != aodShowing) {
mAodShowing = aodShowing;
diff --git a/services/core/java/com/android/server/policy/StatusBarController.java b/services/core/java/com/android/server/policy/StatusBarController.java
deleted file mode 100644
index e6e4d7f..0000000
--- a/services/core/java/com/android/server/policy/StatusBarController.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.policy;
-
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
-import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
-import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
-
-import android.app.StatusBarManager;
-import android.os.IBinder;
-import android.os.SystemClock;
-import android.view.View;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.Interpolator;
-import android.view.animation.TranslateAnimation;
-
-import com.android.server.LocalServices;
-import com.android.server.statusbar.StatusBarManagerInternal;
-
-/**
- * Implements status bar specific behavior.
- */
-public class StatusBarController extends BarController {
-
- private final AppTransitionListener mAppTransitionListener
- = new AppTransitionListener() {
-
- @Override
- public void onAppTransitionPendingLocked() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- StatusBarManagerInternal statusbar = getStatusBarInternal();
- if (statusbar != null) {
- statusbar.appTransitionPending();
- }
- }
- });
- }
-
- @Override
- public int onAppTransitionStartingLocked(int transit, IBinder openToken,
- IBinder closeToken, long duration, long statusBarAnimationStartTime,
- long statusBarAnimationDuration) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- StatusBarManagerInternal statusbar = getStatusBarInternal();
- if (statusbar != null) {
- statusbar.appTransitionStarting(statusBarAnimationStartTime,
- statusBarAnimationDuration);
- }
- }
- });
- return 0;
- }
-
- @Override
- public void onAppTransitionCancelledLocked(int transit) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- StatusBarManagerInternal statusbar = getStatusBarInternal();
- if (statusbar != null) {
- statusbar.appTransitionCancelled();
- }
- }
- });
- }
-
- @Override
- public void onAppTransitionFinishedLocked(IBinder token) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- StatusBarManagerInternal statusbar = LocalServices.getService(
- StatusBarManagerInternal.class);
- if (statusbar != null) {
- statusbar.appTransitionFinished();
- }
- }
- });
- }
- };
-
- public StatusBarController() {
- super("StatusBar",
- View.STATUS_BAR_TRANSIENT,
- View.STATUS_BAR_UNHIDE,
- View.STATUS_BAR_TRANSLUCENT,
- StatusBarManager.WINDOW_STATUS_BAR,
- FLAG_TRANSLUCENT_STATUS,
- View.STATUS_BAR_TRANSPARENT);
- }
-
-
- public void setTopAppHidesStatusBar(boolean hidesStatusBar) {
- StatusBarManagerInternal statusbar = getStatusBarInternal();
- if (statusbar != null) {
- statusbar.setTopAppHidesStatusBar(hidesStatusBar);
- }
- }
-
- @Override
- protected boolean skipAnimation() {
- return mWin.getAttrs().height == MATCH_PARENT;
- }
-
- public AppTransitionListener getAppTransitionListener() {
- return mAppTransitionListener;
- }
-}
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index e1c4acf..3d474e3 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -65,7 +65,6 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.app.WindowConfiguration;
import android.content.Context;
import android.content.res.CompatibilityInfo;
@@ -78,7 +77,6 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
-import android.view.DisplayCutout;
import android.view.IApplicationToken;
import android.view.IWindowManager;
import android.view.InputEventReceiver;
@@ -90,7 +88,6 @@
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IShortcutService;
-import com.android.server.wm.DisplayFrames;
import com.android.server.wm.DisplayRotation;
import com.android.server.wm.WindowFrames;
@@ -173,11 +170,6 @@
void onKeyguardOccludedChangedLw(boolean occluded);
/**
- * Called when the resource overlays change.
- */
- default void onOverlayChangedLw(DisplayContentInfo displayContentInfo) {}
-
- /**
* Interface to the Window Manager state associated with a particular
* window. You can hold on to an instance of this interface from the call
* to prepareAddWindow() until removeWindow().
@@ -526,11 +518,6 @@
public static final int CAMERA_LENS_COVERED = 1;
/**
- * Ask the window manager to re-evaluate the system UI flags.
- */
- public void reevaluateStatusBarVisibility();
-
- /**
* Add a input consumer which will consume all input events going to any window below it.
*/
public InputConsumer createInputConsumer(Looper looper, String name,
@@ -573,22 +560,12 @@
void unregisterPointerEventListener(PointerEventListener listener, int displayId);
/**
- * @return The content insets of the docked divider window.
- */
- int getDockedDividerInsetsLw();
-
- /**
* Retrieves the {@param outBounds} from the stack matching the {@param windowingMode} and
* {@param activityType}.
*/
void getStackBounds(int windowingMode, int activityType, Rect outBounds);
/**
- * Notifies window manager that {@link #isShowingDreamLw} has changed.
- */
- void notifyShowingDreamChanged();
-
- /**
* @return The currently active input method window.
*/
WindowState getInputMethodWindowLw();
@@ -648,7 +625,15 @@
*/
void onKeyguardShowingAndNotOccludedChanged();
- DisplayContentInfo getDefaultDisplayContentInfo();
+ /**
+ * Notifies window manager that power key is being pressed.
+ */
+ void onPowerKeyDown(boolean isScreenOn);
+
+ /**
+ * Notifies window manager that user is switched.
+ */
+ void onUserSwitched();
}
/**
@@ -735,17 +720,6 @@
public boolean checkShowToOwnerOnly(WindowManager.LayoutParams attrs);
/**
- * Sanitize the layout parameters coming from a client. Allows the policy
- * to do things like ensure that windows of a specific type can't take
- * input focus.
- *
- * @param attrs The window layout parameters to be modified. These values
- * are modified in-place.
- */
- public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
- boolean hasStatusBarServicePermission);
-
- /**
* After the window manager has computed the current configuration based
* on its knowledge of the display and input devices, it gives the policy
* a chance to adjust the information contained in it. If you want to
@@ -941,40 +915,6 @@
public int getMaxWallpaperLayer();
/**
- * Return the display width available after excluding any screen
- * decorations that could never be removed in Honeycomb. That is, system bar or
- * button bar.
- */
- public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation,
- int uiMode, int displayId, DisplayCutout displayCutout);
-
- /**
- * Return the display height available after excluding any screen
- * decorations that could never be removed in Honeycomb. That is, system bar or
- * button bar.
- */
- public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation,
- int uiMode, int displayId, DisplayCutout displayCutout);
-
- /**
- * Return the available screen width that we should report for the
- * configuration. This must be no larger than
- * {@link #getNonDecorDisplayWidth(int, int, int, int, int, DisplayCutout)}; it may be smaller
- * than that to account for more transient decoration like a status bar.
- */
- public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation,
- int uiMode, int displayId, DisplayCutout displayCutout);
-
- /**
- * Return the available screen height that we should report for the
- * configuration. This must be no larger than
- * {@link #getNonDecorDisplayHeight(int, int, int, int, int, DisplayCutout)}; it may be smaller
- * than that to account for more transient decoration like a status bar.
- */
- public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation,
- int uiMode, int displayId, DisplayCutout displayCutout);
-
- /**
* Return whether the given window can become the Keyguard window. Typically returns true for
* the StatusBar.
*/
@@ -1013,65 +953,11 @@
int logo, int windowFlags, Configuration overrideConfig, int displayId);
/**
- * Prepare for a window being added to the window manager. You can throw an
- * exception here to prevent the window being added, or do whatever setup
- * you need to keep track of the window.
+ * Set or clear a window which can behave as the keyguard.
*
- * @param win The window being added.
- * @param attrs The window's LayoutParams.
- *
- * @return {@link WindowManagerGlobal#ADD_OKAY} if the add can proceed, else an
- * error code to abort the add.
+ * @param win The window which can behave as the keyguard.
*/
- public int prepareAddWindowLw(WindowState win,
- WindowManager.LayoutParams attrs);
-
- /**
- * Called when a window is being removed from a window manager. Must not
- * throw an exception -- clean up as much as possible.
- *
- * @param win The window being removed.
- */
- public void removeWindowLw(WindowState win);
-
- /**
- * Control the animation to run when a window's state changes. Return a
- * non-0 number to force the animation to a specific resource ID, or 0
- * to use the default animation.
- *
- * @param win The window that is changing.
- * @param transit What is happening to the window: {@link #TRANSIT_ENTER},
- * {@link #TRANSIT_EXIT}, {@link #TRANSIT_SHOW}, or
- * {@link #TRANSIT_HIDE}.
- *
- * @return Resource ID of the actual animation to use, or 0 for none.
- */
- public int selectAnimationLw(WindowState win, int transit);
-
- /**
- * Determine the animation to run for a rotation transition based on the
- * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
- * and whether it is currently fullscreen and frontmost.
- *
- * @param anim The exiting animation resource id is stored in anim[0], the
- * entering animation resource id is stored in anim[1].
- */
- public void selectRotationAnimationLw(int anim[]);
-
- /**
- * Validate whether the current top fullscreen has specified the same
- * {@link WindowManager.LayoutParams#rotationAnimation} value as that
- * being passed in from the previous top fullscreen window.
- *
- * @param exitAnimId exiting resource id from the previous window.
- * @param enterAnimId entering resource id from the previous window.
- * @param forceDefault For rotation animations only, if true ignore the
- * animation values and just return false.
- * @return true if the previous values are still valid, false if they
- * should be replaced with the default.
- */
- public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
- boolean forceDefault);
+ void setKeyguardCandidateLw(@Nullable WindowState win);
/**
* Create and return an animation to re-display a window that was force hidden by Keyguard.
@@ -1148,100 +1034,21 @@
public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags);
/**
- * Called when layout of the windows is about to start.
+ * Apply the keyguard policy to a specific window.
*
- * @param displayFrames frames of the display we are doing layout on.
- * @param uiMode The current uiMode in configuration.
+ * @param win The window to apply the keyguard policy.
+ * @param imeTarget The current IME target window.
*/
- default void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {}
+ void applyKeyguardPolicyLw(WindowState win, WindowState imeTarget);
/**
- * Returns the bottom-most layer of the system decor, above which no policy decor should
- * be applied.
- */
- public int getSystemDecorLayerLw();
-
- /**
- * Called for each window attached to the window manager as layout is proceeding. The
- * implementation of this function must take care of setting the window's frame, either here or
- * in finishLayout().
+ * Called when the state of allow-lockscreen-when-on of the display is changed. See
+ * {@link WindowManager.LayoutParams#FLAG_ALLOW_LOCK_WHILE_SCREEN_ON}
*
- * @param win The window being positioned.
- * @param attached For sub-windows, the window it is attached to; this
- * window will already have had layoutWindow() called on it
- * so you can use its Rect. Otherwise null.
- * @param displayFrames The display frames.
+ * @param displayId The ID of the display.
+ * @param allow Whether the display allows showing lockscreen when it is on.
*/
- default void layoutWindowLw(
- WindowState win, WindowState attached, DisplayFrames displayFrames) {}
-
- /**
- * Return the layout hints for a newly added window. These values are computed on the
- * most recent layout, so they are not guaranteed to be correct.
- *
- * @param attrs The LayoutParams of the window.
- * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
- * associated with the window.
- * @param displayFrames display frames.
- * @param floatingStack Whether the window's stack is floating.
- * @param outFrame The frame of the window.
- * @param outContentInsets The areas covered by system windows, expressed as positive insets.
- * @param outStableInsets The areas covered by stable system windows irrespective of their
- * current visibility. Expressed as positive insets.
- * @param outOutsets The areas that are not real display, but we would like to treat as such.
- * @param outDisplayCutout The area that has been cut away from the display.
- * @return Whether to always consume the navigation bar.
- * See {@link #isNavBarForcedShownLw(WindowState)}.
- */
- default boolean getLayoutHintLw(WindowManager.LayoutParams attrs, Rect taskBounds,
- DisplayFrames displayFrames, boolean floatingStack,
- Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
- DisplayCutout.ParcelableWrapper outDisplayCutout) {
- return false;
- }
-
- /**
- * Called following layout of all windows before each window has policy applied.
- *
- * @param displayWidth The current full width of the screen.
- * @param displayHeight The current full height of the screen.
- */
- public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight);
-
- /**
- * Called following layout of all window to apply policy to each window.
- *
- * @param win The window being positioned.
- * @param attrs The LayoutParams of the window.
- * @param attached For sub-windows, the window it is attached to. Otherwise null.
- */
- public void applyPostLayoutPolicyLw(WindowState win,
- WindowManager.LayoutParams attrs, WindowState attached, WindowState imeTarget);
-
- /**
- * Called following layout of all windows and after policy has been applied
- * to each window. If in this function you do
- * something that may have modified the animation state of another window,
- * be sure to return non-zero in order to perform another pass through layout.
- *
- * @return Return any bit set of {@link #FINISH_LAYOUT_REDO_LAYOUT},
- * {@link #FINISH_LAYOUT_REDO_CONFIG}, {@link #FINISH_LAYOUT_REDO_WALLPAPER},
- * or {@link #FINISH_LAYOUT_REDO_ANIM}.
- */
- public int finishPostLayoutPolicyLw();
-
- /**
- * Return true if it is okay to perform animations for an app transition
- * that is about to occur. You may return false for this if, for example,
- * the dream window is currently displayed so the switch should happen
- * immediately.
- */
- public boolean allowAppAnimationsLw();
-
- /**
- * A new window has been focused.
- */
- public int focusChangedLw(WindowState lastFocus, WindowState newFocus);
+ void setAllowLockscreenWhenOn(int displayId, boolean allow);
/**
* Called when the device has started waking up.
@@ -1430,8 +1237,6 @@
*/
public boolean isKeyguardDrawnLw();
- public boolean isShowingDreamLw();
-
/**
* Called when the system is mostly done booting to set whether
* the system should go into safe mode.
@@ -1491,14 +1296,6 @@
public void keepScreenOnStoppedLw();
/**
- * Called when a new system UI visibility is being reported, allowing
- * the policy to adjust what is actually reported.
- * @param visibility The raw visibility reported by the status bar.
- * @return The new desired visibility.
- */
- public int adjustSystemUiVisibilityLw(int visibility);
-
- /**
* Called by System UI to notify of changes to the visibility of Recents.
*/
public void setRecentsVisibilityLw(boolean visible);
@@ -1548,6 +1345,16 @@
public void showGlobalActions();
/**
+ * Returns whether the user setup is complete.
+ */
+ boolean isUserSetupComplete();
+
+ /**
+ * Returns the current UI mode.
+ */
+ int getUiMode();
+
+ /**
* Called when the current user changes. Guaranteed to be called before the broadcast
* of the new user id is made to all listeners.
*
@@ -1602,69 +1409,6 @@
public void startKeyguardExitAnimation(long startTime, long fadeoutDuration);
/**
- * Calculates the stable insets without running a layout.
- *
- * @param displayRotation the current display rotation
- * @param displayWidth the current display width
- * @param displayHeight the current display height
- * @param displayCutout the current display cutout
- * @param outInsets the insets to return
- */
- public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
- DisplayCutout displayCutout, Rect outInsets);
-
-
- /**
- * @return true if the navigation bar is forced to stay visible
- */
- public boolean isNavBarForcedShownLw(WindowState win);
-
- /**
- * @return The side of the screen where navigation bar is positioned.
- * @see #NAV_BAR_LEFT
- * @see #NAV_BAR_RIGHT
- * @see #NAV_BAR_BOTTOM
- */
- @NavigationBarPosition
- int getNavBarPosition();
-
- /**
- * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
- * bar or button bar. See {@link #getNonDecorDisplayWidth}.
- *
- * @param displayRotation the current display rotation
- * @param displayWidth the current display width
- * @param displayHeight the current display height
- * @param displayCutout the current display cutout
- * @param outInsets the insets to return
- */
- public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
- DisplayCutout displayCutout, Rect outInsets);
-
- /**
- * @param displayRotation the current display rotation
- * @param displayWidth the current display width
- * @param displayHeight the current display height
- * @param dockSide the dockside asking if allowed
- * @param originalDockSide the side that was original docked to in split screen
- * @return True if a specified {@param dockSide} is allowed on the current device, or false
- * otherwise. It is guaranteed that at least one dock side for a particular orientation
- * is allowed, so for example, if DOCKED_RIGHT is not allowed, DOCKED_LEFT is allowed.
- * If navigation bar is movable then the docked side would bias towards the
- * {@param originalDockSide}.
- */
- public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
- int displayHeight, int displayRotation);
-
- /**
- * Called when the configuration has changed, and it's safe to load new values from resources.
- */
- public void onConfigurationChanged(DisplayContentInfo displayContentInfo);
-
- public boolean shouldRotateSeamlessly(DisplayRotation displayRotation,
- int oldRotation, int newRotation);
-
- /**
* Called when System UI has been started.
*/
void onSystemUiStarted();
@@ -1697,17 +1441,6 @@
public void requestUserActivityNotification();
/**
- * Called when the state of lock task mode changes. This should be used to disable immersive
- * mode confirmation.
- *
- * @param lockTaskState the new lock task mode state. One of
- * {@link ActivityManager#LOCK_TASK_MODE_NONE},
- * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
- * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
- */
- void onLockTaskStateChangedLw(int lockTaskState);
-
- /**
* Updates the flag about whether AOD is showing.
*
* @return whether the value was changed.
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 6f6846d..3179ce9 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -194,8 +194,10 @@
"/system/bin/traced", // Perfetto.
"/system/bin/traced_probes", // Perfetto.
"webview_zygote",
- "zygote",
- "zygote64",
+ // Temporarily excluded zygote to investigate its forking consequences in
+ // NativeProcessMemoryState.
+ // "zygote",
+ // "zygote64",
};
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 095eaa5..a66f0ca 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -44,36 +44,42 @@
*/
void showPictureInPictureMenu();
- void setWindowState(int window, int state);
+ void setWindowState(int displayId, int window, int state);
/**
* Notifies the status bar that an app transition is pending to delay applying some flags with
* visual impact until {@link #appTransitionReady} is called.
+ *
+ * @param displayId the ID of the display which has this event.
*/
- void appTransitionPending();
+ void appTransitionPending(int displayId);
/**
* Notifies the status bar that a pending app transition has been cancelled.
+ *
+ * @param displayId the ID of the display which has this event.
*/
- void appTransitionCancelled();
+ void appTransitionCancelled(int displayId);
/**
* Notifies the status bar that an app transition is now being executed.
*
+ * @param displayId the ID of the display which has this event.
* @param statusBarAnimationsStartTime the desired start time for all visual animations in the
* status bar caused by this app transition in uptime millis
* @param statusBarAnimationsDuration the duration for all visual animations in the status
* bar caused by this app transition in millis
*/
- void appTransitionStarting(long statusBarAnimationsStartTime, long statusBarAnimationsDuration);
+ void appTransitionStarting(int displayId, long statusBarAnimationsStartTime,
+ long statusBarAnimationsDuration);
void startAssist(Bundle args);
void onCameraLaunchGestureDetected(int source);
- void topAppWindowChanged(boolean menuVisible);
- void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask,
- Rect fullscreenBounds, Rect dockedBounds, String cause);
+ void topAppWindowChanged(int displayId, boolean menuVisible);
+ void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis, int dockedStackVis,
+ int mask, Rect fullscreenBounds, Rect dockedBounds, String cause);
void toggleSplitScreen();
- void appTransitionFinished();
+ void appTransitionFinished(int displayId);
void toggleRecentApps();
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 3e07ebe..1eb44a0 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -39,6 +39,7 @@
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
+import android.view.Display;
import com.android.internal.R;
import com.android.internal.statusbar.IStatusBar;
@@ -237,14 +238,22 @@
}
@Override
- public void topAppWindowChanged(boolean menuVisible) {
+ public void topAppWindowChanged(int displayId, boolean menuVisible) {
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
+ return;
+ }
StatusBarManagerService.this.topAppWindowChanged(menuVisible);
}
@Override
- public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
- int mask,
- Rect fullscreenBounds, Rect dockedBounds, String cause) {
+ public void setSystemUiVisibility(int displayId, int vis, int fullscreenStackVis,
+ int dockedStackVis, int mask, Rect fullscreenBounds, Rect dockedBounds,
+ String cause) {
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
+ return;
+ }
StatusBarManagerService.this.setSystemUiVisibility(vis, fullscreenStackVis,
dockedStackVis, mask, fullscreenBounds, dockedBounds, cause);
}
@@ -259,8 +268,13 @@
}
}
- public void appTransitionFinished() {
+ @Override
+ public void appTransitionFinished(int displayId) {
enforceStatusBarService();
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
+ return;
+ }
if (mBar != null) {
try {
mBar.appTransitionFinished();
@@ -358,7 +372,11 @@
}
@Override
- public void setWindowState(int window, int state) {
+ public void setWindowState(int displayId, int window, int state) {
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
+ return;
+ }
if (mBar != null) {
try {
mBar.setWindowState(window, state);
@@ -367,7 +385,11 @@
}
@Override
- public void appTransitionPending() {
+ public void appTransitionPending(int displayId) {
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
+ return;
+ }
if (mBar != null) {
try {
mBar.appTransitionPending();
@@ -376,7 +398,11 @@
}
@Override
- public void appTransitionCancelled() {
+ public void appTransitionCancelled(int displayId) {
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
+ return;
+ }
if (mBar != null) {
try {
mBar.appTransitionCancelled();
@@ -385,8 +411,12 @@
}
@Override
- public void appTransitionStarting(long statusBarAnimationsStartTime,
+ public void appTransitionStarting(int displayId, long statusBarAnimationsStartTime,
long statusBarAnimationsDuration) {
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ // TODO (b/117478341): Resolve one status bar/ navigation bar assumption
+ return;
+ }
if (mBar != null) {
try {
mBar.appTransitionStarting(
diff --git a/services/core/java/com/android/server/updates/ConversationActionsInstallReceiver.java b/services/core/java/com/android/server/updates/ConversationActionsInstallReceiver.java
new file mode 100644
index 0000000..7310af3
--- /dev/null
+++ b/services/core/java/com/android/server/updates/ConversationActionsInstallReceiver.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.updates;
+
+public class ConversationActionsInstallReceiver extends ConfigUpdateInstallReceiver {
+
+ public ConversationActionsInstallReceiver() {
+ super(
+ "/data/misc/textclassifier/",
+ "actions_suggestions.model",
+ "metadata/actions_suggestions",
+ "version");
+ }
+}
diff --git a/services/core/java/com/android/server/updates/LangIdInstallReceiver.java b/services/core/java/com/android/server/updates/LangIdInstallReceiver.java
index dfe02ec..05dad21 100644
--- a/services/core/java/com/android/server/updates/LangIdInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/LangIdInstallReceiver.java
@@ -21,8 +21,8 @@
public LangIdInstallReceiver() {
super(
"/data/misc/textclassifier/",
- "textclassifier.langid.model",
- "metadata/langid",
+ "lang_id.model",
+ "metadata/lang_id",
"version");
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 409d2b4..6ede423 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -88,7 +88,6 @@
import android.util.Xml;
import android.view.Display;
import android.view.IWindowManager;
-import android.view.WindowManager;
import com.android.internal.R;
import com.android.internal.content.PackageMonitor;
@@ -487,6 +486,8 @@
private void generateCrop(WallpaperData wallpaper) {
boolean success = false;
+ // Only generate crop for default display.
+ final WallpaperData.DisplayData wpData = getDisplayDataOrCreate(wallpaper, DEFAULT_DISPLAY);
Rect cropHint = new Rect(wallpaper.cropHint);
if (DEBUG) {
@@ -494,7 +495,7 @@
+ Integer.toHexString(wallpaper.whichPending)
+ " to " + wallpaper.cropFile.getName()
+ " crop=(" + cropHint.width() + 'x' + cropHint.height()
- + ") dim=(" + wallpaper.width + 'x' + wallpaper.height + ')');
+ + ") dim=(" + wpData.mWidth + 'x' + wpData.mHeight + ')');
}
// Analyse the source; needed in multiple cases
@@ -533,11 +534,11 @@
}
// scale if the crop height winds up not matching the recommended metrics
- needScale = (wallpaper.height != cropHint.height());
+ needScale = (wpData.mHeight != cropHint.height());
if (DEBUG) {
Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
- Slog.v(TAG, "dims: w=" + wallpaper.width + " h=" + wallpaper.height);
+ Slog.v(TAG, "dims: w=" + wpData.mWidth + " h=" + wpData.mHeight);
Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);
Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);
}
@@ -567,7 +568,7 @@
// just let the decode take care of it because we also want to remap where the
// cropHint rectangle lies in the decoded [super]rect.
final BitmapFactory.Options scaler;
- final int actualScale = cropHint.height() / wallpaper.height;
+ final int actualScale = cropHint.height() / wpData.mHeight;
int scale = 1;
while (2*scale < actualScale) {
scale *= 2;
@@ -593,17 +594,18 @@
cropHint.offsetTo(0, 0);
cropHint.right /= scale; // adjust by downsampling factor
cropHint.bottom /= scale;
- final float heightR = ((float)wallpaper.height) / ((float)cropHint.height());
+ final float heightR =
+ ((float) wpData.mHeight) / ((float) cropHint.height());
if (DEBUG) {
Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint);
}
final int destWidth = (int)(cropHint.width() * heightR);
final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped,
- destWidth, wallpaper.height, true);
+ destWidth, wpData.mHeight, true);
if (DEBUG) {
Slog.v(TAG, "Final extract:");
- Slog.v(TAG, " dims: w=" + wallpaper.width
- + " h=" + wallpaper.height);
+ Slog.v(TAG, " dims: w=" + wpData.mWidth
+ + " h=" + wpData.mHeight);
Slog.v(TAG, " out: w=" + finalCrop.getWidth()
+ " h=" + finalCrop.getHeight());
}
@@ -670,13 +672,13 @@
if (connector == null) return;
connector.disconnectLocked();
mLastWallpaper.connection.removeDisplayConnector(displayId);
+ mLastWallpaper.removeDisplayData(displayId);
}
}
}
@Override
public void onDisplayChanged(int displayId) {
- // TODO(b/115486823) Review that do we need to handle display changes.
}
};
@@ -778,16 +780,23 @@
private RemoteCallbackList<IWallpaperManagerCallback> callbacks
= new RemoteCallbackList<IWallpaperManagerCallback>();
- int width = -1;
- int height = -1;
+ private static final class DisplayData {
+ int mWidth = -1;
+ int mHeight = -1;
+ final Rect mPadding = new Rect(0, 0, 0, 0);
+ final int mDisplayId;
+
+ DisplayData(int displayId) {
+ mDisplayId = displayId;
+ }
+ }
+ private SparseArray<DisplayData> mDisplayDatas = new SparseArray<>();
/**
* The crop hint supplied for displaying a subset of the source image
*/
final Rect cropHint = new Rect(0, 0, 0, 0);
- final Rect padding = new Rect(0, 0, 0, 0);
-
WallpaperData(int userId, String inputFileName, String cropFileName) {
this.userId = userId;
final File wallpaperDir = getWallpaperDir(userId);
@@ -803,6 +812,44 @@
boolean sourceExists() {
return wallpaperFile.exists();
}
+
+ void removeDisplayData(int displayId) {
+ mDisplayDatas.remove(displayId);
+ }
+ }
+
+ private WallpaperData.DisplayData getDisplayDataOrCreate(WallpaperData data, int displayId) {
+ WallpaperData.DisplayData wpdData = data.mDisplayDatas.get(displayId);
+ if (wpdData == null) {
+ wpdData = new WallpaperData.DisplayData(displayId);
+ ensureSaneWallpaperDisplaySize(wpdData, displayId);
+ data.mDisplayDatas.append(displayId, wpdData);
+ }
+ return wpdData;
+ }
+
+ private void ensureSaneWallpaperDisplaySize(WallpaperData.DisplayData wpdData,
+ int displayId) {
+ // We always want to have some reasonable width hint.
+ final int baseSize = getMaximumSizeDimension(displayId);
+ if (wpdData.mWidth < baseSize) {
+ wpdData.mWidth = baseSize;
+ }
+ if (wpdData.mHeight < baseSize) {
+ wpdData.mHeight = baseSize;
+ }
+ }
+
+ private int getMaximumSizeDimension(int displayId) {
+ Display display = mDisplayManager.getDisplay(displayId);
+ return display.getMaximumSizeDimension();
+ }
+
+ void forEachDisplayData(WallpaperData data, Consumer<WallpaperData.DisplayData> action) {
+ for (int i = data.mDisplayDatas.size() - 1; i >= 0; i--) {
+ final WallpaperData.DisplayData wpdData = data.mDisplayDatas.valueAt(i);
+ action.accept(wpdData);
+ }
}
int makeWallpaperIdLocked() {
@@ -830,9 +877,11 @@
}
void ensureStatusHandled() {
+ final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(mWallpaper,
+ mDisplayId);
if (mDimensionsChanged) {
try {
- mEngine.setDesiredSize(mWallpaper.width, mWallpaper.height);
+ mEngine.setDesiredSize(wpdData.mWidth, wpdData.mHeight);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to set wallpaper dimensions", e);
}
@@ -840,7 +889,7 @@
}
if (mPaddingChanged) {
try {
- mEngine.setDisplayPadding(mWallpaper.padding);
+ mEngine.setDisplayPadding(wpdData.mPadding);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to set wallpaper padding", e);
}
@@ -857,16 +906,16 @@
return;
}
+ final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper,
+ mDisplayId);
try {
- // TODO(b/115486823) Consider the size of non-default display
connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false,
- wallpaper.width, wallpaper.height,
- wallpaper.padding, mDisplayId);
+ wpdData.mWidth, wpdData.mHeight,
+ wpdData.mPadding, mDisplayId);
} catch (RemoteException e) {
Slog.w(TAG, "Failed attaching wallpaper on display", e);
- // TODO(b/115486823) Failed when attaching a new engine, however, other engines
- // may still working. Should we abandon them all or just ignore this one.
- if (mLastWallpaper != null && !mLastWallpaper.wallpaperUpdating) {
+ if (mLastWallpaper != null && !mLastWallpaper.wallpaperUpdating
+ && connection.getConnectedEngineSize() == 0) {
bindWallpaperComponentLocked(null /* componentName */, false /* force */,
false /* fromUser */, wallpaper, null /* reply */);
}
@@ -952,11 +1001,20 @@
void forEachDisplayConnector(Consumer<DisplayConnector> action) {
for (int i = mDisplayConnector.size() - 1; i >= 0; i--) {
- final DisplayConnector connector = mDisplayConnector.get(i);
+ final DisplayConnector connector = mDisplayConnector.valueAt(i);
action.accept(connector);
}
}
+ int getConnectedEngineSize() {
+ int engineSize = 0;
+ for (int i = mDisplayConnector.size() - 1; i >= 0; i--) {
+ final DisplayConnector connector = mDisplayConnector.valueAt(i);
+ if (connector.mEngine != null) engineSize++;
+ }
+ return engineSize;
+ }
+
DisplayConnector getDisplayConnectorOrCreate(int displayId) {
DisplayConnector connector = mDisplayConnector.get(displayId);
if (connector == null) {
@@ -1128,7 +1186,8 @@
Slog.w(TAG, "Failed to set ambient mode state", e);
}
}
- // TODO(b/115486823) Extends for secondary display.
+ // TODO(multi-display) So far, we have shared the same wallpaper on each display.
+ // Once we have multiple wallpapers on multiple displays, please complete here.
if (displayId == DEFAULT_DISPLAY) {
try {
// This will trigger onComputeColors in the wallpaper engine.
@@ -1560,7 +1619,7 @@
wallpaper.wallpaperComponent = wallpaper.nextWallpaperComponent;
final WallpaperData fallback = new WallpaperData(wallpaper.userId,
WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
- ensureSaneWallpaperData(fallback);
+ ensureSaneWallpaperData(fallback, DEFAULT_DISPLAY);
bindWallpaperComponentLocked(mImageWallpaper, true, false, fallback, reply);
mWaitingForUnlock = true;
}
@@ -1705,8 +1764,15 @@
return false;
}
- // TODO(b/115486823) Extends this method with specific display.
- public void setDimensionHints(int width, int height, String callingPackage)
+ private boolean isValidDisplay(int displayId) {
+ return mDisplayManager.getDisplay(displayId) != null;
+ }
+
+ /**
+ * Sets the dimension hint for the wallpaper. These hints indicate the desired
+ * minimum width and height for the wallpaper in a particular display.
+ */
+ public void setDimensionHints(int width, int height, String callingPackage, int displayId)
throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
if (!isWallpaperSupported(callingPackage)) {
@@ -1719,90 +1785,113 @@
throw new IllegalArgumentException("width and height must be > 0");
}
- if (width != wallpaper.width || height != wallpaper.height) {
- wallpaper.width = width;
- wallpaper.height = height;
- saveSettingsLocked(userId);
+ if (!isValidDisplay(displayId)) {
+ throw new IllegalArgumentException("Cannot find display with id=" + displayId);
+ }
+
+ final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper, displayId);
+ if (width != wpdData.mWidth || height != wpdData.mHeight) {
+ wpdData.mWidth = width;
+ wpdData.mHeight = height;
+ if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId);
if (mCurrentUserId != userId) return; // Don't change the properties now
if (wallpaper.connection != null) {
- // TODO(b/115486823) Extends this method with specific display.
- final IWallpaperEngine engine = wallpaper.connection
- .getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
+ final WallpaperConnection.DisplayConnector connector = wallpaper.connection
+ .getDisplayConnectorOrCreate(displayId);
+ final IWallpaperEngine engine = connector != null ? connector.mEngine : null;
if (engine != null) {
try {
engine.setDesiredSize(width, height);
} catch (RemoteException e) {
}
notifyCallbacksLocked(wallpaper);
- } else if (wallpaper.connection.mService != null) {
+ } else if (wallpaper.connection.mService != null && connector != null) {
// We've attached to the service but the engine hasn't attached back to us
// yet. This means it will be created with the previous dimensions, so we
// need to update it to the new dimensions once it attaches.
- // TODO(b/115486823) Extends this method with specific display.
- wallpaper.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY)
- .mDimensionsChanged = true;
+ connector.mDimensionsChanged = true;
}
}
}
}
}
- public int getWidthHint() throws RemoteException {
+ /**
+ * Returns the desired minimum width for the wallpaper in a particular display.
+ */
+ public int getWidthHint(int displayId) throws RemoteException {
synchronized (mLock) {
+ if (!isValidDisplay(displayId)) {
+ throw new IllegalArgumentException("Cannot find display with id=" + displayId);
+ }
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
if (wallpaper != null) {
- return wallpaper.width;
+ final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper,
+ displayId);
+ return wpdData.mWidth;
} else {
return 0;
}
}
}
- public int getHeightHint() throws RemoteException {
+ /**
+ * Returns the desired minimum height for the wallpaper in a particular display.
+ */
+ public int getHeightHint(int displayId) throws RemoteException {
synchronized (mLock) {
+ if (!isValidDisplay(displayId)) {
+ throw new IllegalArgumentException("Cannot find display with id=" + displayId);
+ }
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.getCallingUserId());
if (wallpaper != null) {
- return wallpaper.height;
+ final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper,
+ displayId);
+ return wpdData.mHeight;
} else {
return 0;
}
}
}
- // TODO(b/115486823) Extends this method with specific display.
- public void setDisplayPadding(Rect padding, String callingPackage) {
+ /**
+ * Sets extra padding that we would like the wallpaper to have outside of the display.
+ */
+ public void setDisplayPadding(Rect padding, String callingPackage, int displayId) {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
if (!isWallpaperSupported(callingPackage)) {
return;
}
synchronized (mLock) {
+ if (!isValidDisplay(displayId)) {
+ throw new IllegalArgumentException("Cannot find display with id=" + displayId);
+ }
int userId = UserHandle.getCallingUserId();
WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
if (padding.left < 0 || padding.top < 0 || padding.right < 0 || padding.bottom < 0) {
throw new IllegalArgumentException("padding must be positive: " + padding);
}
- if (!padding.equals(wallpaper.padding)) {
- wallpaper.padding.set(padding);
- saveSettingsLocked(userId);
+ final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper, displayId);
+ if (!padding.equals(wpdData.mPadding)) {
+ wpdData.mPadding.set(padding);
+ if (displayId == DEFAULT_DISPLAY) saveSettingsLocked(userId);
if (mCurrentUserId != userId) return; // Don't change the properties now
if (wallpaper.connection != null) {
- // TODO(b/115486823) Extends this method with specific display.
- final IWallpaperEngine engine = wallpaper.connection
- .getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
+ final WallpaperConnection.DisplayConnector connector = wallpaper.connection
+ .getDisplayConnectorOrCreate(displayId);
+ final IWallpaperEngine engine = connector != null ? connector.mEngine : null;
if (engine != null) {
try {
engine.setDisplayPadding(padding);
} catch (RemoteException e) {
}
notifyCallbacksLocked(wallpaper);
- } else if (wallpaper.connection.mService != null) {
+ } else if (wallpaper.connection.mService != null && connector != null) {
// We've attached to the service but the engine hasn't attached back to us
// yet. This means it will be created with the previous dimensions, so we
// need to update it to the new dimensions once it attaches.
- // TODO(b/115486823) Extends this method with specific display.
- wallpaper.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY)
- .mPaddingChanged = true;
+ connector.mPaddingChanged = true;
}
}
}
@@ -1850,10 +1939,13 @@
// user switch)
return null;
}
+ // Only for default display.
+ final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper,
+ DEFAULT_DISPLAY);
try {
if (outParams != null) {
- outParams.putInt("width", wallpaper.width);
- outParams.putInt("height", wallpaper.height);
+ outParams.putInt("width", wpdData.mWidth);
+ outParams.putInt("height", wpdData.mHeight);
}
if (cb != null) {
wallpaper.callbacks.register(cb);
@@ -2075,10 +2167,14 @@
// We know a-priori that there is no lock-only wallpaper currently
WallpaperData lockWP = new WallpaperData(userId,
WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ final WallpaperData.DisplayData lockWPDData = getDisplayDataOrCreate(lockWP,
+ DEFAULT_DISPLAY);
+ final WallpaperData.DisplayData sysWPDData = getDisplayDataOrCreate(sysWP,
+ DEFAULT_DISPLAY);
lockWP.wallpaperId = sysWP.wallpaperId;
lockWP.cropHint.set(sysWP.cropHint);
- lockWP.width = sysWP.width;
- lockWP.height = sysWP.height;
+ lockWPDData.mWidth = sysWPDData.mWidth;
+ lockWPDData.mHeight = sysWPDData.mHeight;
lockWP.allowBackup = sysWP.allowBackup;
lockWP.primaryColors = sysWP.primaryColors;
@@ -2478,27 +2574,29 @@
if (DEBUG) {
Slog.v(TAG, "writeWallpaperAttributes id=" + wallpaper.wallpaperId);
}
+ final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper,
+ DEFAULT_DISPLAY);
out.startTag(null, tag);
out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
- out.attribute(null, "width", Integer.toString(wallpaper.width));
- out.attribute(null, "height", Integer.toString(wallpaper.height));
+ out.attribute(null, "width", Integer.toString(wpdData.mWidth));
+ out.attribute(null, "height", Integer.toString(wpdData.mHeight));
out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
- if (wallpaper.padding.left != 0) {
- out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
+ if (wpdData.mPadding.left != 0) {
+ out.attribute(null, "paddingLeft", Integer.toString(wpdData.mPadding.left));
}
- if (wallpaper.padding.top != 0) {
- out.attribute(null, "paddingTop", Integer.toString(wallpaper.padding.top));
+ if (wpdData.mPadding.top != 0) {
+ out.attribute(null, "paddingTop", Integer.toString(wpdData.mPadding.top));
}
- if (wallpaper.padding.right != 0) {
- out.attribute(null, "paddingRight", Integer.toString(wallpaper.padding.right));
+ if (wpdData.mPadding.right != 0) {
+ out.attribute(null, "paddingRight", Integer.toString(wpdData.mPadding.right));
}
- if (wallpaper.padding.bottom != 0) {
- out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
+ if (wpdData.mPadding.bottom != 0) {
+ out.attribute(null, "paddingBottom", Integer.toString(wpdData.mPadding.bottom));
}
if (wallpaper.primaryColors != null) {
@@ -2601,14 +2699,14 @@
wallpaper = new WallpaperData(userId,
WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
mLockWallpaperMap.put(userId, wallpaper);
- ensureSaneWallpaperData(wallpaper);
+ ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY);
} else {
// sanity fallback: we're in bad shape, but establishing a known
// valid system+lock WallpaperData will keep us from dying.
Slog.wtf(TAG, "Didn't find wallpaper in non-lock case!");
wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
mWallpaperMap.put(userId, wallpaper);
- ensureSaneWallpaperData(wallpaper);
+ ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY);
}
}
}
@@ -2637,6 +2735,8 @@
}
}
boolean success = false;
+ final WallpaperData.DisplayData wpdData = getDisplayDataOrCreate(wallpaper,
+ DEFAULT_DISPLAY);
try {
stream = new FileInputStream(file);
XmlPullParser parser = Xml.newPullParser();
@@ -2663,8 +2763,8 @@
}
if (DEBUG) {
- Slog.v(TAG, "mWidth:" + wallpaper.width);
- Slog.v(TAG, "mHeight:" + wallpaper.height);
+ Slog.v(TAG, "mWidth:" + wpdData.mWidth);
+ Slog.v(TAG, "mHeight:" + wpdData.mHeight);
Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
Slog.v(TAG, "primaryColors:" + wallpaper.primaryColors);
Slog.v(TAG, "mName:" + wallpaper.name);
@@ -2700,10 +2800,10 @@
IoUtils.closeQuietly(stream);
if (!success) {
- wallpaper.width = -1;
- wallpaper.height = -1;
+ wpdData.mWidth = -1;
+ wpdData.mHeight = -1;
wallpaper.cropHint.set(0, 0, 0, 0);
- wallpaper.padding.set(0, 0, 0, 0);
+ wpdData.mPadding.set(0, 0, 0, 0);
wallpaper.name = "";
mLockWallpaperMap.remove(userId);
@@ -2717,26 +2817,22 @@
}
}
- ensureSaneWallpaperData(wallpaper);
+ ensureSaneWallpaperData(wallpaper, DEFAULT_DISPLAY);
WallpaperData lockWallpaper = mLockWallpaperMap.get(userId);
if (lockWallpaper != null) {
- ensureSaneWallpaperData(lockWallpaper);
+ ensureSaneWallpaperData(lockWallpaper, DEFAULT_DISPLAY);
}
}
- private void ensureSaneWallpaperData(WallpaperData wallpaper) {
- // We always want to have some reasonable width hint.
- int baseSize = getMaximumSizeDimension();
- if (wallpaper.width < baseSize) {
- wallpaper.width = baseSize;
- }
- if (wallpaper.height < baseSize) {
- wallpaper.height = baseSize;
- }
- // and crop, if not previously specified
- if (wallpaper.cropHint.width() <= 0
- || wallpaper.cropHint.height() <= 0) {
- wallpaper.cropHint.set(0, 0, wallpaper.width, wallpaper.height);
+ private void ensureSaneWallpaperData(WallpaperData wallpaper, int displayId) {
+ final WallpaperData.DisplayData size = getDisplayDataOrCreate(wallpaper, displayId);
+
+ if (displayId == DEFAULT_DISPLAY) {
+ // crop, if not previously specified
+ if (wallpaper.cropHint.width() <= 0
+ || wallpaper.cropHint.height() <= 0) {
+ wallpaper.cropHint.set(0, 0, size.mWidth, size.mHeight);
+ }
}
}
@@ -2752,19 +2848,20 @@
wallpaper.wallpaperId = makeWallpaperIdLocked();
}
+ final WallpaperData.DisplayData wpData = getDisplayDataOrCreate(wallpaper, DEFAULT_DISPLAY);
+
if (!keepDimensionHints) {
- wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
- wallpaper.height = Integer.parseInt(parser
- .getAttributeValue(null, "height"));
+ wpData.mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
+ wpData.mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
}
wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
- wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
- wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
- wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
- wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
+ wpData.mPadding.left = getAttributeInt(parser, "paddingLeft", 0);
+ wpData.mPadding.top = getAttributeInt(parser, "paddingTop", 0);
+ wpData.mPadding.right = getAttributeInt(parser, "paddingRight", 0);
+ wpData.mPadding.bottom = getAttributeInt(parser, "paddingBottom", 0);
int colorsCount = getAttributeInt(parser, "colorsCount", 0);
if (colorsCount > 0) {
Color primary = null, secondary = null, tertiary = null;
@@ -2787,12 +2884,6 @@
wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
}
- private int getMaximumSizeDimension() {
- WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
- Display d = wm.getDefaultDisplay();
- return d.getMaximumSizeDimension();
- }
-
// Called by SystemBackupAgent after files are restored to disk.
public void settingsRestored() {
// Verify caller is the system
@@ -2832,7 +2923,7 @@
if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success
+ " id=" + wallpaper.wallpaperId);
if (success) {
- generateCrop(wallpaper); // based on the new image + metadata
+ generateCrop(wallpaper); // based on the new image + metadata
bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, true, false,
wallpaper, null);
}
@@ -2937,12 +3028,16 @@
WallpaperData wallpaper = mWallpaperMap.valueAt(i);
pw.print(" User "); pw.print(wallpaper.userId);
pw.print(": id="); pw.println(wallpaper.wallpaperId);
- pw.print(" mWidth=");
- pw.print(wallpaper.width);
- pw.print(" mHeight=");
- pw.println(wallpaper.height);
+ forEachDisplayData(wallpaper, wpSize -> {
+ pw.print(" displayId=");
+ pw.println(wpSize.mDisplayId);
+ pw.print(" mWidth=");
+ pw.print(wpSize.mWidth);
+ pw.print(" mHeight=");
+ pw.println(wpSize.mHeight);
+ pw.print(" mPadding="); pw.println(wpSize.mPadding);
+ });
pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
- pw.print(" mPadding="); pw.println(wallpaper.padding);
pw.print(" mName="); pw.println(wallpaper.name);
pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
pw.print(" mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
@@ -2973,11 +3068,15 @@
for (int i = 0; i < mLockWallpaperMap.size(); i++) {
WallpaperData wallpaper = mLockWallpaperMap.valueAt(i);
pw.print(" User "); pw.print(wallpaper.userId);
- pw.print(": id="); pw.println(wallpaper.wallpaperId);
- pw.print(" mWidth="); pw.print(wallpaper.width);
- pw.print(" mHeight="); pw.println(wallpaper.height);
+ pw.print(": id="); pw.println(wallpaper.wallpaperId);
+ forEachDisplayData(wallpaper, wpSize -> {
+ pw.print(" displayId=");
+ pw.println(wpSize.mDisplayId);
+ pw.print(" mWidth="); pw.print(wpSize.mWidth);
+ pw.print(" mHeight="); pw.println(wpSize.mHeight);
+ pw.print(" mPadding="); pw.println(wpSize.mPadding);
+ });
pw.print(" mCropHint="); pw.println(wallpaper.cropHint);
- pw.print(" mPadding="); pw.println(wallpaper.padding);
pw.print(" mName="); pw.println(wallpaper.name);
pw.print(" mAllowBackup="); pw.println(wallpaper.allowBackup);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index c43e64e..5e92b9e 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2354,7 +2354,7 @@
// bounds would end up too small.
outBounds.set(0, 0, maxActivityWidth + appBounds.left, maxActivityHeight + appBounds.top);
- if (service.mWindowManager.getNavBarPosition() == NAV_BAR_LEFT) {
+ if (service.mWindowManager.getNavBarPosition(getDisplayId()) == NAV_BAR_LEFT) {
// Position the activity frame on the opposite side of the nav bar.
outBounds.left = appBounds.right - maxActivityWidth;
outBounds.right = appBounds.right;
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 694e9d1..14b2f01c 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1039,11 +1039,8 @@
boolean didSomething = false;
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ActivityDisplay display = mActivityDisplays.get(displayNdx);
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = display.getChildAt(stackNdx);
- if (!isTopDisplayFocusedStack(stack)) {
- continue;
- }
+ final ActivityStack stack = display.getFocusedStack();
+ if (stack != null) {
stack.getAllRunningVisibleActivitiesLocked(mTmpActivityList);
final ActivityRecord top = stack.topRunningActivityLocked();
final int size = mTmpActivityList.size();
@@ -2429,6 +2426,7 @@
// We give preference to the launch preference in activity options.
if (options != null) {
taskId = options.getLaunchTaskId();
+ displayId = options.getLaunchDisplayId();
}
// First preference for stack goes to the task Id set in the activity options. Use the stack
@@ -2448,7 +2446,7 @@
T stack;
// Next preference for stack goes to the display Id set the candidate display.
- if (launchParams != null) {
+ if (launchParams != null && launchParams.mPreferredDisplayId != INVALID_DISPLAY) {
displayId = launchParams.mPreferredDisplayId;
}
if (displayId != INVALID_DISPLAY && canLaunchOnDisplay(r, displayId)) {
@@ -2566,10 +2564,10 @@
windowingMode = options != null ? options.getLaunchWindowingMode()
: r.getWindowingMode();
}
- return activityDisplay.createStack(
- windowingMode,
- options != null ? options.getLaunchActivityType() : r.getActivityType(),
- true /*onTop*/);
+ final int activityType =
+ options != null && options.getLaunchActivityType() != ACTIVITY_TYPE_UNDEFINED
+ ? options.getLaunchActivityType() : r.getActivityType();
+ return activityDisplay.createStack(windowingMode, activityType, true /*onTop*/);
}
Slog.w(TAG, "getValidLaunchStackOnDisplay: can't launch on displayId " + displayId);
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index d4c1bca..90f3ff8 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1859,7 +1859,8 @@
}
}
- if (mStartActivity.isActivityTypeHome() && intentActivity != null
+ if (intentActivity != null
+ && (mStartActivity.isActivityTypeHome() || intentActivity.isActivityTypeHome())
&& intentActivity.getDisplayId() != mPreferredDisplayId) {
// Do not reuse home activity on other displays.
intentActivity = null;
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index e65f3b4..32a6f74 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -96,14 +96,15 @@
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
- int transit = mDisplayContent.mAppTransition.getAppTransition();
+ final AppTransition appTransition = mDisplayContent.mAppTransition;
+ int transit = appTransition.getAppTransition();
if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
transit = WindowManager.TRANSIT_UNSET;
}
mDisplayContent.mSkipAppTransitionAnimation = false;
mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
- mDisplayContent.mAppTransition.removeAppTransitionTimeoutCallbacks();
+ appTransition.removeAppTransitionTimeoutCallbacks();
mDisplayContent.mWallpaperMayChange = false;
@@ -141,7 +142,7 @@
// done behind a dream window.
final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
mDisplayContent.mClosingApps);
- final boolean allowAnimations = mService.mPolicy.allowAppAnimationsLw();
+ final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
final AppWindowToken animLpToken = allowAnimations
? findAnimLayoutParamsToken(transit, activityTypes)
: null;
@@ -165,15 +166,15 @@
handleClosingApps(transit, animLp, voiceInteraction);
handleOpeningApps(transit, animLp, voiceInteraction);
- mDisplayContent.mAppTransition.setLastAppTransition(transit, topOpeningApp,
+ appTransition.setLastAppTransition(transit, topOpeningApp,
topClosingApp);
- final int flags = mDisplayContent.mAppTransition.getTransitFlags();
- layoutRedo = mDisplayContent.mAppTransition.goodToGo(transit, topOpeningApp,
+ final int flags = appTransition.getTransitFlags();
+ layoutRedo = appTransition.goodToGo(transit, topOpeningApp,
topClosingApp, mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps);
handleNonAppWindowsInTransition(transit, flags);
- mDisplayContent.mAppTransition.postAnimationCallback();
- mDisplayContent.mAppTransition.clear();
+ appTransition.postAnimationCallback();
+ appTransition.clear();
} finally {
mService.mSurfaceAnimationRunner.continueStartingAnimations();
}
@@ -254,8 +255,8 @@
}
/**
- * @return The set of {@link WindowConfiguration.ActivityType}s contained in the set of apps in
- * {@code array1} and {@code array2}.
+ * @return The set of {@link android.app.WindowConfiguration.ActivityType}s contained in the set
+ * of apps in {@code array1} and {@code array2}.
*/
private static ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
ArraySet<AppWindowToken> array2) {
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/wm/BarController.java
similarity index 90%
rename from services/core/java/com/android/server/policy/BarController.java
rename to services/core/java/com/android/server/wm/BarController.java
index 14c985c..a335fa2 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.policy;
+package com.android.server.wm;
import static com.android.server.wm.BarControllerProto.STATE;
import static com.android.server.wm.BarControllerProto.TRANSIENT_STATE;
@@ -30,7 +30,7 @@
import android.view.WindowManager;
import com.android.server.LocalServices;
-import com.android.server.policy.WindowManagerPolicy.WindowState;
+import com.android.server.UiThread;
import com.android.server.statusbar.StatusBarManagerInternal;
import java.io.PrintWriter;
@@ -59,7 +59,7 @@
private final int mTranslucentWmFlag;
protected final Handler mHandler;
private final Object mServiceAquireLock = new Object();
- protected StatusBarManagerInternal mStatusBarInternal;
+ private StatusBarManagerInternal mStatusBarInternal;
protected WindowState mWin;
private int mState = StatusBarManager.WINDOW_STATE_SHOWING;
@@ -73,7 +73,7 @@
private OnBarVisibilityChangedListener mVisibilityChangeListener;
- public BarController(String tag, int transientFlag, int unhideFlag, int translucentFlag,
+ BarController(String tag, int transientFlag, int unhideFlag, int translucentFlag,
int statusBarManagerId, int translucentWmFlag, int transparentFlag) {
mTag = "BarController." + tag;
mTransientFlag = transientFlag;
@@ -85,7 +85,7 @@
mHandler = new BarHandler();
}
- public void setWindow(WindowState win) {
+ void setWindow(WindowState win) {
mWin = win;
}
@@ -94,11 +94,11 @@
*
* This is used to determine if letterboxes interfere with the display of such content.
*/
- public void setContentFrame(Rect frame) {
+ void setContentFrame(Rect frame) {
mContentFrame.set(frame);
}
- public void setShowTransparent(boolean transparent) {
+ void setShowTransparent(boolean transparent) {
if (transparent != mShowTransparent) {
mShowTransparent = transparent;
mSetUnHideFlagWhenNextTransparent = transparent;
@@ -106,27 +106,27 @@
}
}
- public void showTransient() {
+ void showTransient() {
if (mWin != null) {
setTransientBarState(TRANSIENT_BAR_SHOW_REQUESTED);
}
}
- public boolean isTransientShowing() {
+ boolean isTransientShowing() {
return mTransientBarState == TRANSIENT_BAR_SHOWING;
}
- public boolean isTransientShowRequested() {
+ boolean isTransientShowRequested() {
return mTransientBarState == TRANSIENT_BAR_SHOW_REQUESTED;
}
- public boolean wasRecentlyTranslucent() {
+ boolean wasRecentlyTranslucent() {
return (SystemClock.uptimeMillis() - mLastTranslucent) < TRANSLUCENT_ANIMATION_DELAY_MS;
}
- public void adjustSystemUiVisibilityLw(int oldVis, int vis) {
- if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING &&
- (vis & mTransientFlag) == 0) {
+ void adjustSystemUiVisibilityLw(int oldVis, int vis) {
+ if (mWin != null && mTransientBarState == TRANSIENT_BAR_SHOWING
+ && (vis & mTransientFlag) == 0) {
// sysui requests hide
setTransientBarState(TRANSIENT_BAR_HIDING);
setBarShowingLw(false);
@@ -136,7 +136,7 @@
}
}
- public int applyTranslucentFlagLw(WindowState win, int vis, int oldVis) {
+ int applyTranslucentFlagLw(WindowState win, int vis, int oldVis) {
if (mWin != null) {
if (win != null && (win.getAttrs().privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
@@ -164,7 +164,7 @@
return win == null || !win.isLetterboxedOverlappingWith(mContentFrame);
}
- public boolean setBarShowingLw(final boolean show) {
+ boolean setBarShowingLw(final boolean show) {
if (mWin == null) return false;
if (show && mTransientBarState == TRANSIENT_BAR_HIDING) {
mPendingShow = true;
@@ -227,7 +227,7 @@
public void run() {
StatusBarManagerInternal statusbar = getStatusBarInternal();
if (statusbar != null) {
- statusbar.setWindowState(mStatusBarManagerId, state);
+ statusbar.setWindowState(mWin.getDisplayId(), mStatusBarManagerId, state);
}
}
});
@@ -236,7 +236,7 @@
return false;
}
- public boolean checkHiddenLw() {
+ boolean checkHiddenLw() {
if (mWin != null && mWin.isDrawnLw()) {
if (!mWin.isVisibleLw() && !mWin.isAnimatingLw()) {
updateStateLw(StatusBarManager.WINDOW_STATE_HIDDEN);
@@ -254,7 +254,7 @@
return false;
}
- public boolean checkShowTransientBarLw() {
+ boolean checkShowTransientBarLw() {
if (mTransientBarState == TRANSIENT_BAR_SHOWING) {
if (DEBUG) Slog.d(mTag, "Not showing transient bar, already shown");
return false;
@@ -272,7 +272,7 @@
}
}
- public int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) {
+ int updateVisibilityLw(boolean transientAllowed, int oldVis, int vis) {
if (mWin == null) return vis;
if (isTransientShowing() || isTransientShowRequested()) { // transient bar requested
if (transientAllowed) {
@@ -296,8 +296,8 @@
vis |= mTransientFlag; // ignore clear requests until transition completes
vis &= ~View.SYSTEM_UI_FLAG_LOW_PROFILE; // never show transient bars in low profile
}
- if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0 ||
- ((vis | oldVis) & mTransparentFlag) != 0) {
+ if ((vis & mTranslucentFlag) != 0 || (oldVis & mTranslucentFlag) != 0
+ || ((vis | oldVis) & mTransparentFlag) != 0) {
mLastTranslucent = SystemClock.uptimeMillis();
}
return vis;
@@ -330,14 +330,14 @@
throw new IllegalArgumentException("Unknown state " + state);
}
- public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ void writeToProto(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(STATE, mState);
proto.write(TRANSIENT_STATE, mTransientBarState);
proto.end(token);
}
- public void dump(PrintWriter pw, String prefix) {
+ void dump(PrintWriter pw, String prefix) {
if (mWin != null) {
pw.print(prefix); pw.println(mTag);
pw.print(prefix); pw.print(" "); pw.print("mState"); pw.print('=');
@@ -349,6 +349,10 @@
}
private class BarHandler extends Handler {
+ BarHandler() {
+ super(UiThread.getHandler().getLooper());
+ }
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2f7956e..886b2ff 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -156,6 +156,7 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
+import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -182,9 +183,6 @@
/**
* Utility class for keeping track of the WindowStates and other pertinent contents of a
* particular Display.
- *
- * IMPORTANT: No method from this class should ever be used without holding
- * WindowManagerService.mWindowMap.
*/
class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer>
implements WindowManagerPolicy.DisplayContentInfo {
@@ -289,7 +287,8 @@
* @see WindowManagerService#createWatermarkInTransaction()
*/
final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics();
- /** @see #computeCompatSmallestWidth(boolean, int, int, int, int) */
+
+ /** @see #computeCompatSmallestWidth(boolean, int, int, int, DisplayCutout) */
private final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
/**
@@ -508,6 +507,11 @@
private final PointerEventDispatcher mPointerEventDispatcher;
+ // Last systemUiVisibility we received from status bar.
+ private int mLastStatusBarVisibility = 0;
+ // Last systemUiVisibility we dispatched to windows.
+ private int mLastDispatchedSystemUiVisibility = 0;
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final AppWindowToken atoken = w.mAppToken;
@@ -649,7 +653,7 @@
w.mLayoutNeeded = false;
w.prelayout();
final boolean firstLayout = !w.isLaidOut();
- mService.mPolicy.layoutWindowLw(w, null, mDisplayFrames);
+ getDisplayPolicy().layoutWindowLw(w, null, mDisplayFrames);
w.mLayoutSeq = mLayoutSeq;
// If this is the first layout, we need to initialize the last inset values as
@@ -688,7 +692,7 @@
}
w.mLayoutNeeded = false;
w.prelayout();
- mService.mPolicy.layoutWindowLw(w, w.getParentWindow(), mDisplayFrames);
+ getDisplayPolicy().layoutWindowLw(w, w.getParentWindow(), mDisplayFrames);
w.mLayoutSeq = mLayoutSeq;
if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.getFrameLw()
+ " mContainingFrame=" + w.getContainingFrame()
@@ -708,7 +712,7 @@
};
private final Consumer<WindowState> mApplyPostLayoutPolicy =
- w -> mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs, w.getParentWindow(),
+ w -> getDisplayPolicy().applyPostLayoutPolicyLw(w, w.mAttrs, w.getParentWindow(),
mInputMethodTarget);
private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
@@ -838,15 +842,6 @@
mDisplayFrames = new DisplayFrames(mDisplayId, mDisplayInfo,
calculateDisplayCutoutForRotation(mDisplayInfo.rotation));
initializeDisplayBaseInfo();
- mDisplayPolicy = new DisplayPolicy(service);
- mDisplayRotation = new DisplayRotation(service, this);
- if (isDefaultDisplay) {
- // The policy may be invoked right after here, so it requires the necessary default
- // fields of this display content.
- mService.mPolicy.setDefaultDisplay(this);
- }
- mDividerControllerLocked = new DockedStackDividerController(service, this);
- mPinnedStackControllerLocked = new PinnedStackController(service, this);
mAppTransition = new AppTransition(service.mContext, service, this);
mAppTransition.registerListenerLocked(service.mActivityManagerAppTransitionNotifier);
@@ -857,6 +852,30 @@
mBoundsAnimationController = new BoundsAnimationController(service.mContext,
mAppTransition, SurfaceAnimationThread.getHandler(), animationHandler);
+ if (mService.mInputManager != null) {
+ final InputChannel inputChannel = mService.mInputManager.monitorInput("Display "
+ + mDisplayId, mDisplayId);
+ mPointerEventDispatcher = inputChannel != null
+ ? new PointerEventDispatcher(inputChannel) : null;
+ } else {
+ mPointerEventDispatcher = null;
+ }
+ mDisplayPolicy = new DisplayPolicy(service, this);
+ mDisplayRotation = new DisplayRotation(service, this);
+ if (isDefaultDisplay) {
+ // The policy may be invoked right after here, so it requires the necessary default
+ // fields of this display content.
+ mService.mPolicy.setDefaultDisplay(this);
+ }
+ if (mService.mDisplayReady) {
+ mDisplayPolicy.onConfigurationChanged();
+ }
+ if (mService.mSystemReady) {
+ mDisplayPolicy.systemReady();
+ }
+ mDividerControllerLocked = new DockedStackDividerController(service, this);
+ mPinnedStackControllerLocked = new PinnedStackController(service, this);
+
// We use this as our arbitrary surface size for buffer-less parents
// that don't impose cropping on their children. It may need to be larger
// than the display size because fullscreen windows can be shifted offscreen
@@ -895,15 +914,6 @@
mService.mAnimator.addDisplayLocked(mDisplayId);
mInputMonitor = new InputMonitor(service, mDisplayId);
-
- if (mService.mInputManager != null) {
- final InputChannel inputChannel = mService.mInputManager.monitorInput("Display "
- + mDisplayId, mDisplayId);
- mPointerEventDispatcher = inputChannel != null
- ? new PointerEventDispatcher(inputChannel) : null;
- } else {
- mPointerEventDispatcher = null;
- }
}
boolean isReady() {
@@ -1223,7 +1233,7 @@
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id="
+ mDisplayId + " based on lastOrientation=" + lastOrientation
+ " and oldRotation=" + oldRotation);
- boolean mayRotateSeamlessly = mService.mPolicy.shouldRotateSeamlessly(mDisplayRotation,
+ boolean mayRotateSeamlessly = mDisplayPolicy.shouldRotateSeamlessly(mDisplayRotation,
oldRotation, rotation);
if (mayRotateSeamlessly) {
@@ -1286,7 +1296,7 @@
setLayoutNeeded();
final int[] anim = new int[2];
- mService.mPolicy.selectRotationAnimationLw(anim);
+ mDisplayPolicy.selectRotationAnimationLw(anim);
if (!rotateSeamlessly) {
mService.startFreezingDisplayLocked(anim[0], anim[1], this);
@@ -1445,10 +1455,10 @@
final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(mRotation);
final DisplayCutout displayCutout = wmDisplayCutout.getDisplayCutout();
- final int appWidth = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode,
- mDisplayId, displayCutout);
- final int appHeight = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode,
- mDisplayId, displayCutout);
+ final int appWidth = mDisplayPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode,
+ displayCutout);
+ final int appHeight = mDisplayPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode,
+ displayCutout);
mDisplayInfo.rotation = mRotation;
mDisplayInfo.logicalWidth = dw;
mDisplayInfo.logicalHeight = dh;
@@ -1527,13 +1537,13 @@
final float density = mDisplayMetrics.density;
config.screenWidthDp =
- (int)(mService.mPolicy.getConfigDisplayWidth(dw, dh, displayInfo.rotation,
- config.uiMode, mDisplayId, displayInfo.displayCutout) / density);
+ (int)(mDisplayPolicy.getConfigDisplayWidth(dw, dh, displayInfo.rotation,
+ config.uiMode, displayInfo.displayCutout) / density);
config.screenHeightDp =
- (int)(mService.mPolicy.getConfigDisplayHeight(dw, dh, displayInfo.rotation,
- config.uiMode, mDisplayId, displayInfo.displayCutout) / density);
+ (int)(mDisplayPolicy.getConfigDisplayHeight(dw, dh, displayInfo.rotation,
+ config.uiMode, displayInfo.displayCutout) / density);
- mService.mPolicy.getNonDecorInsetsLw(displayInfo.rotation, dw, dh,
+ mDisplayPolicy.getNonDecorInsetsLw(displayInfo.rotation, dw, dh,
displayInfo.displayCutout, mTmpRect);
final int leftInset = mTmpRect.left;
final int topInset = mTmpRect.top;
@@ -1544,8 +1554,8 @@
final boolean rotated = (displayInfo.rotation == Surface.ROTATION_90
|| displayInfo.rotation == Surface.ROTATION_270);
- computeSizeRangesAndScreenLayout(displayInfo, mDisplayId, rotated, config.uiMode, dw, dh,
- density, config);
+ computeSizeRangesAndScreenLayout(displayInfo, rotated, config.uiMode, dw, dh, density,
+ config);
config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
| ((displayInfo.flags & Display.FLAG_ROUND) != 0
@@ -1555,7 +1565,7 @@
config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode, dw,
- dh, displayInfo.displayCutout, mDisplayId);
+ dh, displayInfo.displayCutout);
config.densityDpi = displayInfo.logicalDensityDpi;
config.colorMode =
@@ -1624,6 +1634,8 @@
mService.mH.sendEmptyMessage(WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
}
+ mDisplayPolicy.updateConfigurationDependentBehaviors();
+
// Let the policy update hidden states.
config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
@@ -1632,7 +1644,7 @@
}
private int computeCompatSmallestWidth(boolean rotated, int uiMode, int dw, int dh,
- DisplayCutout displayCutout, int displayId) {
+ DisplayCutout displayCutout) {
mTmpDisplayMetrics.setTo(mDisplayMetrics);
final DisplayMetrics tmpDm = mTmpDisplayMetrics;
final int unrotDw, unrotDh;
@@ -1644,22 +1656,22 @@
unrotDh = dh;
}
int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh,
- displayCutout, displayId);
+ displayCutout);
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw,
- displayCutout, displayId);
+ displayCutout);
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh,
- displayCutout, displayId);
+ displayCutout);
sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw,
- displayCutout, displayId);
+ displayCutout);
return sw;
}
private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode,
- DisplayMetrics dm, int dw, int dh, DisplayCutout displayCutout, int displayId) {
- dm.noncompatWidthPixels = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
- displayId, displayCutout);
- dm.noncompatHeightPixels = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
- uiMode, displayId, displayCutout);
+ DisplayMetrics dm, int dw, int dh, DisplayCutout displayCutout) {
+ dm.noncompatWidthPixels = mDisplayPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
+ displayCutout);
+ dm.noncompatHeightPixels = mDisplayPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode,
+ displayCutout);
float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
if (curSize == 0 || size < curSize) {
@@ -1668,8 +1680,8 @@
return curSize;
}
- private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, int displayId,
- boolean rotated, int uiMode, int dw, int dh, float density, Configuration outConfig) {
+ private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated,
+ int uiMode, int dw, int dh, float density, Configuration outConfig) {
// We need to determine the smallest width that will occur under normal
// operation. To this, start with the base screen size and compute the
@@ -1687,34 +1699,28 @@
displayInfo.smallestNominalAppHeight = 1<<30;
displayInfo.largestNominalAppWidth = 0;
displayInfo.largestNominalAppHeight = 0;
- adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_0, uiMode, unrotDw,
- unrotDh);
- adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_90, uiMode, unrotDh,
- unrotDw);
- adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_180, uiMode, unrotDw,
- unrotDh);
- adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_270, uiMode, unrotDh,
- unrotDw);
+ adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, uiMode, unrotDw, unrotDh);
+ adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, uiMode, unrotDh, unrotDw);
+ adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, uiMode, unrotDw, unrotDh);
+ adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, uiMode, unrotDh, unrotDw);
int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode,
- displayInfo.displayCutout, displayId);
+ displayInfo.displayCutout);
sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode,
- displayInfo.displayCutout, displayId);
+ displayInfo.displayCutout);
sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode,
- displayInfo.displayCutout, displayId);
+ displayInfo.displayCutout);
sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode,
- displayInfo.displayCutout, displayId);
+ displayInfo.displayCutout);
outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
outConfig.screenLayout = sl;
}
private int reduceConfigLayout(int curLayout, int rotation, float density, int dw, int dh,
- int uiMode, DisplayCutout displayCutout, int displayId) {
+ int uiMode, DisplayCutout displayCutout) {
// Get the app screen size at this rotation.
- int w = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayId,
- displayCutout);
- int h = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayId,
- displayCutout);
+ int w = mDisplayPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayCutout);
+ int h = mDisplayPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayCutout);
// Compute the screen layout size class for this rotation.
int longSize = w;
@@ -1729,20 +1735,20 @@
return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
}
- private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int displayId, int rotation,
+ private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation,
int uiMode, int dw, int dh) {
final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(
rotation).getDisplayCutout();
- final int width = mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode,
- displayId, displayCutout);
+ final int width = mDisplayPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode,
+ displayCutout);
if (width < displayInfo.smallestNominalAppWidth) {
displayInfo.smallestNominalAppWidth = width;
}
if (width > displayInfo.largestNominalAppWidth) {
displayInfo.largestNominalAppWidth = width;
}
- final int height = mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode,
- displayId, displayCutout);
+ final int height = mDisplayPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode,
+ displayCutout);
if (height < displayInfo.smallestNominalAppHeight) {
displayInfo.smallestNominalAppHeight = height;
}
@@ -1887,6 +1893,9 @@
@Override
public void onConfigurationChanged(Configuration newParentConfig) {
super.onConfigurationChanged(newParentConfig);
+ if (mDisplayPolicy != null) {
+ mDisplayPolicy.onConfigurationChanged();
+ }
// If there was no pinned stack, we still need to notify the controller of the display info
// update as a result of the config change.
@@ -2383,7 +2392,7 @@
mDisplayReady = false;
mRemovingDisplay = false;
}
-
+ mDisplayPolicy.onDisplayRemoved();
mInputMonitor.onRemoved();
mService.mWindowPlacerLocked.requestTraversal();
}
@@ -2659,6 +2668,10 @@
}
}
pw.print(" mFocusedApp="); pw.println(mFocusedApp);
+ if (mLastStatusBarVisibility != 0) {
+ pw.print(" mLastStatusBarVisibility=0x");
+ pw.println(Integer.toHexString(mLastStatusBarVisibility));
+ }
pw.println();
mWallpaperController.dump(pw, " ");
@@ -2852,9 +2865,7 @@
}
}
- // System UI is only shown on the default display.
- int focusChanged = isDefaultDisplay
- ? mService.mPolicy.focusChangedLw(oldFocus, newFocus) : 0;
+ int focusChanged = getDisplayPolicy().focusChangedLw(oldFocus, newFocus);
if (imWindowChanged && oldFocus != mInputMethodWindow) {
// Focus of the input method window changed. Perform layout if needed.
@@ -3321,6 +3332,31 @@
return win != null;
}
+ void statusBarVisibilityChanged(int visibility) {
+ mLastStatusBarVisibility = visibility;
+ visibility = getDisplayPolicy().adjustSystemUiVisibilityLw(visibility);
+ updateStatusBarVisibilityLocked(visibility);
+ }
+
+ private boolean updateStatusBarVisibilityLocked(int visibility) {
+ if (mLastDispatchedSystemUiVisibility == visibility) {
+ return false;
+ }
+ final int globalDiff = (visibility ^ mLastDispatchedSystemUiVisibility)
+ // We are only interested in differences of one of the
+ // clearable flags...
+ & View.SYSTEM_UI_CLEARABLE_FLAGS
+ // ...if it has actually been cleared.
+ & ~visibility;
+
+ mLastDispatchedSystemUiVisibility = visibility;
+ if (isDefaultDisplay) {
+ mService.mInputManager.setSystemUiVisibility(visibility);
+ }
+ updateSystemUiVisibility(visibility, globalDiff);
+ return true;
+ }
+
void updateSystemUiVisibility(int visibility, int globalDiff) {
forAllWindows(w -> {
try {
@@ -3341,6 +3377,13 @@
}, true /* traverseTopToBottom */);
}
+ void reevaluateStatusBarVisibility() {
+ int visibility = getDisplayPolicy().adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
+ if (updateStatusBarVisibilityLocked(visibility)) {
+ mService.mWindowPlacerLocked.requestTraversal();
+ }
+ }
+
void onWindowFreezeTimeout() {
Slog.w(TAG_WM, "Window freeze timeout expired.");
mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
@@ -3372,9 +3415,6 @@
// TODO: Super crazy long method that should be broken down...
void applySurfaceChangesTransaction(boolean recoveringMemory) {
-
- final int dw = mDisplayInfo.logicalWidth;
- final int dh = mDisplayInfo.logicalHeight;
final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;
mTmpUpdateAllDrawn.clear();
@@ -3417,13 +3457,11 @@
// FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think it is animating.
pendingLayoutChanges = 0;
- if (isDefaultDisplay) {
- mService.mPolicy.beginPostLayoutPolicyLw(dw, dh);
- forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
- pendingLayoutChanges |= mService.mPolicy.finishPostLayoutPolicyLw();
- if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
- "after finishPostLayoutPolicyLw", pendingLayoutChanges);
- }
+ mDisplayPolicy.beginPostLayoutPolicyLw();
+ forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
+ pendingLayoutChanges |= mDisplayPolicy.finishPostLayoutPolicyLw();
+ if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
+ "after finishPostLayoutPolicyLw", pendingLayoutChanges);
} while (pendingLayoutChanges != 0);
mTmpApplySurfaceChangesTransactionState.reset();
@@ -3513,12 +3551,7 @@
// TODO: Not sure if we really need to set the rotation here since we are updating from the
// display info above...
mDisplayFrames.mRotation = mRotation;
- mService.mPolicy.beginLayoutLw(mDisplayFrames, getConfiguration().uiMode);
- if (isDefaultDisplay) {
- // Not needed on non-default displays.
- mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw();
- mService.mScreenRect.set(0, 0, dw, dh);
- }
+ mDisplayPolicy.beginLayoutLw(mDisplayFrames, getConfiguration().uiMode);
int seq = mLayoutSeq + 1;
if (seq < 0) seq = 0;
@@ -4548,7 +4581,7 @@
* However we need child windows of the applications to be above the IME (Text drag handles).
* This is a non-strictly hierarcical layering and we need to break out of the Z ordering
* somehow. We do this by relatively ordering children of the target to the IME in cooperation
- * with {@link #WindowState#assignLayer}
+ * with {@link WindowState#assignLayer}
*/
void assignRelativeLayerForImeTargetChild(SurfaceControl.Transaction t, WindowContainer child) {
child.assignRelativeLayer(t, mImeWindowsContainers.getSurfaceControl(), 1);
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 9151ddf..c16f95e 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -16,20 +16,143 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
+import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
+import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
+import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManagerGlobal.ADD_OKAY;
import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
+
+import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW;
import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
+import static com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.localLOGV;
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityThread;
+import android.app.StatusBarManager;
+import android.content.Context;
import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.hardware.input.InputManager;
+import android.hardware.power.V1_0.PowerHint;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.util.ArraySet;
+import android.util.PrintWriterPrinter;
import android.util.Slog;
+import android.view.DisplayCutout;
+import android.view.Gravity;
+import android.view.IApplicationToken;
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
+import android.view.Surface;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerGlobal;
+import android.view.WindowManagerPolicyConstants;
+import android.view.accessibility.AccessibilityManager;
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ScreenShapeHelper;
+import com.android.internal.util.ScreenshotHelper;
+import com.android.server.LocalServices;
+import com.android.server.UiThread;
+import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.policy.WindowManagerPolicy.InputConsumer;
+import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
+import com.android.server.policy.WindowOrientationListener;
+import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.utils.InsetUtils;
import java.io.PrintWriter;
@@ -38,12 +161,61 @@
*/
public class DisplayPolicy {
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;
+ private static final boolean DEBUG = false;
+
+ private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
+
+ // The panic gesture may become active only after the keyguard is dismissed and the immersive
+ // app shows again. If that doesn't happen for 30s we drop the gesture.
+ private static final long PANIC_GESTURE_EXPIRATION = 30000;
+
+ // Controls navigation bar opacity depending on which workspace stacks are currently
+ // visible.
+ // Nav bar is always opaque when either the freeform stack or docked stack is visible.
+ private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
+ // Nav bar is always translucent when the freeform stack is visible, otherwise always opaque.
+ private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
+
+ /**
+ * These are the system UI flags that, when changing, can cause the layout
+ * of the screen to change.
+ */
+ private static final int SYSTEM_UI_CHANGING_LAYOUT =
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.STATUS_BAR_TRANSLUCENT
+ | View.NAVIGATION_BAR_TRANSLUCENT
+ | View.STATUS_BAR_TRANSPARENT
+ | View.NAVIGATION_BAR_TRANSPARENT;
private final WindowManagerService mService;
+ private final Context mContext;
+ private final DisplayContent mDisplayContent;
private final Object mLock;
+ private final Handler mHandler;
private final boolean mCarDockEnablesAccelerometer;
private final boolean mDeskDockEnablesAccelerometer;
+ private final boolean mTranslucentDecorEnabled;
+ private final AccessibilityManager mAccessibilityManager;
+ private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
+ private final ScreenshotHelper mScreenshotHelper;
+
+ private final Object mServiceAcquireLock = new Object();
+ private StatusBarManagerInternal mStatusBarManagerInternal;
+
+ private StatusBarManagerInternal getStatusBarManagerInternal() {
+ synchronized (mServiceAcquireLock) {
+ if (mStatusBarManagerInternal == null) {
+ mStatusBarManagerInternal =
+ LocalServices.getService(StatusBarManagerInternal.class);
+ }
+ return mStatusBarManagerInternal;
+ }
+ }
+
+ @VisibleForTesting
+ private final SystemGesturesPointerEventListener mSystemGestures;
private volatile int mLidState = LID_ABSENT;
private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
@@ -64,32 +236,311 @@
private volatile boolean mKeyguardDrawComplete;
private volatile boolean mWindowManagerDrawComplete;
- DisplayPolicy(WindowManagerService service) {
+ private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
+ private WindowState mStatusBar = null;
+ private final int[] mStatusBarHeightForRotation = new int[4];
+ private WindowState mNavigationBar = null;
+ @NavigationBarPosition
+ private int mNavigationBarPosition = NAV_BAR_BOTTOM;
+ private int[] mNavigationBarHeightForRotationDefault = new int[4];
+ private int[] mNavigationBarWidthForRotationDefault = new int[4];
+ private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
+ private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
+
+ private final StatusBarController mStatusBarController = new StatusBarController();
+
+ private final BarController mNavigationBarController = new BarController("NavigationBar",
+ View.NAVIGATION_BAR_TRANSIENT,
+ View.NAVIGATION_BAR_UNHIDE,
+ View.NAVIGATION_BAR_TRANSLUCENT,
+ StatusBarManager.WINDOW_NAVIGATION_BAR,
+ FLAG_TRANSLUCENT_NAVIGATION,
+ View.NAVIGATION_BAR_TRANSPARENT);
+
+ private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
+ new BarController.OnBarVisibilityChangedListener() {
+ @Override
+ public void onBarVisibilityChanged(boolean visible) {
+ if (mAccessibilityManager == null) {
+ return;
+ }
+ mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
+ }
+ };
+
+ // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
+ private NavigationBarExperiments mExperiments = new NavigationBarExperiments();
+ // EXPERIMENT END
+
+ @GuardedBy("mHandler")
+ private SleepToken mDreamingSleepToken;
+
+ @GuardedBy("mHandler")
+ private SleepToken mWindowSleepToken;
+
+ private final Runnable mAcquireSleepTokenRunnable;
+ private final Runnable mReleaseSleepTokenRunnable;
+
+ // The windows we were told about in focusChanged.
+ private WindowState mFocusedWindow;
+ private WindowState mLastFocusedWindow;
+
+ IApplicationToken mFocusedApp;
+
+ int mLastSystemUiFlags;
+ // Bits that we are in the process of clearing, so we want to prevent
+ // them from being set by applications until everything has been updated
+ // to have them clear.
+ private int mResettingSystemUiFlags = 0;
+ // Bits that we are currently always keeping cleared.
+ private int mForceClearedSystemUiFlags = 0;
+ private int mLastFullscreenStackSysUiFlags;
+ private int mLastDockedStackSysUiFlags;
+ private final Rect mNonDockedStackBounds = new Rect();
+ private final Rect mDockedStackBounds = new Rect();
+ private final Rect mLastNonDockedStackBounds = new Rect();
+ private final Rect mLastDockedStackBounds = new Rect();
+
+ // What we last reported to system UI about whether the compatibility
+ // menu needs to be displayed.
+ private boolean mLastFocusNeedsMenu = false;
+ // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
+ private long mPendingPanicGestureUptime;
+
+ private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
+ private static final Rect sTmpRect = new Rect();
+ private static final Rect sTmpDockedFrame = new Rect();
+ private static final Rect sTmpNavFrame = new Rect();
+ private static final Rect sTmpLastParentFrame = new Rect();
+
+ private WindowState mTopFullscreenOpaqueWindowState;
+ private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
+ private WindowState mTopDockedOpaqueWindowState;
+ private WindowState mTopDockedOpaqueOrDimmingWindowState;
+ private boolean mTopIsFullscreen;
+ private boolean mForceStatusBar;
+ private boolean mForceStatusBarFromKeyguard;
+ private boolean mForceStatusBarTransparent;
+ private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
+ private boolean mForcingShowNavBar;
+ private int mForcingShowNavBarLayer;
+ private boolean mForceShowSystemBars;
+
+ private boolean mShowingDream;
+ private boolean mLastShowingDream;
+ private boolean mDreamingLockscreen;
+ private boolean mDreamingSleepTokenNeeded;
+ private boolean mWindowSleepTokenNeeded;
+ private boolean mLastWindowSleepTokenNeeded;
+ private boolean mAllowLockscreenWhenOn;
+
+ private InputConsumer mInputConsumer = null;
+
+ // -------- PolicyHandler --------
+ private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
+ private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
+ private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
+
+ private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
+ private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
+
+ private class PolicyHandler extends Handler {
+
+ PolicyHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
+ updateDreamingSleepToken(msg.arg1 != 0);
+ break;
+ case MSG_REQUEST_TRANSIENT_BARS:
+ WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
+ ? mStatusBar : mNavigationBar;
+ if (targetBar != null) {
+ requestTransientBars(targetBar);
+ }
+ break;
+ case MSG_DISPOSE_INPUT_CONSUMER:
+ disposeInputConsumer((InputConsumer) msg.obj);
+ break;
+ }
+ }
+ }
+
+ DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
mService = service;
+ mContext = displayContent.isDefaultDisplay ? service.mContext
+ : service.mContext.createDisplayContext(displayContent.getDisplay());
+ mDisplayContent = displayContent;
mLock = service.getWindowManagerLock();
- mCarDockEnablesAccelerometer = service.mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_carDockEnablesAccelerometer);
- mDeskDockEnablesAccelerometer = service.mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_deskDockEnablesAccelerometer);
+
+ final Resources r = mContext.getResources();
+ mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
+ mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
+ mTranslucentDecorEnabled = r.getBoolean(R.bool.config_enableTranslucentDecor);
+ updateConfigurationDependentBehaviors();
+
+ mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
+ Context.ACCESSIBILITY_SERVICE);
+ if (!displayContent.isDefaultDisplay) {
+ mAwake = true;
+ mScreenOnEarly = true;
+ mScreenOnFully = true;
+ }
+
+ final Looper looper = UiThread.getHandler().getLooper();
+ mHandler = new PolicyHandler(looper);
+ mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
+ new SystemGesturesPointerEventListener.Callbacks() {
+ @Override
+ public void onSwipeFromTop() {
+ if (mStatusBar != null) {
+ requestTransientBars(mStatusBar);
+ }
+ }
+
+ @Override
+ public void onSwipeFromBottom() {
+ if (mNavigationBar != null
+ && mNavigationBarPosition == NAV_BAR_BOTTOM) {
+ requestTransientBars(mNavigationBar);
+ }
+ }
+
+ @Override
+ public void onSwipeFromRight() {
+ if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_RIGHT) {
+ requestTransientBars(mNavigationBar);
+ }
+ }
+
+ @Override
+ public void onSwipeFromLeft() {
+ if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_LEFT) {
+ requestTransientBars(mNavigationBar);
+ }
+ }
+
+ @Override
+ public void onFling(int duration) {
+ if (mService.mPowerManagerInternal != null) {
+ mService.mPowerManagerInternal.powerHint(
+ PowerHint.INTERACTION, duration);
+ }
+ }
+
+ @Override
+ public void onDebug() {
+ // no-op
+ }
+
+ private WindowOrientationListener getOrientationListener() {
+ final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
+ return rotation != null ? rotation.getOrientationListener() : null;
+ }
+
+ @Override
+ public void onDown() {
+ final WindowOrientationListener listener = getOrientationListener();
+ if (listener != null) {
+ listener.onTouchStart();
+ }
+ }
+
+ @Override
+ public void onUpOrCancel() {
+ final WindowOrientationListener listener = getOrientationListener();
+ if (listener != null) {
+ listener.onTouchEnd();
+ }
+ }
+
+ @Override
+ public void onMouseHoverAtTop() {
+ mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+ Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
+ msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
+ mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
+ }
+
+ @Override
+ public void onMouseHoverAtBottom() {
+ mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+ Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
+ msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
+ mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
+ }
+
+ @Override
+ public void onMouseLeaveFromEdge() {
+ mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
+ }
+ });
+ displayContent.registerPointerEventListener(mSystemGestures);
+ displayContent.mAppTransition.registerListenerLocked(
+ mStatusBarController.getAppTransitionListener());
+ mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
+ mService.mVrModeEnabled);
+ mAcquireSleepTokenRunnable = () -> {
+ if (mWindowSleepToken != null) {
+ return;
+ }
+ final int displayId = displayContent.getDisplayId();
+ mWindowSleepToken = service.mAtmInternal.acquireSleepToken(
+ "WindowSleepTokenOnDisplay" + displayId, displayId);
+ };
+ mReleaseSleepTokenRunnable = () -> {
+ if (mWindowSleepToken == null) {
+ return;
+ }
+ mWindowSleepToken.release();
+ mWindowSleepToken = null;
+ };
+
+ // TODO: Make it can take screenshot on external display
+ mScreenshotHelper = displayContent.isDefaultDisplay
+ ? new ScreenshotHelper(mContext) : null;
+ }
+
+ void systemReady() {
+ mSystemGestures.systemReady();
+ }
+
+ private int getDisplayId() {
+ return mDisplayContent.getDisplayId();
+ }
+
+ void onDisplayRemoved() {
+ mDisplayContent.unregisterPointerEventListener(mSystemGestures);
}
void configure(int width, int height, int shortSizeDp) {
// Allow the navigation bar to move on non-square small devices (phones).
mNavigationBarCanMove = width != height && shortSizeDp < 600;
- mHasNavigationBar = mService.mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_showNavigationBar);
+ if (mDisplayContent.isDefaultDisplay) {
+ mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
- // Allow a system property to override this. Used by the emulator.
- // See also hasNavigationBar().
- String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
- if ("1".equals(navBarOverride)) {
- mHasNavigationBar = false;
- } else if ("0".equals(navBarOverride)) {
- mHasNavigationBar = true;
+ // Allow a system property to override this. Used by the emulator.
+ // See also hasNavigationBar().
+ String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
+ if ("1".equals(navBarOverride)) {
+ mHasNavigationBar = false;
+ } else if ("0".equals(navBarOverride)) {
+ mHasNavigationBar = true;
+ }
+ } else {
+ mHasNavigationBar = mDisplayContent.getDisplay().supportsSystemDecorations();
}
}
+ void updateConfigurationDependentBehaviors() {
+ mNavBarOpacityMode = mContext.getResources().getInteger(R.integer.config_navBarOpacityMode);
+ }
+
public void setHdmiPlugged(boolean plugged) {
setHdmiPlugged(plugged, false /* force */);
}
@@ -101,7 +552,7 @@
final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
- mService.mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
}
@@ -244,17 +695,2642 @@
return true;
}
+ /**
+ * Sanitize the layout parameters coming from a client. Allows the policy
+ * to do things like ensure that windows of a specific type can't take
+ * input focus.
+ *
+ * @param attrs The window layout parameters to be modified. These values
+ * are modified in-place.
+ */
+ public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
+ boolean hasStatusBarServicePermission) {
+
+ final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
+ if (mScreenDecorWindows.contains(win)) {
+ if (!isScreenDecor) {
+ // No longer has the flag set, so remove from the set.
+ mScreenDecorWindows.remove(win);
+ }
+ } else if (isScreenDecor && hasStatusBarServicePermission) {
+ mScreenDecorWindows.add(win);
+ }
+
+ switch (attrs.type) {
+ case TYPE_SYSTEM_OVERLAY:
+ case TYPE_SECURE_SYSTEM_OVERLAY:
+ // These types of windows can't receive input events.
+ attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+ attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+ break;
+ case TYPE_DREAM:
+ case TYPE_WALLPAPER:
+ // Dreams and wallpapers don't have an app window token and can thus not be
+ // letterboxed. Hence always let them extend under the cutout.
+ attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ break;
+ case TYPE_STATUS_BAR:
+
+ // If the Keyguard is in a hidden state (occluded by another window), we force to
+ // remove the wallpaper and keyguard flag so that any change in-flight after setting
+ // the keyguard as occluded wouldn't set these flags again.
+ // See {@link #processKeyguardSetHiddenResultLw}.
+ if (mService.mPolicy.isKeyguardOccluded()) {
+ attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+ attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+ }
+ break;
+
+ case TYPE_SCREENSHOT:
+ attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ break;
+
+ case TYPE_TOAST:
+ // While apps should use the dedicated toast APIs to add such windows
+ // it possible legacy apps to add the window directly. Therefore, we
+ // make windows added directly by the app behave as a toast as much
+ // as possible in terms of timeout and animation.
+ if (attrs.hideTimeoutMilliseconds < 0
+ || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
+ attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
+ }
+ attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
+ break;
+ }
+
+ if (attrs.type != TYPE_STATUS_BAR) {
+ // The status bar is the only window allowed to exhibit keyguard behavior.
+ attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+ }
+ }
+
+ /**
+ * Preflight adding a window to the system.
+ *
+ * Currently enforces that three window types are singletons per display:
+ * <ul>
+ * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
+ * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
+ * </ul>
+ *
+ * @param win The window to be added
+ * @param attrs Information about the window to be added
+ *
+ * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
+ * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
+ */
+ public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
+
+ if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.STATUS_BAR_SERVICE,
+ "DisplayPolicy");
+ mScreenDecorWindows.add(win);
+ }
+
+ switch (attrs.type) {
+ case TYPE_STATUS_BAR:
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.STATUS_BAR_SERVICE,
+ "DisplayPolicy");
+ if (mStatusBar != null) {
+ if (mStatusBar.isAlive()) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+ }
+ }
+ mStatusBar = win;
+ mStatusBarController.setWindow(win);
+ if (mDisplayContent.isDefaultDisplay) {
+ mService.mPolicy.setKeyguardCandidateLw(win);
+ }
+ break;
+ case TYPE_NAVIGATION_BAR:
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.STATUS_BAR_SERVICE,
+ "DisplayPolicy");
+ if (mNavigationBar != null) {
+ if (mNavigationBar.isAlive()) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+ }
+ }
+ mNavigationBar = win;
+ mNavigationBarController.setWindow(win);
+ mNavigationBarController.setOnBarVisibilityChangedListener(
+ mNavBarVisibilityListener, true);
+ if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
+ break;
+ case TYPE_NAVIGATION_BAR_PANEL:
+ case TYPE_STATUS_BAR_PANEL:
+ case TYPE_STATUS_BAR_SUB_PANEL:
+ case TYPE_VOICE_INTERACTION_STARTING:
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.STATUS_BAR_SERVICE,
+ "DisplayPolicy");
+ break;
+ }
+ return ADD_OKAY;
+ }
+
+ /**
+ * Called when a window is being removed from a window manager. Must not
+ * throw an exception -- clean up as much as possible.
+ *
+ * @param win The window being removed.
+ */
+ public void removeWindowLw(WindowState win) {
+ if (mStatusBar == win) {
+ mStatusBar = null;
+ mStatusBarController.setWindow(null);
+ if (mDisplayContent.isDefaultDisplay) {
+ mService.mPolicy.setKeyguardCandidateLw(null);
+ }
+ } else if (mNavigationBar == win) {
+ mNavigationBar = null;
+ mNavigationBarController.setWindow(null);
+ }
+ if (mLastFocusedWindow == win) {
+ mLastFocusedWindow = null;
+ }
+ mScreenDecorWindows.remove(win);
+ }
+
+ /**
+ * Control the animation to run when a window's state changes. Return a
+ * non-0 number to force the animation to a specific resource ID, or 0
+ * to use the default animation.
+ *
+ * @param win The window that is changing.
+ * @param transit What is happening to the window:
+ * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
+ * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
+ * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
+ * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
+ *
+ * @return Resource ID of the actual animation to use, or 0 for none.
+ */
+ public int selectAnimationLw(WindowState win, int transit) {
+ if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
+ + ": transit=" + transit);
+ if (win == mStatusBar) {
+ final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+ final boolean expanded = win.getAttrs().height == MATCH_PARENT
+ && win.getAttrs().width == MATCH_PARENT;
+ if (isKeyguard || expanded) {
+ return -1;
+ }
+ if (transit == TRANSIT_EXIT
+ || transit == TRANSIT_HIDE) {
+ return R.anim.dock_top_exit;
+ } else if (transit == TRANSIT_ENTER
+ || transit == TRANSIT_SHOW) {
+ return R.anim.dock_top_enter;
+ }
+ } else if (win == mNavigationBar) {
+ if (win.getAttrs().windowAnimations != 0) {
+ return 0;
+ }
+ // This can be on either the bottom or the right or the left.
+ if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
+ if (transit == TRANSIT_EXIT
+ || transit == TRANSIT_HIDE) {
+ if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
+ return R.anim.dock_bottom_exit_keyguard;
+ } else {
+ return R.anim.dock_bottom_exit;
+ }
+ } else if (transit == TRANSIT_ENTER
+ || transit == TRANSIT_SHOW) {
+ return R.anim.dock_bottom_enter;
+ }
+ } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
+ if (transit == TRANSIT_EXIT
+ || transit == TRANSIT_HIDE) {
+ return R.anim.dock_right_exit;
+ } else if (transit == TRANSIT_ENTER
+ || transit == TRANSIT_SHOW) {
+ return R.anim.dock_right_enter;
+ }
+ } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
+ if (transit == TRANSIT_EXIT
+ || transit == TRANSIT_HIDE) {
+ return R.anim.dock_left_exit;
+ } else if (transit == TRANSIT_ENTER
+ || transit == TRANSIT_SHOW) {
+ return R.anim.dock_left_enter;
+ }
+ }
+ } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
+ return selectDockedDividerAnimationLw(win, transit);
+ }
+
+ if (transit == TRANSIT_PREVIEW_DONE) {
+ if (win.hasAppShownWindows()) {
+ if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
+ return R.anim.app_starting_exit;
+ }
+ } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
+ && transit == TRANSIT_ENTER) {
+ // Special case: we are animating in a dream, while the keyguard
+ // is shown. We don't want an animation on the dream, because
+ // we need it shown immediately with the keyguard animating away
+ // to reveal it.
+ return -1;
+ }
+
+ return 0;
+ }
+
+ private int selectDockedDividerAnimationLw(WindowState win, int transit) {
+ int insets = mDisplayContent.getDockedDividerController().getContentInsets();
+
+ // If the divider is behind the navigation bar, don't animate.
+ final Rect frame = win.getFrameLw();
+ final boolean behindNavBar = mNavigationBar != null
+ && ((mNavigationBarPosition == NAV_BAR_BOTTOM
+ && frame.top + insets >= mNavigationBar.getFrameLw().top)
+ || (mNavigationBarPosition == NAV_BAR_RIGHT
+ && frame.left + insets >= mNavigationBar.getFrameLw().left)
+ || (mNavigationBarPosition == NAV_BAR_LEFT
+ && frame.right - insets <= mNavigationBar.getFrameLw().right));
+ final boolean landscape = frame.height() > frame.width();
+ final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
+ || frame.left + insets >= win.getDisplayFrameLw().right);
+ final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
+ || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
+ final boolean offscreen = offscreenLandscape || offscreenPortrait;
+ if (behindNavBar || offscreen) {
+ return 0;
+ }
+ if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
+ return R.anim.fade_in;
+ } else if (transit == TRANSIT_EXIT) {
+ return R.anim.fade_out;
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Determine the animation to run for a rotation transition based on the
+ * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
+ * and whether it is currently fullscreen and frontmost.
+ *
+ * @param anim The exiting animation resource id is stored in anim[0], the
+ * entering animation resource id is stored in anim[1].
+ */
+ public void selectRotationAnimationLw(int anim[]) {
+ // If the screen is off or non-interactive, force a jumpcut.
+ final boolean forceJumpcut = !mScreenOnFully || !mService.mPolicy.okToAnimate();
+ if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
+ + mTopFullscreenOpaqueWindowState + " rotationAnimation="
+ + (mTopFullscreenOpaqueWindowState == null
+ ? "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation)
+ + " forceJumpcut=" + forceJumpcut);
+ if (forceJumpcut) {
+ anim[0] = R.anim.rotation_animation_jump_exit;
+ anim[1] = R.anim.rotation_animation_enter;
+ return;
+ }
+ if (mTopFullscreenOpaqueWindowState != null) {
+ int animationHint = mTopFullscreenOpaqueWindowState.getRotationAnimationHint();
+ if (animationHint < 0 && mTopIsFullscreen) {
+ animationHint = mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation;
+ }
+ switch (animationHint) {
+ case ROTATION_ANIMATION_CROSSFADE:
+ case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless.
+ anim[0] = R.anim.rotation_animation_xfade_exit;
+ anim[1] = R.anim.rotation_animation_enter;
+ break;
+ case ROTATION_ANIMATION_JUMPCUT:
+ anim[0] = R.anim.rotation_animation_jump_exit;
+ anim[1] = R.anim.rotation_animation_enter;
+ break;
+ case ROTATION_ANIMATION_ROTATE:
+ default:
+ anim[0] = anim[1] = 0;
+ break;
+ }
+ } else {
+ anim[0] = anim[1] = 0;
+ }
+ }
+
+ /**
+ * Validate whether the current top fullscreen has specified the same
+ * {@link WindowManager.LayoutParams#rotationAnimation} value as that
+ * being passed in from the previous top fullscreen window.
+ *
+ * @param exitAnimId exiting resource id from the previous window.
+ * @param enterAnimId entering resource id from the previous window.
+ * @param forceDefault For rotation animations only, if true ignore the
+ * animation values and just return false.
+ * @return true if the previous values are still valid, false if they
+ * should be replaced with the default.
+ */
+ public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
+ boolean forceDefault) {
+ switch (exitAnimId) {
+ case R.anim.rotation_animation_xfade_exit:
+ case R.anim.rotation_animation_jump_exit:
+ // These are the only cases that matter.
+ if (forceDefault) {
+ return false;
+ }
+ int anim[] = new int[2];
+ selectRotationAnimationLw(anim);
+ return (exitAnimId == anim[0] && enterAnimId == anim[1]);
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Called when a new system UI visibility is being reported, allowing
+ * the policy to adjust what is actually reported.
+ * @param visibility The raw visibility reported by the status bar.
+ * @return The new desired visibility.
+ */
+ public int adjustSystemUiVisibilityLw(int visibility) {
+ mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
+ mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
+
+ // Reset any bits in mForceClearingStatusBarVisibility that
+ // are now clear.
+ mResettingSystemUiFlags &= visibility;
+ // Clear any bits in the new visibility that are currently being
+ // force cleared, before reporting it.
+ return visibility & ~mResettingSystemUiFlags
+ & ~mForceClearedSystemUiFlags;
+ }
+
+ /**
+ * @return true if the navigation bar is forced to stay visible
+ */
+ public boolean isNavBarForcedShownLw(WindowState windowState) {
+ return mForceShowSystemBars;
+ }
+
+ // TODO: Should probably be moved into DisplayFrames.
+ /**
+ * Return the layout hints for a newly added window. These values are computed on the
+ * most recent layout, so they are not guaranteed to be correct.
+ *
+ * @param attrs The LayoutParams of the window.
+ * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
+ * associated with the window.
+ * @param displayFrames display frames.
+ * @param floatingStack Whether the window's stack is floating.
+ * @param outFrame The frame of the window.
+ * @param outContentInsets The areas covered by system windows, expressed as positive insets.
+ * @param outStableInsets The areas covered by stable system windows irrespective of their
+ * current visibility. Expressed as positive insets.
+ * @param outOutsets The areas that are not real display, but we would like to treat as such.
+ * @param outDisplayCutout The area that has been cut away from the display.
+ * @return Whether to always consume the navigation bar.
+ * See {@link #isNavBarForcedShownLw(WindowState)}.
+ */
+ public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
+ DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
+ Rect outContentInsets, Rect outStableInsets,
+ Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
+ final int fl = PolicyControl.getWindowFlags(null, attrs);
+ final int pfl = attrs.privateFlags;
+ final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
+ final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
+ final int displayRotation = displayFrames.mRotation;
+
+ final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
+ if (useOutsets) {
+ int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
+ if (outset > 0) {
+ if (displayRotation == Surface.ROTATION_0) {
+ outOutsets.bottom += outset;
+ } else if (displayRotation == Surface.ROTATION_90) {
+ outOutsets.right += outset;
+ } else if (displayRotation == Surface.ROTATION_180) {
+ outOutsets.top += outset;
+ } else if (displayRotation == Surface.ROTATION_270) {
+ outOutsets.left += outset;
+ }
+ }
+ }
+
+ final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
+ final boolean layoutInScreenAndInsetDecor = layoutInScreen
+ && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
+ final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
+
+ if (layoutInScreenAndInsetDecor && !screenDecor) {
+ if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
+ outFrame.set(displayFrames.mUnrestricted);
+ } else {
+ outFrame.set(displayFrames.mRestricted);
+ }
+
+ final Rect sf;
+ if (floatingStack) {
+ sf = null;
+ } else {
+ sf = displayFrames.mStable;
+ }
+
+ final Rect cf;
+ if (floatingStack) {
+ cf = null;
+ } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
+ if ((fl & FLAG_FULLSCREEN) != 0) {
+ cf = displayFrames.mStableFullscreen;
+ } else {
+ cf = displayFrames.mStable;
+ }
+ } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
+ cf = displayFrames.mOverscan;
+ } else {
+ cf = displayFrames.mCurrent;
+ }
+
+ if (taskBounds != null) {
+ outFrame.intersect(taskBounds);
+ }
+ InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
+ InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
+ outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
+ .getDisplayCutout());
+ return mForceShowSystemBars;
+ } else {
+ if (layoutInScreen) {
+ outFrame.set(displayFrames.mUnrestricted);
+ } else {
+ outFrame.set(displayFrames.mStable);
+ }
+ if (taskBounds != null) {
+ outFrame.intersect(taskBounds);
+ }
+
+ outContentInsets.setEmpty();
+ outStableInsets.setEmpty();
+ outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
+ return mForceShowSystemBars;
+ }
+ }
+
+ private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
+ int impliedFlags = 0;
+ if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
+ impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+ }
+ final boolean forceWindowDrawsStatusBarBackground =
+ (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
+ if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
+ || forceWindowDrawsStatusBarBackground
+ && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT) {
+ impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ }
+ return impliedFlags;
+ }
+
+ private static boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
+ return attrs.type == TYPE_WALLPAPER || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0;
+ }
+
+ private final Runnable mClearHideNavigationFlag = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ mDisplayContent.reevaluateStatusBarVisibility();
+ }
+ }
+ };
+
+ /**
+ * Input handler used while nav bar is hidden. Captures any touch on the screen,
+ * to determine when the nav bar should be shown and prevent applications from
+ * receiving those touches.
+ */
+ private final class HideNavInputEventReceiver extends InputEventReceiver {
+ HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
+ super(inputChannel, looper);
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ try {
+ if (event instanceof MotionEvent
+ && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
+ final MotionEvent motionEvent = (MotionEvent) event;
+ if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
+ // When the user taps down, we re-show the nav bar.
+ boolean changed = false;
+ synchronized (mLock) {
+ if (mInputConsumer == null) {
+ return;
+ }
+ // Any user activity always causes us to show the
+ // navigation controls, if they had been hidden.
+ // We also clear the low profile and only content
+ // flags so that tapping on the screen will atomically
+ // restore all currently hidden screen decorations.
+ int newVal = mResettingSystemUiFlags
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LOW_PROFILE
+ | View.SYSTEM_UI_FLAG_FULLSCREEN;
+ if (mResettingSystemUiFlags != newVal) {
+ mResettingSystemUiFlags = newVal;
+ changed = true;
+ }
+ // We don't allow the system's nav bar to be hidden
+ // again for 1 second, to prevent applications from
+ // spamming us and keeping it from being shown.
+ newVal = mForceClearedSystemUiFlags
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ if (mForceClearedSystemUiFlags != newVal) {
+ mForceClearedSystemUiFlags = newVal;
+ changed = true;
+ mHandler.postDelayed(mClearHideNavigationFlag, 1000);
+ }
+ if (changed) {
+ mDisplayContent.reevaluateStatusBarVisibility();
+ }
+ }
+ }
+ }
+ } finally {
+ finishInputEvent(event, false /* handled */);
+ }
+ }
+ }
+
+ /**
+ * Called when layout of the windows is about to start.
+ *
+ * @param displayFrames frames of the display we are doing layout on.
+ * @param uiMode The current uiMode in configuration.
+ */
+ public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
+ displayFrames.onBeginLayout();
+ mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
+ mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
+
+ // For purposes of putting out fake window up to steal focus, we will
+ // drive nav being hidden only by whether it is requested.
+ final int sysui = mLastSystemUiFlags;
+ boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+ boolean navTranslucent = (sysui
+ & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
+ boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
+ boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
+ boolean navAllowedHidden = immersive || immersiveSticky;
+ navTranslucent &= !immersiveSticky; // transient trumps translucent
+ boolean isKeyguardShowing = isStatusBarKeyguard()
+ && !mService.mPolicy.isKeyguardOccluded();
+ if (!isKeyguardShowing) {
+ navTranslucent &= areTranslucentBarsAllowed();
+ }
+ boolean statusBarForcesShowingNavigation = !isKeyguardShowing && mStatusBar != null
+ && (mStatusBar.getAttrs().privateFlags
+ & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
+
+ // When the navigation bar isn't visible, we put up a fake input window to catch all
+ // touch events. This way we can detect when the user presses anywhere to bring back the
+ // nav bar and ensure the application doesn't see the event.
+ if (navVisible || navAllowedHidden) {
+ if (mInputConsumer != null) {
+ mHandler.sendMessage(
+ mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
+ mInputConsumer = null;
+ }
+ } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
+ mInputConsumer = mService.createInputConsumer(mHandler.getLooper(),
+ INPUT_CONSUMER_NAVIGATION,
+ HideNavInputEventReceiver::new,
+ displayFrames.mDisplayId);
+ // As long as mInputConsumer is active, hover events are not dispatched to the app
+ // and the pointer icon is likely to become stale. Hide it to avoid confusion.
+ InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
+ }
+
+ // For purposes of positioning and showing the nav bar, if we have decided that it can't
+ // be hidden (because of the screen aspect ratio), then take that into account.
+ navVisible |= !canHideNavigationBar();
+
+ boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
+ navTranslucent, navAllowedHidden, statusBarForcesShowingNavigation);
+ if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
+ updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
+ if (updateSysUiVisibility) {
+ updateSystemUiVisibilityLw();
+ }
+ layoutScreenDecorWindows(displayFrames);
+
+ if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
+ // Make sure that the zone we're avoiding for the cutout is at least as tall as the
+ // status bar; otherwise fullscreen apps will end up cutting halfway into the status
+ // bar.
+ displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
+ displayFrames.mStable.top);
+ }
+ }
+
+ private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
+ if (mScreenDecorWindows.isEmpty()) {
+ return;
+ }
+
+ sTmpRect.setEmpty();
+ sTmpDockedFrame.set(displayFrames.mDock);
+
+ final int displayId = displayFrames.mDisplayId;
+ final Rect dockFrame = displayFrames.mDock;
+ final int displayHeight = displayFrames.mDisplayHeight;
+ final int displayWidth = displayFrames.mDisplayWidth;
+
+ for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
+ final WindowState w = mScreenDecorWindows.valueAt(i);
+ if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
+ // Skip if not on the same display or not visible.
+ continue;
+ }
+
+ w.getWindowFrames().setFrames(sTmpDockedFrame /* parentFrame */,
+ sTmpDockedFrame /* displayFrame */, sTmpDockedFrame /* overscanFrame */,
+ sTmpDockedFrame /* contentFrame */, sTmpDockedFrame /* visibleFrame */,
+ sTmpRect /* decorFrame */, sTmpDockedFrame /* stableFrame */,
+ sTmpDockedFrame /* outsetFrame */);
+ w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
+ w.computeFrameLw();
+ final Rect frame = w.getFrameLw();
+
+ if (frame.left <= 0 && frame.top <= 0) {
+ // Docked at left or top.
+ if (frame.bottom >= displayHeight) {
+ // Docked left.
+ dockFrame.left = Math.max(frame.right, dockFrame.left);
+ } else if (frame.right >= displayWidth) {
+ // Docked top.
+ dockFrame.top = Math.max(frame.bottom, dockFrame.top);
+ } else {
+ Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
+ + " not docked on left or top of display. frame=" + frame
+ + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
+ }
+ } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
+ // Docked at right or bottom.
+ if (frame.top <= 0) {
+ // Docked right.
+ dockFrame.right = Math.min(frame.left, dockFrame.right);
+ } else if (frame.left <= 0) {
+ // Docked bottom.
+ dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
+ } else {
+ Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
+ + " not docked on right or bottom" + " of display. frame=" + frame
+ + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
+ }
+ } else {
+ // Screen decor windows are required to be docked on one of the sides of the screen.
+ Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
+ + " not docked on one of the sides of the display. frame=" + frame
+ + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
+ }
+ }
+
+ displayFrames.mRestricted.set(dockFrame);
+ displayFrames.mCurrent.set(dockFrame);
+ displayFrames.mVoiceContent.set(dockFrame);
+ displayFrames.mSystem.set(dockFrame);
+ displayFrames.mContent.set(dockFrame);
+ displayFrames.mRestrictedOverscan.set(dockFrame);
+ }
+
+ private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
+ boolean isKeyguardShowing) {
+ // decide where the status bar goes ahead of time
+ if (mStatusBar == null) {
+ return false;
+ }
+ // apply any navigation bar insets
+ sTmpRect.setEmpty();
+ mStatusBar.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
+ displayFrames.mUnrestricted /* displayFrame */,
+ displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
+ displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
+ displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
+ mStatusBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
+
+ // Let the status bar determine its size.
+ mStatusBar.computeFrameLw();
+
+ // For layout, the status bar is always at the top with our fixed height.
+ displayFrames.mStable.top = displayFrames.mUnrestricted.top
+ + mStatusBarHeightForRotation[displayFrames.mRotation];
+ // Make sure the status bar covers the entire cutout height
+ displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
+ displayFrames.mDisplayCutoutSafe.top);
+
+ // Tell the bar controller where the collapsed status bar content is
+ sTmpRect.set(mStatusBar.getContentFrameLw());
+ sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
+ sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
+ sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
+ mStatusBarController.setContentFrame(sTmpRect);
+
+ boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
+ boolean statusBarTranslucent = (sysui
+ & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
+ if (!isKeyguardShowing) {
+ statusBarTranslucent &= areTranslucentBarsAllowed();
+ }
+
+ // If the status bar is hidden, we don't want to cause windows behind it to scroll.
+ if (mStatusBar.isVisibleLw() && !statusBarTransient) {
+ // Status bar may go away, so the screen area it occupies is available to apps but just
+ // covering them when the status bar is visible.
+ final Rect dockFrame = displayFrames.mDock;
+ dockFrame.top = displayFrames.mStable.top;
+ displayFrames.mContent.set(dockFrame);
+ displayFrames.mVoiceContent.set(dockFrame);
+ displayFrames.mCurrent.set(dockFrame);
+
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
+ "dock=%s content=%s cur=%s", dockFrame.toString(),
+ displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
+
+ if (!mStatusBar.isAnimatingLw() && !statusBarTranslucent
+ && !mStatusBarController.wasRecentlyTranslucent()) {
+ // If the opaque status bar is currently requested to be visible, and not in the
+ // process of animating on or off, then we can tell the app that it is covered by
+ // it.
+ displayFrames.mSystem.top = displayFrames.mStable.top;
+ }
+ }
+ return mStatusBarController.checkHiddenLw();
+ }
+
+ private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
+ boolean navTranslucent, boolean navAllowedHidden,
+ boolean statusBarForcesShowingNavigation) {
+ if (mNavigationBar == null) {
+ return false;
+ }
+
+ final Rect navigationFrame = sTmpNavFrame;
+ boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
+ // Force the navigation bar to its appropriate place and size. We need to do this directly,
+ // instead of relying on it to bubble up from the nav bar, because this needs to change
+ // atomically with screen rotations.
+ final int rotation = displayFrames.mRotation;
+ final int displayHeight = displayFrames.mDisplayHeight;
+ final int displayWidth = displayFrames.mDisplayWidth;
+ final Rect dockFrame = displayFrames.mDock;
+ mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
+
+ final Rect cutoutSafeUnrestricted = sTmpRect;
+ cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
+ cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
+
+ if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
+ // It's a system nav bar or a portrait screen; nav bar goes on bottom.
+ final int top = cutoutSafeUnrestricted.bottom
+ - getNavigationBarHeight(rotation, uiMode);
+ // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
+ final int topNavBar = cutoutSafeUnrestricted.bottom
+ - mExperiments.getNavigationBarFrameHeight();
+ navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
+ // EXPERIMENT END
+ displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
+ if (transientNavBarShowing) {
+ mNavigationBarController.setBarShowingLw(true);
+ } else if (navVisible) {
+ mNavigationBarController.setBarShowingLw(true);
+ dockFrame.bottom = displayFrames.mRestricted.bottom =
+ displayFrames.mRestrictedOverscan.bottom = top;
+ } else {
+ // We currently want to hide the navigation UI - unless we expanded the status bar.
+ mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
+ }
+ if (navVisible && !navTranslucent && !navAllowedHidden
+ && !mNavigationBar.isAnimatingLw()
+ && !mNavigationBarController.wasRecentlyTranslucent()) {
+ // If the opaque nav bar is currently requested to be visible and not in the process
+ // of animating on or off, then we can tell the app that it is covered by it.
+ displayFrames.mSystem.bottom = top;
+ }
+ } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
+ // Landscape screen; nav bar goes to the right.
+ final int left = cutoutSafeUnrestricted.right
+ - getNavigationBarWidth(rotation, uiMode);
+ // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
+ final int leftNavBar = cutoutSafeUnrestricted.right
+ - mExperiments.getNavigationBarFrameWidth();
+ navigationFrame.set(leftNavBar, 0, displayFrames.mUnrestricted.right, displayHeight);
+ // EXPERIMENT END
+ displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
+ if (transientNavBarShowing) {
+ mNavigationBarController.setBarShowingLw(true);
+ } else if (navVisible) {
+ mNavigationBarController.setBarShowingLw(true);
+ dockFrame.right = displayFrames.mRestricted.right =
+ displayFrames.mRestrictedOverscan.right = left;
+ } else {
+ // We currently want to hide the navigation UI - unless we expanded the status bar.
+ mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
+ }
+ if (navVisible && !navTranslucent && !navAllowedHidden
+ && !mNavigationBar.isAnimatingLw()
+ && !mNavigationBarController.wasRecentlyTranslucent()) {
+ // If the nav bar is currently requested to be visible, and not in the process of
+ // animating on or off, then we can tell the app that it is covered by it.
+ displayFrames.mSystem.right = left;
+ }
+ } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
+ // Seascape screen; nav bar goes to the left.
+ final int right = cutoutSafeUnrestricted.left
+ + getNavigationBarWidth(rotation, uiMode);
+ // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
+ final int rightNavBar = cutoutSafeUnrestricted.left
+ + mExperiments.getNavigationBarFrameWidth();
+ navigationFrame.set(displayFrames.mUnrestricted.left, 0, rightNavBar, displayHeight);
+ // EXPERIMENT END
+ displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
+ if (transientNavBarShowing) {
+ mNavigationBarController.setBarShowingLw(true);
+ } else if (navVisible) {
+ mNavigationBarController.setBarShowingLw(true);
+ dockFrame.left = displayFrames.mRestricted.left =
+ displayFrames.mRestrictedOverscan.left = right;
+ } else {
+ // We currently want to hide the navigation UI - unless we expanded the status bar.
+ mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
+ }
+ if (navVisible && !navTranslucent && !navAllowedHidden
+ && !mNavigationBar.isAnimatingLw()
+ && !mNavigationBarController.wasRecentlyTranslucent()) {
+ // If the nav bar is currently requested to be visible, and not in the process of
+ // animating on or off, then we can tell the app that it is covered by it.
+ displayFrames.mSystem.left = right;
+ }
+ }
+
+ // Make sure the content and current rectangles are updated to account for the restrictions
+ // from the navigation bar.
+ displayFrames.mCurrent.set(dockFrame);
+ displayFrames.mVoiceContent.set(dockFrame);
+ displayFrames.mContent.set(dockFrame);
+ // And compute the final frame.
+ sTmpRect.setEmpty();
+ mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
+ navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
+ displayFrames.mDisplayCutoutSafe /* contentFrame */,
+ navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
+ navigationFrame /* stableFrame */,
+ displayFrames.mDisplayCutoutSafe /* outsetFrame */);
+ mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
+ mNavigationBar.computeFrameLw();
+ mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
+
+ if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
+ return mNavigationBarController.checkHiddenLw();
+ }
+
+ private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
+ boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
+ DisplayFrames displayFrames) {
+ if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
+ // Here's a special case: if the child window is not the 'dock window'
+ // or input method target, and the window it is attached to is below
+ // the dock window, then the frames we computed for the window it is
+ // attached to can not be used because the dock is effectively part
+ // of the underlying window and the attached window is floating on top
+ // of the whole thing. So, we ignore the attached window and explicitly
+ // compute the frames that would be appropriate without the dock.
+ vf.set(displayFrames.mDock);
+ cf.set(displayFrames.mDock);
+ of.set(displayFrames.mDock);
+ df.set(displayFrames.mDock);
+ } else {
+ // The effective display frame of the attached window depends on whether it is taking
+ // care of insetting its content. If not, we need to use the parent's content frame so
+ // that the entire window is positioned within that content. Otherwise we can use the
+ // overscan frame and let the attached window take care of positioning its content
+ // appropriately.
+ if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+ // Set the content frame of the attached window to the parent's decor frame
+ // (same as content frame when IME isn't present) if specifically requested by
+ // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
+ // Otherwise, use the overscan frame.
+ cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
+ ? attached.getContentFrameLw() : attached.getOverscanFrameLw());
+ } else {
+ // If the window is resizing, then we want to base the content frame on our attached
+ // content frame to resize...however, things can be tricky if the attached window is
+ // NOT in resize mode, in which case its content frame will be larger.
+ // Ungh. So to deal with that, make sure the content frame we end up using is not
+ // covering the IM dock.
+ cf.set(attached.getContentFrameLw());
+ if (attached.isVoiceInteraction()) {
+ cf.intersectUnchecked(displayFrames.mVoiceContent);
+ } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
+ cf.intersectUnchecked(displayFrames.mContent);
+ }
+ }
+ df.set(insetDecors ? attached.getDisplayFrameLw() : cf);
+ of.set(insetDecors ? attached.getOverscanFrameLw() : cf);
+ vf.set(attached.getVisibleFrameLw());
+ }
+ // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
+ // positioned relative to its parent or the entire screen.
+ pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
+ }
+
+ private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
+ if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
+ return;
+ }
+ // If app is requesting a stable layout, don't let the content insets go below the stable
+ // values.
+ if ((fl & FLAG_FULLSCREEN) != 0) {
+ r.intersectUnchecked(displayFrames.mStableFullscreen);
+ } else {
+ r.intersectUnchecked(displayFrames.mStable);
+ }
+ }
+
+ private boolean canReceiveInput(WindowState win) {
+ boolean notFocusable =
+ (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
+ boolean altFocusableIm =
+ (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
+ boolean notFocusableForIm = notFocusable ^ altFocusableIm;
+ return !notFocusableForIm;
+ }
+
+ /**
+ * Called for each window attached to the window manager as layout is proceeding. The
+ * implementation of this function must take care of setting the window's frame, either here or
+ * in finishLayout().
+ *
+ * @param win The window being positioned.
+ * @param attached For sub-windows, the window it is attached to; this
+ * window will already have had layoutWindow() called on it
+ * so you can use its Rect. Otherwise null.
+ * @param displayFrames The display frames.
+ */
+ public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
+ // We've already done the navigation bar, status bar, and all screen decor windows. If the
+ // status bar can receive input, we need to layout it again to accommodate for the IME
+ // window.
+ if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
+ || mScreenDecorWindows.contains(win)) {
+ return;
+ }
+ final WindowManager.LayoutParams attrs = win.getAttrs();
+ final boolean isDefaultDisplay = win.isDefaultDisplay();
+
+ final int type = attrs.type;
+ final int fl = PolicyControl.getWindowFlags(win, attrs);
+ final int pfl = attrs.privateFlags;
+ final int sim = attrs.softInputMode;
+ final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
+ final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
+
+ final WindowFrames windowFrames = win.getWindowFrames();
+
+ windowFrames.setHasOutsets(false);
+ sTmpLastParentFrame.set(windowFrames.mParentFrame);
+ final Rect pf = windowFrames.mParentFrame;
+ final Rect df = windowFrames.mDisplayFrame;
+ final Rect of = windowFrames.mOverscanFrame;
+ final Rect cf = windowFrames.mContentFrame;
+ final Rect vf = windowFrames.mVisibleFrame;
+ final Rect dcf = windowFrames.mDecorFrame;
+ final Rect sf = windowFrames.mStableFrame;
+ dcf.setEmpty();
+ windowFrames.setParentFrameWasClippedByDisplayCutout(false);
+ windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
+
+ final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
+ && mNavigationBar.isVisibleLw();
+
+ final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
+
+ final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
+ || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
+
+ final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
+ final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
+
+ sf.set(displayFrames.mStable);
+
+ if (type == TYPE_INPUT_METHOD) {
+ vf.set(displayFrames.mDock);
+ cf.set(displayFrames.mDock);
+ of.set(displayFrames.mDock);
+ df.set(displayFrames.mDock);
+ windowFrames.mParentFrame.set(displayFrames.mDock);
+ // IM dock windows layout below the nav bar...
+ pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
+ // ...with content insets above the nav bar
+ cf.bottom = vf.bottom = displayFrames.mStable.bottom;
+ if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
+ // The status bar forces the navigation bar while it's visible. Make sure the IME
+ // avoids the navigation bar in that case.
+ if (mNavigationBarPosition == NAV_BAR_RIGHT) {
+ pf.right = df.right = of.right = cf.right = vf.right =
+ displayFrames.mStable.right;
+ } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
+ pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left;
+ }
+ }
+
+ // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
+ // Offset the ime to avoid overlapping with the nav bar
+ mExperiments.offsetWindowFramesForNavBar(mNavigationBarPosition, win);
+ // EXPERIMENT END
+
+ // IM dock windows always go to the bottom of the screen.
+ attrs.gravity = Gravity.BOTTOM;
+ } else if (type == TYPE_VOICE_INTERACTION) {
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
+ if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+ cf.set(displayFrames.mDock);
+ } else {
+ cf.set(displayFrames.mContent);
+ }
+ if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+ vf.set(displayFrames.mCurrent);
+ } else {
+ vf.set(cf);
+ }
+ } else if (type == TYPE_WALLPAPER) {
+ layoutWallpaper(displayFrames, pf, df, of, cf);
+ } else if (win == mStatusBar) {
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
+ cf.set(displayFrames.mStable);
+ vf.set(displayFrames.mStable);
+
+ if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
+ cf.bottom = displayFrames.mContent.bottom;
+ } else {
+ cf.bottom = displayFrames.mDock.bottom;
+ vf.bottom = displayFrames.mContent.bottom;
+ }
+ } else {
+ dcf.set(displayFrames.mSystem);
+ final boolean inheritTranslucentDecor =
+ (attrs.privateFlags & PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
+ final boolean isAppWindow =
+ type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
+ final boolean topAtRest =
+ win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
+ if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
+ if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
+ && (fl & FLAG_FULLSCREEN) == 0
+ && (fl & FLAG_TRANSLUCENT_STATUS) == 0
+ && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
+ && (pfl & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) == 0) {
+ // Ensure policy decor includes status bar
+ dcf.top = displayFrames.mStable.top;
+ }
+ if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
+ && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
+ && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
+ // Ensure policy decor includes navigation bar
+ dcf.bottom = displayFrames.mStable.bottom;
+ dcf.right = displayFrames.mStable.right;
+ }
+ }
+
+ if (layoutInScreen && layoutInsetDecor) {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ + "): IN_SCREEN, INSET_DECOR");
+ // This is the case for a normal activity window: we want it to cover all of the
+ // screen space, and it can take care of moving its contents to account for screen
+ // decorations that intrude into that space.
+ if (attached != null) {
+ // If this window is attached to another, our display
+ // frame is the same as the one we are attached to.
+ setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf,
+ displayFrames);
+ } else {
+ if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
+ // Status bar panels are the only windows who can go on top of the status
+ // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
+ // have the same privileges as the status bar itself.
+ //
+ // However, they should still dodge the navigation bar if it exists.
+
+ pf.left = df.left = of.left = hasNavBar
+ ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
+ pf.top = df.top = of.top = displayFrames.mUnrestricted.top;
+ pf.right = df.right = of.right = hasNavBar
+ ? displayFrames.mRestricted.right
+ : displayFrames.mUnrestricted.right;
+ pf.bottom = df.bottom = of.bottom = hasNavBar
+ ? displayFrames.mRestricted.bottom
+ : displayFrames.mUnrestricted.bottom;
+
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
+ } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
+ && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
+ // Asking to layout into the overscan region, so give it that pure
+ // unrestricted area.
+ of.set(displayFrames.mOverscan);
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
+ } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+ && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
+ || type == TYPE_VOLUME_OVERLAY)) {
+ // Asking for layout as if the nav bar is hidden, lets the application
+ // extend into the unrestricted overscan screen area. We only do this for
+ // application windows and certain system windows to ensure no window that
+ // can be above the nav bar can do this.
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
+ // We need to tell the app about where the frame inside the overscan is, so
+ // it can inset its content by that amount -- it didn't ask to actually
+ // extend itself into the overscan region.
+ of.set(displayFrames.mUnrestricted);
+ } else {
+ df.set(displayFrames.mRestrictedOverscan);
+ pf.set(displayFrames.mRestrictedOverscan);
+ // We need to tell the app about where the frame inside the overscan
+ // is, so it can inset its content by that amount -- it didn't ask
+ // to actually extend itself into the overscan region.
+ of.set(displayFrames.mUnrestricted);
+ }
+
+ if ((fl & FLAG_FULLSCREEN) == 0) {
+ if (win.isVoiceInteraction()) {
+ cf.set(displayFrames.mVoiceContent);
+ } else {
+ if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+ cf.set(displayFrames.mDock);
+ } else {
+ cf.set(displayFrames.mContent);
+ }
+ }
+ } else {
+ // Full screen windows are always given a layout that is as if the status
+ // bar and other transient decors are gone. This is to avoid bad states when
+ // moving from a window that is not hiding the status bar to one that is.
+ cf.set(displayFrames.mRestricted);
+ }
+ applyStableConstraints(sysUiFl, fl, cf, displayFrames);
+ if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+ vf.set(displayFrames.mCurrent);
+ } else {
+ vf.set(cf);
+ }
+
+ // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
+ mExperiments.offsetWindowFramesForNavBar(mNavigationBarPosition, win);
+ // EXPERIMENT END
+ }
+ } else if (layoutInScreen || (sysUiFl
+ & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ + "): IN_SCREEN");
+ // A window that has requested to fill the entire screen just
+ // gets everything, period.
+ if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
+ cf.set(displayFrames.mUnrestricted);
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
+ if (hasNavBar) {
+ pf.left = df.left = of.left = cf.left = displayFrames.mDock.left;
+ pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right;
+ pf.bottom = df.bottom = of.bottom = cf.bottom =
+ displayFrames.mRestricted.bottom;
+ }
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
+ } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
+ // The navigation bar has Real Ultimate Power.
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
+ } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
+ && ((fl & FLAG_FULLSCREEN) != 0)) {
+ // Fullscreen secure system overlays get what they ask for. Screenshot region
+ // selection overlay should also expand to full screen.
+ cf.set(displayFrames.mOverscan);
+ of.set(displayFrames.mOverscan);
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
+ } else if (type == TYPE_BOOT_PROGRESS) {
+ // Boot progress screen always covers entire display.
+ cf.set(displayFrames.mOverscan);
+ of.set(displayFrames.mOverscan);
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
+ } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
+ && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
+ // Asking to layout into the overscan region, so give it that pure unrestricted
+ // area.
+ cf.set(displayFrames.mOverscan);
+ of.set(displayFrames.mOverscan);
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
+ } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
+ && (type == TYPE_STATUS_BAR
+ || type == TYPE_TOAST
+ || type == TYPE_DOCK_DIVIDER
+ || type == TYPE_VOICE_INTERACTION_STARTING
+ || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
+ // Asking for layout as if the nav bar is hidden, lets the
+ // application extend into the unrestricted screen area. We
+ // only do this for application windows (or toasts) to ensure no window that
+ // can be above the nav bar can do this.
+ // XXX This assumes that an app asking for this will also
+ // ask for layout in only content. We can't currently figure out
+ // what the screen would be if only laying out to hide the nav bar.
+ cf.set(displayFrames.mUnrestricted);
+ of.set(displayFrames.mUnrestricted);
+ df.set(displayFrames.mUnrestricted);
+ pf.set(displayFrames.mUnrestricted);
+ } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
+ of.set(displayFrames.mRestricted);
+ df.set(displayFrames.mRestricted);
+ pf.set(displayFrames.mRestricted);
+ if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+ cf.set(displayFrames.mDock);
+ } else {
+ cf.set(displayFrames.mContent);
+ }
+ } else {
+ cf.set(displayFrames.mRestricted);
+ of.set(displayFrames.mRestricted);
+ df.set(displayFrames.mRestricted);
+ pf.set(displayFrames.mRestricted);
+ }
+
+ applyStableConstraints(sysUiFl, fl, cf, displayFrames);
+
+ if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+ vf.set(displayFrames.mCurrent);
+ } else {
+ vf.set(cf);
+ }
+ } else if (attached != null) {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ + "): attached to " + attached);
+ // A child window should be placed inside of the same visible
+ // frame that its parent had.
+ setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf,
+ displayFrames);
+ } else {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
+ + "): normal window");
+ // Otherwise, a normal window must be placed inside the content
+ // of all screen decorations.
+ if (type == TYPE_STATUS_BAR_PANEL) {
+ // Status bar panels can go on
+ // top of the status bar. They are protected by the STATUS_BAR_SERVICE
+ // permission, so they have the same privileges as the status bar itself.
+ cf.set(displayFrames.mRestricted);
+ of.set(displayFrames.mRestricted);
+ df.set(displayFrames.mRestricted);
+ pf.set(displayFrames.mRestricted);
+ } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
+ // These dialogs are stable to interim decor changes.
+ cf.set(displayFrames.mStable);
+ of.set(displayFrames.mStable);
+ df.set(displayFrames.mStable);
+ pf.set(displayFrames.mStable);
+ } else {
+ pf.set(displayFrames.mContent);
+ if (win.isVoiceInteraction()) {
+ cf.set(displayFrames.mVoiceContent);
+ of.set(displayFrames.mVoiceContent);
+ df.set(displayFrames.mVoiceContent);
+ } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+ cf.set(displayFrames.mDock);
+ of.set(displayFrames.mDock);
+ df.set(displayFrames.mDock);
+ } else {
+ cf.set(displayFrames.mContent);
+ of.set(displayFrames.mContent);
+ df.set(displayFrames.mContent);
+ }
+ if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+ vf.set(displayFrames.mCurrent);
+ } else {
+ vf.set(cf);
+ }
+ }
+ }
+ }
+
+ final int cutoutMode = attrs.layoutInDisplayCutoutMode;
+ final boolean attachedInParent = attached != null && !layoutInScreen;
+ final boolean requestedHideNavigation =
+ (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
+
+ // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
+ // cropped / shifted to the displayFrame in WindowState.
+ final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
+ && type != TYPE_BASE_APPLICATION;
+
+ // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
+ // the cutout safe zone.
+ if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
+ final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
+ displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
+ if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
+ && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
+ // At the top we have the status bar, so apps that are
+ // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
+ // already expect that there's an inset there and we don't need to exclude
+ // the window from that area.
+ displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
+ }
+ if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
+ && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
+ // Same for the navigation bar.
+ switch (mNavigationBarPosition) {
+ case NAV_BAR_BOTTOM:
+ displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
+ break;
+ case NAV_BAR_RIGHT:
+ displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
+ break;
+ case NAV_BAR_LEFT:
+ displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
+ break;
+ }
+ }
+ if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
+ // The IME can always extend under the bottom cutout if the navbar is there.
+ displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
+ }
+ // Windows that are attached to a parent and laid out in said parent already avoid
+ // the cutout according to that parent and don't need to be further constrained.
+ // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
+ // They will later be cropped or shifted using the displayFrame in WindowState,
+ // which prevents overlap with the DisplayCutout.
+ if (!attachedInParent && !floatingInScreenWindow) {
+ sTmpRect.set(pf);
+ pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
+ windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
+ }
+ // Make sure that NO_LIMITS windows clipped to the display don't extend under the
+ // cutout.
+ df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
+ }
+
+ // Content should never appear in the cutout.
+ cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
+
+ // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
+ // Also, we don't allow windows in multi-window mode to extend out of the screen.
+ if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
+ && !win.isInMultiWindowMode()) {
+ df.left = df.top = -10000;
+ df.right = df.bottom = 10000;
+ if (type != TYPE_WALLPAPER) {
+ of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
+ of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
+ }
+ }
+
+ // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
+ // need to provide information to the clients that want to pretend that you can draw there.
+ // We only want to apply outsets to certain types of windows. For example, we never want to
+ // apply the outsets to floating dialogs, because they wouldn't make sense there.
+ final boolean useOutsets = shouldUseOutsets(attrs, fl);
+ if (isDefaultDisplay && useOutsets) {
+ final Rect osf = windowFrames.mOutsetFrame;
+ osf.set(cf.left, cf.top, cf.right, cf.bottom);
+ windowFrames.setHasOutsets(true);
+ int outset = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
+ if (outset > 0) {
+ int rotation = displayFrames.mRotation;
+ if (rotation == Surface.ROTATION_0) {
+ osf.bottom += outset;
+ } else if (rotation == Surface.ROTATION_90) {
+ osf.right += outset;
+ } else if (rotation == Surface.ROTATION_180) {
+ osf.top -= outset;
+ } else if (rotation == Surface.ROTATION_270) {
+ osf.left -= outset;
+ }
+ if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset
+ + " with rotation " + rotation + ", result: " + osf);
+ }
+ }
+
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
+ + ": sim=#" + Integer.toHexString(sim)
+ + " attach=" + attached + " type=" + type
+ + String.format(" flags=0x%08x", fl)
+ + " pf=" + pf.toShortString() + " df=" + df.toShortString()
+ + " of=" + of.toShortString()
+ + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
+ + " dcf=" + dcf.toShortString()
+ + " sf=" + sf.toShortString()
+ + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
+
+ if (!sTmpLastParentFrame.equals(pf)) {
+ windowFrames.setContentChanged(true);
+ }
+
+ win.computeFrameLw();
+ // Dock windows carve out the bottom of the screen, so normal windows
+ // can't appear underneath them.
+ if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
+ && !win.getGivenInsetsPendingLw()) {
+ offsetInputMethodWindowLw(win, displayFrames);
+ }
+ if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
+ && !win.getGivenInsetsPendingLw()) {
+ offsetVoiceInputWindowLw(win, displayFrames);
+ }
+ }
+
+ private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) {
+ // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area.
+ df.set(displayFrames.mOverscan);
+ pf.set(displayFrames.mOverscan);
+ cf.set(displayFrames.mUnrestricted);
+ of.set(displayFrames.mUnrestricted);
+ }
+
+ private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
+ int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
+ top += win.getGivenContentInsetsLw().top;
+ displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
+ displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
+ top = win.getVisibleFrameLw().top;
+ top += win.getGivenVisibleInsetsLw().top;
+ displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
+ + displayFrames.mDock.bottom + " mContentBottom="
+ + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
+ }
+
+ private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
+ int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
+ top += win.getGivenContentInsetsLw().top;
+ displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
+ }
+
+ /**
+ * Called following layout of all windows before each window has policy applied.
+ */
+ public void beginPostLayoutPolicyLw() {
+ mTopFullscreenOpaqueWindowState = null;
+ mTopFullscreenOpaqueOrDimmingWindowState = null;
+ mTopDockedOpaqueWindowState = null;
+ mTopDockedOpaqueOrDimmingWindowState = null;
+ mForceStatusBar = false;
+ mForceStatusBarFromKeyguard = false;
+ mForceStatusBarTransparent = false;
+ mForcingShowNavBar = false;
+ mForcingShowNavBarLayer = -1;
+
+ mAllowLockscreenWhenOn = false;
+ mShowingDream = false;
+ mWindowSleepTokenNeeded = false;
+ }
+
+ /**
+ * Called following layout of all window to apply policy to each window.
+ *
+ * @param win The window being positioned.
+ * @param attrs The LayoutParams of the window.
+ * @param attached For sub-windows, the window it is attached to. Otherwise null.
+ */
+ public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
+ WindowState attached, WindowState imeTarget) {
+ final boolean affectsSystemUi = win.canAffectSystemUiFlags();
+ if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
+ mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
+ final int fl = PolicyControl.getWindowFlags(win, attrs);
+ if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
+ && attrs.type == TYPE_INPUT_METHOD) {
+ mForcingShowNavBar = true;
+ mForcingShowNavBarLayer = win.getSurfaceLayer();
+ }
+ if (attrs.type == TYPE_STATUS_BAR) {
+ if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+ mForceStatusBarFromKeyguard = true;
+ }
+ if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
+ mForceStatusBarTransparent = true;
+ }
+ }
+
+ boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
+ && attrs.type < FIRST_SYSTEM_WINDOW;
+ final int windowingMode = win.getWindowingMode();
+ final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
+ windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+ if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
+ if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
+ mForceStatusBar = true;
+ }
+ if (attrs.type == TYPE_DREAM) {
+ // If the lockscreen was showing when the dream started then wait
+ // for the dream to draw before hiding the lockscreen.
+ if (!mDreamingLockscreen
+ || (win.isVisibleLw() && win.hasDrawnLw())) {
+ mShowingDream = true;
+ appWindow = true;
+ }
+ }
+
+ // For app windows that are not attached, we decide if all windows in the app they
+ // represent should be hidden or if we should hide the lockscreen. For attached app
+ // windows we defer the decision to the window it is attached to.
+ if (appWindow && attached == null) {
+ if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
+ mTopFullscreenOpaqueWindowState = win;
+ if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
+ mTopFullscreenOpaqueOrDimmingWindowState = win;
+ }
+ if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
+ mAllowLockscreenWhenOn = true;
+ }
+ }
+ }
+ }
+
+ // Voice interaction overrides both top fullscreen and top docked.
+ if (affectsSystemUi && win.getAttrs().type == TYPE_VOICE_INTERACTION) {
+ if (mTopFullscreenOpaqueWindowState == null) {
+ mTopFullscreenOpaqueWindowState = win;
+ if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
+ mTopFullscreenOpaqueOrDimmingWindowState = win;
+ }
+ }
+ if (mTopDockedOpaqueWindowState == null) {
+ mTopDockedOpaqueWindowState = win;
+ if (mTopDockedOpaqueOrDimmingWindowState == null) {
+ mTopDockedOpaqueOrDimmingWindowState = win;
+ }
+ }
+ }
+
+ // Keep track of the window if it's dimming but not necessarily fullscreen.
+ if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
+ && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
+ mTopFullscreenOpaqueOrDimmingWindowState = win;
+ }
+
+ // We need to keep track of the top "fullscreen" opaque window for the docked stack
+ // separately, because both the "real fullscreen" opaque window and the one for the docked
+ // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
+ if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
+ && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ mTopDockedOpaqueWindowState = win;
+ if (mTopDockedOpaqueOrDimmingWindowState == null) {
+ mTopDockedOpaqueOrDimmingWindowState = win;
+ }
+ }
+
+ // Also keep track of any windows that are dimming but not necessarily fullscreen in the
+ // docked stack.
+ if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
+ && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ mTopDockedOpaqueOrDimmingWindowState = win;
+ }
+
+ // Take note if a window wants to acquire a sleep token.
+ if ((attrs.privateFlags & PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN) != 0
+ && win.canAcquireSleepToken()) {
+ mWindowSleepTokenNeeded = true;
+ }
+ }
+
+ /**
+ * Called following layout of all windows and after policy has been applied
+ * to each window. If in this function you do
+ * something that may have modified the animation state of another window,
+ * be sure to return non-zero in order to perform another pass through layout.
+ *
+ * @return Return any bit set of
+ * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
+ * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
+ * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
+ * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
+ */
+ public int finishPostLayoutPolicyLw() {
+ int changes = 0;
+ boolean topIsFullscreen = false;
+
+ // If we are not currently showing a dream then remember the current
+ // lockscreen state. We will use this to determine whether the dream
+ // started while the lockscreen was showing and remember this state
+ // while the dream is showing.
+ if (!mShowingDream) {
+ mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
+ if (mDreamingSleepTokenNeeded) {
+ mDreamingSleepTokenNeeded = false;
+ mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
+ }
+ } else {
+ if (!mDreamingSleepTokenNeeded) {
+ mDreamingSleepTokenNeeded = true;
+ mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
+ }
+ }
+
+ if (mStatusBar != null) {
+ if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
+ + " forcefkg=" + mForceStatusBarFromKeyguard
+ + " top=" + mTopFullscreenOpaqueWindowState);
+ boolean shouldBeTransparent = mForceStatusBarTransparent
+ && !mForceStatusBar
+ && !mForceStatusBarFromKeyguard;
+ if (!shouldBeTransparent) {
+ mStatusBarController.setShowTransparent(false /* transparent */);
+ } else if (!mStatusBar.isVisibleLw()) {
+ mStatusBarController.setShowTransparent(true /* transparent */);
+ }
+
+ boolean statusBarForcesShowingNavigation =
+ (mStatusBar.getAttrs().privateFlags
+ & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
+ boolean topAppHidesStatusBar = topAppHidesStatusBar();
+ if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent
+ || statusBarForcesShowingNavigation) {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
+ if (mStatusBarController.setBarShowingLw(true)) {
+ changes |= FINISH_LAYOUT_REDO_LAYOUT;
+ }
+ // Maintain fullscreen layout until incoming animation is complete.
+ topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
+ // Transient status bar is not allowed if status bar is on lockscreen or status bar
+ // is expecting the navigation keys from the user.
+ if ((mForceStatusBarFromKeyguard || statusBarForcesShowingNavigation)
+ && mStatusBarController.isTransientShowing()) {
+ mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
+ mLastSystemUiFlags, mLastSystemUiFlags);
+ }
+ } else if (mTopFullscreenOpaqueWindowState != null) {
+ topIsFullscreen = topAppHidesStatusBar;
+ // The subtle difference between the window for mTopFullscreenOpaqueWindowState
+ // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
+ // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
+ // case though.
+ if (mStatusBarController.isTransientShowing()) {
+ if (mStatusBarController.setBarShowingLw(true)) {
+ changes |= FINISH_LAYOUT_REDO_LAYOUT;
+ }
+ } else if (topIsFullscreen
+ && !mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM)
+ && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
+ if (mStatusBarController.setBarShowingLw(false)) {
+ changes |= FINISH_LAYOUT_REDO_LAYOUT;
+ } else {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
+ }
+ } else {
+ if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
+ if (mStatusBarController.setBarShowingLw(true)) {
+ changes |= FINISH_LAYOUT_REDO_LAYOUT;
+ }
+ topAppHidesStatusBar = false;
+ }
+ }
+ mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
+ }
+
+ if (mTopIsFullscreen != topIsFullscreen) {
+ if (!topIsFullscreen) {
+ // Force another layout when status bar becomes fully shown.
+ changes |= FINISH_LAYOUT_REDO_LAYOUT;
+ }
+ mTopIsFullscreen = topIsFullscreen;
+ }
+
+ if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
+ // If the navigation bar has been hidden or shown, we need to do another
+ // layout pass to update that window.
+ changes |= FINISH_LAYOUT_REDO_LAYOUT;
+ }
+
+ if (mShowingDream != mLastShowingDream) {
+ mLastShowingDream = mShowingDream;
+ mService.notifyShowingDreamChanged();
+ }
+
+ updateWindowSleepToken();
+
+ mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
+ return changes;
+ }
+
+ private void updateWindowSleepToken() {
+ if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
+ mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
+ mHandler.post(mAcquireSleepTokenRunnable);
+ } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
+ mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
+ mHandler.post(mReleaseSleepTokenRunnable);
+ }
+ mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
+ }
+
+ /**
+ * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
+ * window.
+ */
+ private boolean topAppHidesStatusBar() {
+ if (mTopFullscreenOpaqueWindowState == null) {
+ return false;
+ }
+ final int fl = PolicyControl.getWindowFlags(null,
+ mTopFullscreenOpaqueWindowState.getAttrs());
+ if (localLOGV) {
+ Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
+ Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
+ + " lp.flags=0x" + Integer.toHexString(fl));
+ }
+ return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
+ || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
+ }
+
+ /**
+ * Called when the resource overlays change.
+ */
+ public void onOverlayChangedLw() {
+ onConfigurationChanged();
+ }
+
+ /**
+ * Called when the configuration has changed, and it's safe to load new values from resources.
+ */
+ public void onConfigurationChanged() {
+ final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
+
+ final Context uiContext = getSystemUiContext();
+ final Resources res = uiContext.getResources();
+ final int portraitRotation = displayRotation.getPortraitRotation();
+ final int upsideDownRotation = displayRotation.getUpsideDownRotation();
+ final int landscapeRotation = displayRotation.getLandscapeRotation();
+ final int seascapeRotation = displayRotation.getSeascapeRotation();
+
+ mStatusBarHeightForRotation[portraitRotation] =
+ mStatusBarHeightForRotation[upsideDownRotation] =
+ res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
+ mStatusBarHeightForRotation[landscapeRotation] =
+ mStatusBarHeightForRotation[seascapeRotation] =
+ res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
+
+ // Height of the navigation bar when presented horizontally at bottom
+ mNavigationBarHeightForRotationDefault[portraitRotation] =
+ mNavigationBarHeightForRotationDefault[upsideDownRotation] =
+ res.getDimensionPixelSize(R.dimen.navigation_bar_height);
+ mNavigationBarHeightForRotationDefault[landscapeRotation] =
+ mNavigationBarHeightForRotationDefault[seascapeRotation] =
+ res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
+
+ // Width of the navigation bar when presented vertically along one side
+ mNavigationBarWidthForRotationDefault[portraitRotation] =
+ mNavigationBarWidthForRotationDefault[upsideDownRotation] =
+ mNavigationBarWidthForRotationDefault[landscapeRotation] =
+ mNavigationBarWidthForRotationDefault[seascapeRotation] =
+ res.getDimensionPixelSize(R.dimen.navigation_bar_width);
+
+ if (ALTERNATE_CAR_MODE_NAV_SIZE) {
+ // Height of the navigation bar when presented horizontally at bottom
+ mNavigationBarHeightForRotationInCarMode[portraitRotation] =
+ mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
+ res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
+ mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
+ mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
+ res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
+
+ // Width of the navigation bar when presented vertically along one side
+ mNavigationBarWidthForRotationInCarMode[portraitRotation] =
+ mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
+ mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
+ mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
+ res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
+ }
+
+ // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
+ mExperiments.onConfigurationChanged(uiContext);
+ // EXPERIMENT END
+ }
+
+ @VisibleForTesting
+ Context getSystemUiContext() {
+ final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
+ return mDisplayContent.isDefaultDisplay
+ ? uiContext : uiContext.createDisplayContext(mDisplayContent.getDisplay());
+ }
+
+ private int getNavigationBarWidth(int rotation, int uiMode) {
+ if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
+ return mNavigationBarWidthForRotationInCarMode[rotation];
+ } else {
+ return mNavigationBarWidthForRotationDefault[rotation];
+ }
+ }
+
+ /**
+ * Return the display width available after excluding any screen
+ * decorations that could never be removed in Honeycomb. That is, system bar or
+ * button bar.
+ */
+ public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
+ DisplayCutout displayCutout) {
+ int width = fullWidth;
+ if (hasNavigationBar()) {
+ // For a basic navigation bar, when we are in landscape mode we place
+ // the navigation bar to the side.
+ if (navigationBarCanMove() && fullWidth > fullHeight) {
+ width -= getNavigationBarWidth(rotation, uiMode);
+ }
+ }
+ if (displayCutout != null) {
+ width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
+ }
+ return width;
+ }
+
+ private int getNavigationBarHeight(int rotation, int uiMode) {
+ if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
+ return mNavigationBarHeightForRotationInCarMode[rotation];
+ } else {
+ return mNavigationBarHeightForRotationDefault[rotation];
+ }
+ }
+
+ /**
+ * Return the display height available after excluding any screen
+ * decorations that could never be removed in Honeycomb. That is, system bar or
+ * button bar.
+ */
+ public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
+ DisplayCutout displayCutout) {
+ int height = fullHeight;
+ if (hasNavigationBar()) {
+ // For a basic navigation bar, when we are in portrait mode we place
+ // the navigation bar to the bottom.
+ if (!navigationBarCanMove() || fullWidth < fullHeight) {
+ height -= getNavigationBarHeight(rotation, uiMode);
+ }
+ }
+ if (displayCutout != null) {
+ height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
+ }
+ return height;
+ }
+
+ /**
+ * Return the available screen width that we should report for the
+ * configuration. This must be no larger than
+ * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
+ * than that to account for more transient decoration like a status bar.
+ */
+ public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
+ DisplayCutout displayCutout) {
+ return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
+ }
+
+ /**
+ * Return the available screen height that we should report for the
+ * configuration. This must be no larger than
+ * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
+ * than that to account for more transient decoration like a status bar.
+ */
+ public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
+ DisplayCutout displayCutout) {
+ // There is a separate status bar at the top of the display. We don't count that as part
+ // of the fixed decor, since it can hide; however, for purposes of configurations,
+ // we do want to exclude it since applications can't generally use that part
+ // of the screen.
+ int statusBarHeight = mStatusBarHeightForRotation[rotation];
+ if (displayCutout != null) {
+ // If there is a cutout, it may already have accounted for some part of the status
+ // bar height.
+ statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
+ }
+ return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
+ - statusBarHeight;
+ }
+
+ boolean isShowingDreamLw() {
+ return mShowingDream;
+ }
+
+ /**
+ * Calculates the stable insets without running a layout.
+ *
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param displayCutout the current display cutout
+ * @param outInsets the insets to return
+ */
+ public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
+ DisplayCutout displayCutout, Rect outInsets) {
+ outInsets.setEmpty();
+
+ // Navigation bar and status bar.
+ getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
+ outInsets.top = Math.max(outInsets.top, mStatusBarHeightForRotation[displayRotation]);
+ }
+
+ /**
+ * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
+ * bar or button bar. See {@link #getNonDecorDisplayWidth}.
+ *
+ * @param displayRotation the current display rotation
+ * @param displayWidth the current display width
+ * @param displayHeight the current display height
+ * @param displayCutout the current display cutout
+ * @param outInsets the insets to return
+ */
+ public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
+ DisplayCutout displayCutout, Rect outInsets) {
+ outInsets.setEmpty();
+
+ // Only navigation bar
+ if (hasNavigationBar()) {
+ final int uiMode = mService.mPolicy.getUiMode();
+ int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
+ if (position == NAV_BAR_BOTTOM) {
+ outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
+ } else if (position == NAV_BAR_RIGHT) {
+ outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
+ } else if (position == NAV_BAR_LEFT) {
+ outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
+ }
+ }
+
+ if (displayCutout != null) {
+ outInsets.left += displayCutout.getSafeInsetLeft();
+ outInsets.top += displayCutout.getSafeInsetTop();
+ outInsets.right += displayCutout.getSafeInsetRight();
+ outInsets.bottom += displayCutout.getSafeInsetBottom();
+ }
+ }
+
+ @NavigationBarPosition
+ int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
+ if (navigationBarCanMove() && displayWidth > displayHeight) {
+ if (displayRotation == Surface.ROTATION_270) {
+ return NAV_BAR_LEFT;
+ } else if (displayRotation == Surface.ROTATION_90) {
+ return NAV_BAR_RIGHT;
+ }
+ }
+ return NAV_BAR_BOTTOM;
+ }
+
+ /**
+ * @return The side of the screen where navigation bar is positioned.
+ * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
+ * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
+ * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
+ */
+ @NavigationBarPosition
+ public int getNavBarPosition() {
+ return mNavigationBarPosition;
+ }
+
+ /**
+ * A new window has been focused.
+ */
+ public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
+ mFocusedWindow = newFocus;
+ mLastFocusedWindow = lastFocus;
+ if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
+ // If the navigation bar has been hidden or shown, we need to do another
+ // layout pass to update that window.
+ return FINISH_LAYOUT_REDO_LAYOUT;
+ }
+ return 0;
+ }
+
+ /**
+ * Return true if it is okay to perform animations for an app transition
+ * that is about to occur. You may return false for this if, for example,
+ * the dream window is currently displayed so the switch should happen
+ * immediately.
+ */
+ public boolean allowAppAnimationsLw() {
+ return !mShowingDream;
+ }
+
+ private void updateDreamingSleepToken(boolean acquire) {
+ if (acquire) {
+ final int displayId = getDisplayId();
+ if (mDreamingSleepToken == null) {
+ mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken(
+ "DreamOnDisplay" + displayId, displayId);
+ }
+ } else {
+ if (mDreamingSleepToken != null) {
+ mDreamingSleepToken.release();
+ mDreamingSleepToken = null;
+ }
+ }
+ }
+
+ private void requestTransientBars(WindowState swipeTarget) {
+ synchronized (mLock) {
+ if (!mService.mPolicy.isUserSetupComplete()) {
+ // Swipe-up for navigation bar is disabled during setup
+ return;
+ }
+ boolean sb = mStatusBarController.checkShowTransientBarLw();
+ boolean nb = mNavigationBarController.checkShowTransientBarLw()
+ && !isNavBarEmpty(mLastSystemUiFlags);
+ if (sb || nb) {
+ // Don't show status bar when swiping on already visible navigation bar
+ if (!nb && swipeTarget == mNavigationBar) {
+ if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
+ return;
+ }
+ if (sb) mStatusBarController.showTransient();
+ if (nb) mNavigationBarController.showTransient();
+ mImmersiveModeConfirmation.confirmCurrentPrompt();
+ updateSystemUiVisibilityLw();
+ }
+ }
+ }
+
+ private void disposeInputConsumer(InputConsumer inputConsumer) {
+ if (inputConsumer != null) {
+ inputConsumer.dismiss();
+ }
+ }
+
+ private boolean isStatusBarKeyguard() {
+ return mStatusBar != null
+ && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
+ }
+
+ private boolean isKeyguardOccluded() {
+ // TODO (b/113840485): Handle per display keyguard.
+ return mService.mPolicy.isKeyguardOccluded();
+ }
+
+ void resetSystemUiVisibilityLw() {
+ mLastSystemUiFlags = 0;
+ updateSystemUiVisibilityLw();
+ }
+
+ private int updateSystemUiVisibilityLw() {
+ // If there is no window focused, there will be nobody to handle the events
+ // anyway, so just hang on in whatever state we're in until things settle down.
+ WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
+ : mTopFullscreenOpaqueWindowState;
+ if (winCandidate == null) {
+ return 0;
+ }
+
+ // The immersive mode confirmation should never affect the system bar visibility, otherwise
+ // it will unhide the navigation bar and hide itself.
+ if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
+
+ // The immersive mode confirmation took the focus from mLastFocusedWindow which was
+ // controlling the system ui visibility. So if mLastFocusedWindow can still receive
+ // keys, we let it keep controlling the visibility.
+ final boolean lastFocusCanReceiveKeys =
+ (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
+ winCandidate = isStatusBarKeyguard() ? mStatusBar
+ : lastFocusCanReceiveKeys ? mLastFocusedWindow
+ : mTopFullscreenOpaqueWindowState;
+ if (winCandidate == null) {
+ return 0;
+ }
+ }
+ final WindowState win = winCandidate;
+ if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && isKeyguardOccluded()) {
+ // We are updating at a point where the keyguard has gotten
+ // focus, but we were last in a state where the top window is
+ // hiding it. This is probably because the keyguard as been
+ // shown while the top window was displayed, so we want to ignore
+ // it here because this is just a very transient change and it
+ // will quickly lose focus once it correctly gets hidden.
+ return 0;
+ }
+
+ int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
+ & ~mResettingSystemUiFlags
+ & ~mForceClearedSystemUiFlags;
+ if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
+ tmpVisibility
+ &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
+ }
+
+ final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
+ mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
+ final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
+ mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
+ mService.getStackBounds(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds);
+ mService.getStackBounds(
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
+ final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
+ final int diff = visibility ^ mLastSystemUiFlags;
+ final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
+ final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
+ final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
+ if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
+ && mFocusedApp == win.getAppToken()
+ && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
+ && mLastDockedStackBounds.equals(mDockedStackBounds)) {
+ return 0;
+ }
+ mLastSystemUiFlags = visibility;
+ mLastFullscreenStackSysUiFlags = fullscreenVisibility;
+ mLastDockedStackSysUiFlags = dockedVisibility;
+ mLastFocusNeedsMenu = needsMenu;
+ mFocusedApp = win.getAppToken();
+ final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
+ final Rect dockedStackBounds = new Rect(mDockedStackBounds);
+ mHandler.post(() -> {
+ StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ final int displayId = getDisplayId();
+ statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility,
+ dockedVisibility, 0xffffffff, fullscreenStackBounds,
+ dockedStackBounds, win.toString());
+ statusBar.topAppWindowChanged(displayId, needsMenu);
+ }
+ });
+ return diff;
+ }
+
+ private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
+ final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded();
+ final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming;
+ if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
+ // If the top fullscreen-or-dimming window is also the top fullscreen, respect
+ // its light flag.
+ vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
+ & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ } else if (statusColorWin != null && statusColorWin.isDimming()) {
+ // Otherwise if it's dimming, clear the light flag.
+ vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ }
+ return vis;
+ }
+
+ @VisibleForTesting
+ @Nullable
+ static WindowState chooseNavigationColorWindowLw(WindowState opaque,
+ WindowState opaqueOrDimming, WindowState imeWindow,
+ @NavigationBarPosition int navBarPosition) {
+ // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
+ // window can be navigation color window.
+ final boolean imeWindowCanNavColorWindow = imeWindow != null
+ && imeWindow.isVisibleLw()
+ && navBarPosition == NAV_BAR_BOTTOM
+ && (PolicyControl.getWindowFlags(imeWindow, null)
+ & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
+
+ if (opaque != null && opaqueOrDimming == opaque) {
+ // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
+ // unless IME window is also eligible, since currently the IME window is always show
+ // above the opaque fullscreen app window, regardless of the IME target window.
+ // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
+ return imeWindowCanNavColorWindow ? imeWindow : opaque;
+ }
+
+ if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
+ // No dimming window is involved. Determine the result only with the IME window.
+ return imeWindowCanNavColorWindow ? imeWindow : null;
+ }
+
+ if (!imeWindowCanNavColorWindow) {
+ // No IME window is involved. Determine the result only with opaqueOrDimming.
+ return opaqueOrDimming;
+ }
+
+ // The IME window and the dimming window are competing. Check if the dimming window can be
+ // IME target or not.
+ if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
+ // The IME window is above the dimming window.
+ return imeWindow;
+ } else {
+ // The dimming window is above the IME window.
+ return opaqueOrDimming;
+ }
+ }
+
+ @VisibleForTesting
+ static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
+ WindowState imeWindow, WindowState navColorWin) {
+
+ if (navColorWin != null) {
+ if (navColorWin == imeWindow || navColorWin == opaque) {
+ // Respect the light flag.
+ vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+ vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
+ & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+ } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
+ // Clear the light flag for dimming window.
+ vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+ }
+ }
+ return vis;
+ }
+
+ private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {
+ final boolean dockedStackVisible =
+ mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ final boolean freeformStackVisible =
+ mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
+ final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
+
+ // We need to force system bars when the docked stack is visible, when the freeform stack
+ // is visible but also when we are resizing for the transitions when docked stack
+ // visibility changes.
+ mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing;
+ final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
+
+ // apply translucent bar vis flags
+ WindowState fullscreenTransWin = isStatusBarKeyguard() && !isKeyguardOccluded()
+ ? mStatusBar
+ : mTopFullscreenOpaqueWindowState;
+ vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
+ vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
+ final int dockedVis = mStatusBarController.applyTranslucentFlagLw(
+ mTopDockedOpaqueWindowState, 0, 0);
+
+ final boolean fullscreenDrawsStatusBarBackground =
+ drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
+ final boolean dockedDrawsStatusBarBackground =
+ drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
+
+ // prevent status bar interaction from clearing certain flags
+ int type = win.getAttrs().type;
+ boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
+ if (statusBarHasFocus && !isStatusBarKeyguard()) {
+ int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_IMMERSIVE
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+ | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ if (isKeyguardOccluded()) {
+ flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
+ }
+ vis = (vis & ~flags) | (oldVis & flags);
+ }
+
+ if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
+ vis |= View.STATUS_BAR_TRANSPARENT;
+ vis &= ~View.STATUS_BAR_TRANSLUCENT;
+ } else if ((!areTranslucentBarsAllowed() && fullscreenTransWin != mStatusBar)
+ || forceOpaqueStatusBar) {
+ vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
+ }
+
+ vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing);
+
+ // update status bar
+ boolean immersiveSticky =
+ (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
+ final boolean hideStatusBarWM =
+ mTopFullscreenOpaqueWindowState != null
+ && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
+ & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
+ final boolean hideStatusBarSysui =
+ (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
+ final boolean hideNavBarSysui =
+ (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
+
+ final boolean transientStatusBarAllowed = mStatusBar != null
+ && (statusBarHasFocus || (!mForceShowSystemBars
+ && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
+
+ final boolean transientNavBarAllowed = mNavigationBar != null
+ && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
+
+ final long now = SystemClock.uptimeMillis();
+ final boolean pendingPanic = mPendingPanicGestureUptime != 0
+ && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
+ final DisplayPolicy defaultDisplayPolicy =
+ mService.getDefaultDisplayContentLocked().getDisplayPolicy();
+ if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard()
+ // TODO (b/111955725): Show keyguard presentation on all external displays
+ && defaultDisplayPolicy.isKeyguardDrawComplete()) {
+ // The user performed the panic gesture recently, we're about to hide the bars,
+ // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
+ mPendingPanicGestureUptime = 0;
+ mStatusBarController.showTransient();
+ if (!isNavBarEmpty(vis)) {
+ mNavigationBarController.showTransient();
+ }
+ }
+
+ final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
+ && !transientStatusBarAllowed && hideStatusBarSysui;
+ final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
+ && !transientNavBarAllowed;
+ if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
+ // clear the clearable flags instead
+ clearClearableFlagsLw();
+ vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
+ }
+
+ final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
+ immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
+ final boolean navAllowedHidden = immersive || immersiveSticky;
+
+ if (hideNavBarSysui && !navAllowedHidden
+ && mService.mPolicy.getWindowLayerLw(win)
+ > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
+ // We can't hide the navbar from this window otherwise the input consumer would not get
+ // the input events.
+ vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
+ }
+
+ vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
+
+ // update navigation bar
+ boolean oldImmersiveMode = isImmersiveMode(oldVis);
+ boolean newImmersiveMode = isImmersiveMode(vis);
+ if (oldImmersiveMode != newImmersiveMode) {
+ final String pkg = win.getOwningPackage();
+ mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
+ mService.mPolicy.isUserSetupComplete(),
+ isNavBarEmpty(win.getSystemUiVisibility()));
+ }
+
+ vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
+
+ final WindowState navColorWin = chooseNavigationColorWindowLw(
+ mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
+ mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
+ vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
+ mTopFullscreenOpaqueOrDimmingWindowState,
+ mDisplayContent.mInputMethodWindow, navColorWin);
+
+ return vis;
+ }
+
+ private boolean drawsStatusBarBackground(int vis, WindowState win) {
+ if (!mStatusBarController.isTransparentAllowed(win)) {
+ return false;
+ }
+ if (win == null) {
+ return true;
+ }
+
+ final boolean drawsSystemBars =
+ (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
+ final boolean forceDrawsSystemBars =
+ (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
+
+ return forceDrawsSystemBars || drawsSystemBars && (vis & View.STATUS_BAR_TRANSLUCENT) == 0;
+ }
+
+ /**
+ * @return the current visibility flags with the nav-bar opacity related flags toggled based
+ * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
+ */
+ private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
+ boolean freeformStackVisible, boolean isDockedDividerResizing) {
+ if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
+ if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
+ visibility = setNavBarOpaqueFlag(visibility);
+ }
+ } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
+ if (isDockedDividerResizing) {
+ visibility = setNavBarOpaqueFlag(visibility);
+ } else if (freeformStackVisible) {
+ visibility = setNavBarTranslucentFlag(visibility);
+ } else {
+ visibility = setNavBarOpaqueFlag(visibility);
+ }
+ }
+
+ if (!areTranslucentBarsAllowed()) {
+ visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
+ }
+ return visibility;
+ }
+
+ private int setNavBarOpaqueFlag(int visibility) {
+ return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
+ }
+
+ private int setNavBarTranslucentFlag(int visibility) {
+ visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
+ return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
+ }
+
+ private void clearClearableFlagsLw() {
+ int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
+ if (newVal != mResettingSystemUiFlags) {
+ mResettingSystemUiFlags = newVal;
+ mDisplayContent.reevaluateStatusBarVisibility();
+ }
+ }
+
+ private boolean isImmersiveMode(int vis) {
+ final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ return mNavigationBar != null
+ && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
+ && (vis & flags) != 0
+ && canHideNavigationBar();
+ }
+
+ /**
+ * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
+ */
+ private boolean canHideNavigationBar() {
+ return hasNavigationBar();
+ }
+
+ private static boolean isNavBarEmpty(int systemUiFlags) {
+ final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
+ | View.STATUS_BAR_DISABLE_BACK
+ | View.STATUS_BAR_DISABLE_RECENT);
+
+ return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
+ }
+
+ /**
+ * @return whether the navigation or status bar can be made translucent
+ *
+ * This should return true unless touch exploration is not enabled or
+ * R.boolean.config_enableTranslucentDecor is false.
+ */
+ private boolean areTranslucentBarsAllowed() {
+ return mTranslucentDecorEnabled;
+ }
+
+ boolean shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation,
+ int newRotation) {
+ // For the upside down rotation we don't rotate seamlessly as the navigation
+ // bar moves position.
+ // Note most apps (using orientation:sensor or user as opposed to fullSensor)
+ // will not enter the reverse portrait orientation, so actually the
+ // orientation won't change at all.
+ if (oldRotation == displayRotation.getUpsideDownRotation()
+ || newRotation == displayRotation.getUpsideDownRotation()) {
+ return false;
+ }
+ // If the navigation bar can't change sides, then it will
+ // jump when we change orientations and we don't rotate
+ // seamlessly.
+ if (!navigationBarCanMove()) {
+ return false;
+ }
+
+ final WindowState w = mTopFullscreenOpaqueWindowState;
+ if (w != mFocusedWindow) {
+ return false;
+ }
+
+ // We only enable seamless rotation if the top window has requested
+ // it and is in the fullscreen opaque state. Seamless rotation
+ // requires freezing various Surface states and won't work well
+ // with animations, so we disable it in the animation case for now.
+ if (w != null && !w.isAnimatingLw()
+ && w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) {
+ return true;
+ }
+ return false;
+ }
+
+ private final Runnable mHiddenNavPanic = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mLock) {
+ if (!mService.mPolicy.isUserSetupComplete()) {
+ // Swipe-up for navigation bar is disabled during setup
+ return;
+ }
+ mPendingPanicGestureUptime = SystemClock.uptimeMillis();
+ if (!isNavBarEmpty(mLastSystemUiFlags)) {
+ mNavigationBarController.showTransient();
+ }
+ }
+ }
+ };
+
+ void onPowerKeyDown(boolean isScreenOn) {
+ // Detect user pressing the power button in panic when an application has
+ // taken over the whole screen.
+ boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
+ SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
+ isNavBarEmpty(mLastSystemUiFlags));
+ if (panic) {
+ mHandler.post(mHiddenNavPanic);
+ }
+ }
+
+ void onVrStateChangedLw(boolean enabled) {
+ mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
+ }
+
+ /**
+ * Called when the state of lock task mode changes. This should be used to disable immersive
+ * mode confirmation.
+ *
+ * @param lockTaskState the new lock task mode state. One of
+ * {@link ActivityManager#LOCK_TASK_MODE_NONE},
+ * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
+ * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
+ */
+ public void onLockTaskStateChangedLw(int lockTaskState) {
+ mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
+ }
+
+ /**
+ * Request a screenshot be taken.
+ *
+ * @param screenshotType The type of screenshot, for example either
+ * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
+ * {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
+ */
+ public void takeScreenshot(int screenshotType) {
+ if (mScreenshotHelper != null) {
+ mScreenshotHelper.takeScreenshot(screenshotType,
+ mStatusBar != null && mStatusBar.isVisibleLw(),
+ mNavigationBar != null && mNavigationBar.isVisibleLw(), mHandler);
+ }
+ }
+
void dump(String prefix, PrintWriter pw) {
- pw.println(prefix + "DisplayPolicy");
- pw.print(prefix + " mCarDockEnablesAccelerometer=" + mCarDockEnablesAccelerometer);
- pw.println(" mDeskDockEnablesAccelerometer=" + mDeskDockEnablesAccelerometer);
- pw.print(prefix + " mDockMode=" + Intent.dockStateToString(mDockMode));
- pw.println(" mLidState=" + WindowManagerFuncs.lidStateToString(mLidState));
- pw.print(prefix + " mAwake=" + mAwake);
- pw.print(" mScreenOnEarly=" + mScreenOnEarly);
- pw.println(" mScreenOnFully=" + mScreenOnFully);
- pw.print(prefix + " mKeyguardDrawComplete=" + mKeyguardDrawComplete);
- pw.println(" mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
- pw.println(prefix + " mHdmiPlugged=" + mHdmiPlugged);
+ pw.print(prefix); pw.print("DisplayPolicy");
+ prefix += " ";
+ pw.print(prefix);
+ pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
+ pw.print(" mDeskDockEnablesAccelerometer=");
+ pw.println(mDeskDockEnablesAccelerometer);
+ pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
+ pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
+ pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
+ pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
+ pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
+ pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
+ pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
+ pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
+ if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
+ || mForceClearedSystemUiFlags != 0) {
+ pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
+ pw.print(Integer.toHexString(mLastSystemUiFlags));
+ pw.print(" mResettingSystemUiFlags=0x");
+ pw.print(Integer.toHexString(mResettingSystemUiFlags));
+ pw.print(" mForceClearedSystemUiFlags=0x");
+ pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
+ }
+ if (mLastFocusNeedsMenu) {
+ pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu);
+ }
+ pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
+ pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
+ pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
+ if (mStatusBar != null) {
+ pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
+ pw.print(" isStatusBarKeyguard="); pw.println(isStatusBarKeyguard());
+ }
+ if (mNavigationBar != null) {
+ pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
+ }
+ if (mFocusedWindow != null) {
+ pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
+ }
+ if (mFocusedApp != null) {
+ pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp);
+ }
+ if (mTopFullscreenOpaqueWindowState != null) {
+ pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
+ pw.println(mTopFullscreenOpaqueWindowState);
+ }
+ if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
+ pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
+ pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
+ }
+ if (mForcingShowNavBar) {
+ pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
+ pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
+ pw.println(mForcingShowNavBarLayer);
+ }
+ pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
+ pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
+ pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard);
+ pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
+ mStatusBarController.dump(pw, prefix);
+ mNavigationBarController.dump(pw, prefix);
+
+ pw.print(prefix); pw.println("Looper state:");
+ mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " ");
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 6ab7090..f1d1e49 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -844,9 +844,9 @@
pw.print(prefix + " mPortraitRotation=" + Surface.rotationToString(mPortraitRotation));
pw.println(" mUpsideDownRotation=" + Surface.rotationToString(mUpsideDownRotation));
- pw.print(prefix + " mSupportAutoRotation=" + mSupportAutoRotation);
+ pw.println(prefix + " mSupportAutoRotation=" + mSupportAutoRotation);
if (mOrientationListener != null) {
- pw.print(" mOrientationSensorEnabled=" + mOrientationListener.mEnabled);
+ mOrientationListener.dump(pw, prefix + " ");
}
pw.println();
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index c377072..7ea88bb 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -28,6 +28,8 @@
import static android.view.WindowManager.DOCKED_RIGHT;
import static android.view.WindowManager.DOCKED_TOP;
import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
@@ -52,6 +54,7 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.internal.policy.DockedDividerUtils;
import com.android.server.LocalServices;
@@ -184,8 +187,8 @@
.calculateNonDismissingSnapTarget(position).position;
DockedDividerUtils.calculateBoundsForPosition(snappedPosition, dockSide, mTmpRect,
mTmpRect2.width(), mTmpRect2.height(), getContentWidth());
- mService.mPolicy.getStableInsetsLw(rotation, mTmpRect2.width(), mTmpRect2.height(),
- displayCutout, mTmpRect3);
+ mDisplayContent.getDisplayPolicy().getStableInsetsLw(rotation, mTmpRect2.width(),
+ mTmpRect2.height(), displayCutout, mTmpRect3);
mService.intersectDisplayInsetBounds(mTmpRect2, mTmpRect3, mTmpRect);
minWidth = Math.min(mTmpRect.width(), minWidth);
}
@@ -231,8 +234,9 @@
final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout;
final int displayWidth = parentConfig.windowConfiguration.getBounds().width();
final int displayHeight = parentConfig.windowConfiguration.getBounds().height();
- mService.mPolicy.getStableInsetsLw(parentConfig.windowConfiguration.getRotation(),
- displayWidth, displayHeight, displayCutout, mTmpRect);
+ mDisplayContent.getDisplayPolicy().getStableInsetsLw(
+ parentConfig.windowConfiguration.getRotation(), displayWidth, displayHeight,
+ displayCutout, mTmpRect);
int dividerSize = mDividerWindowWidth - 2 * mDividerInsets;
// The offset in the left (landscape)/top (portrait) is calculated with the minimized
// offset value with the divider size and any system insets in that direction.
@@ -240,7 +244,7 @@
outBounds.set(0, mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top,
displayWidth, displayHeight);
} else {
- // In landscape also inset the left/right side with the statusbar height to match the
+ // In landscape also inset the left/right side with the status bar height to match the
// minimized size height in portrait mode.
final int primaryTaskWidth = mTaskHeightInMinimizedMode + dividerSize + mTmpRect.top;
int left = mTmpRect.left;
@@ -278,16 +282,16 @@
: mDisplayContent.mBaseDisplayHeight;
final DisplayCutout displayCutout =
mDisplayContent.calculateDisplayCutoutForRotation(rotation).getDisplayCutout();
- mService.mPolicy.getStableInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
+ final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
+ displayPolicy.getStableInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
config.unset();
config.orientation = (dw <= dh) ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
- final int displayId = mDisplayContent.getDisplayId();
- final int appWidth = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation,
- baseConfig.uiMode, displayId, displayCutout);
- final int appHeight = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
- baseConfig.uiMode, displayId, displayCutout);
- mService.mPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
+ final int appWidth = displayPolicy.getNonDecorDisplayWidth(dw, dh, rotation,
+ baseConfig.uiMode, displayCutout);
+ final int appHeight = displayPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
+ baseConfig.uiMode, displayCutout);
+ displayPolicy.getNonDecorInsetsLw(rotation, dw, dh, displayCutout, mTmpRect);
final int leftInset = mTmpRect.left;
final int topInset = mTmpRect.top;
@@ -295,10 +299,10 @@
leftInset + appWidth /*right*/, topInset + appHeight /*bottom*/);
final float density = mDisplayContent.getDisplayMetrics().density;
- config.screenWidthDp = (int) (mService.mPolicy.getConfigDisplayWidth(dw, dh,
- rotation, baseConfig.uiMode, displayId, displayCutout) / density);
- config.screenHeightDp = (int) (mService.mPolicy.getConfigDisplayHeight(dw, dh,
- rotation, baseConfig.uiMode, displayId, displayCutout) / density);
+ config.screenWidthDp = (int) (displayPolicy.getConfigDisplayWidth(dw, dh, rotation,
+ baseConfig.uiMode, displayCutout) / density);
+ config.screenHeightDp = (int) (displayPolicy.getConfigDisplayHeight(dw, dh, rotation,
+ baseConfig.uiMode, displayCutout) / density);
final Context rotationContext = mService.mContext.createConfigurationContext(config);
mSnapAlgorithmForRotation[rotation] = new DividerSnapAlgorithm(
rotationContext.getResources(), dw, dh, getContentWidth(),
@@ -464,8 +468,32 @@
* @return true if the side provided is valid
*/
boolean canPrimaryStackDockTo(int dockSide, Rect parentRect, int rotation) {
- return mService.mPolicy.isDockSideAllowed(dockSide, mOriginalDockedSide,
- parentRect.width(), parentRect.height(), rotation);
+ final DisplayPolicy policy = mDisplayContent.getDisplayPolicy();
+ return isDockSideAllowed(dockSide, mOriginalDockedSide,
+ policy.navigationBarPosition(parentRect.width(), parentRect.height(), rotation),
+ policy.navigationBarCanMove());
+ }
+
+ @VisibleForTesting
+ static boolean isDockSideAllowed(int dockSide, int originalDockSide, int navBarPosition,
+ boolean navigationBarCanMove) {
+ if (dockSide == DOCKED_TOP) {
+ return true;
+ }
+
+ if (navigationBarCanMove) {
+ // Only allow the dockside opposite to the nav bar position in landscape
+ return dockSide == DOCKED_LEFT && navBarPosition == NAV_BAR_RIGHT
+ || dockSide == DOCKED_RIGHT && navBarPosition == NAV_BAR_LEFT;
+ }
+
+ // Side is the same as original side
+ if (dockSide == originalDockSide) {
+ return true;
+ }
+
+ // Only if original docked side was top in portrait will allow left for landscape
+ return dockSide == DOCKED_LEFT && originalDockSide == DOCKED_TOP;
}
void notifyDockedStackExistsChanged(boolean exists) {
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
similarity index 81%
rename from services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
rename to services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index 4aa2446..3d20501 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package com.android.server.policy;
+package com.android.server.wm;
import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.view.Display.DEFAULT_DISPLAY;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
@@ -32,16 +33,14 @@
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.service.vr.IVrManager;
-import android.service.vr.IVrStateCallbacks;
import android.util.DisplayMetrics;
import android.util.Slog;
+import android.view.Display;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -55,7 +54,6 @@
import android.widget.FrameLayout;
import com.android.internal.R;
-import com.android.server.vr.VrManagerService;
/**
* Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden
@@ -67,30 +65,34 @@
private static final boolean DEBUG_SHOW_EVERY_TIME = false; // super annoying, use with caution
private static final String CONFIRMED = "confirmed";
+ private static boolean sConfirmed;
+
private final Context mContext;
private final H mHandler;
private final long mShowDelayMs;
private final long mPanicThresholdMs;
private final IBinder mWindowToken = new Binder();
- private boolean mConfirmed;
private ClingWindowView mClingWindow;
private long mPanicTime;
private WindowManager mWindowManager;
- private int mCurrentUserId;
// Local copy of vr mode enabled state, to avoid calling into VrManager with
// the lock held.
- boolean mVrModeEnabled = false;
+ private boolean mVrModeEnabled;
private int mLockTaskState = LOCK_TASK_MODE_NONE;
- public ImmersiveModeConfirmation(Context context) {
- mContext = ActivityThread.currentActivityThread().getSystemUiContext();
- mHandler = new H();
+ ImmersiveModeConfirmation(Context context, Looper looper, boolean vrModeEnabled) {
+ final Display display = context.getDisplay();
+ final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
+ mContext = display.getDisplayId() == DEFAULT_DISPLAY
+ ? uiContext : uiContext.createDisplayContext(display);
+ mHandler = new H(looper);
mShowDelayMs = getNavBarExitDuration() * 3;
mPanicThresholdMs = context.getResources()
.getInteger(R.integer.config_immersive_mode_confirmation_panic);
mWindowManager = (WindowManager)
mContext.getSystemService(Context.WINDOW_SERVICE);
+ mVrModeEnabled = vrModeEnabled;
}
private long getNavBarExitDuration() {
@@ -98,57 +100,46 @@
return exit != null ? exit.getDuration() : 0;
}
- public void loadSetting(int currentUserId) {
- mConfirmed = false;
- mCurrentUserId = currentUserId;
- if (DEBUG) Slog.d(TAG, String.format("loadSetting() mCurrentUserId=%d", mCurrentUserId));
+ static boolean loadSetting(int currentUserId, Context context) {
+ final boolean wasConfirmed = sConfirmed;
+ sConfirmed = false;
+ if (DEBUG) Slog.d(TAG, String.format("loadSetting() currentUserId=%d", currentUserId));
String value = null;
try {
- value = Settings.Secure.getStringForUser(mContext.getContentResolver(),
+ value = Settings.Secure.getStringForUser(context.getContentResolver(),
Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
UserHandle.USER_CURRENT);
- mConfirmed = CONFIRMED.equals(value);
- if (DEBUG) Slog.d(TAG, "Loaded mConfirmed=" + mConfirmed);
+ sConfirmed = CONFIRMED.equals(value);
+ if (DEBUG) Slog.d(TAG, "Loaded sConfirmed=" + sConfirmed);
} catch (Throwable t) {
Slog.w(TAG, "Error loading confirmations, value=" + value, t);
}
+ return sConfirmed != wasConfirmed;
}
- private void saveSetting() {
+ private static void saveSetting(Context context) {
if (DEBUG) Slog.d(TAG, "saveSetting()");
try {
- final String value = mConfirmed ? CONFIRMED : null;
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ final String value = sConfirmed ? CONFIRMED : null;
+ Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS,
value,
UserHandle.USER_CURRENT);
if (DEBUG) Slog.d(TAG, "Saved value=" + value);
} catch (Throwable t) {
- Slog.w(TAG, "Error saving confirmations, mConfirmed=" + mConfirmed, t);
+ Slog.w(TAG, "Error saving confirmations, sConfirmed=" + sConfirmed, t);
}
}
- void systemReady() {
- IVrManager vrManager = IVrManager.Stub.asInterface(
- ServiceManager.getService(Context.VR_SERVICE));
- if (vrManager != null) {
- try {
- vrManager.registerListener(mVrStateCallbacks);
- mVrModeEnabled = vrManager.getVrModeState();
- } catch (RemoteException re) {
- }
- }
- }
-
- public void immersiveModeChangedLw(String pkg, boolean isImmersiveMode,
+ void immersiveModeChangedLw(String pkg, boolean isImmersiveMode,
boolean userSetupComplete, boolean navBarEmpty) {
mHandler.removeMessages(H.SHOW);
if (isImmersiveMode) {
final boolean disabled = PolicyControl.disableImmersiveConfirmation(pkg);
- if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s mConfirmed=%s",
- disabled, mConfirmed));
+ if (DEBUG) Slog.d(TAG, String.format("immersiveModeChanged() disabled=%s sConfirmed=%s",
+ disabled, sConfirmed));
if (!disabled
- && (DEBUG_SHOW_EVERY_TIME || !mConfirmed)
+ && (DEBUG_SHOW_EVERY_TIME || !sConfirmed)
&& userSetupComplete
&& !mVrModeEnabled
&& !navBarEmpty
@@ -161,7 +152,7 @@
}
}
- public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode,
+ boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode,
boolean navBarEmpty) {
if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
// turning the screen back on within the panic threshold
@@ -176,7 +167,7 @@
return false;
}
- public void confirmCurrentPrompt() {
+ void confirmCurrentPrompt() {
if (mClingWindow != null) {
if (DEBUG) Slog.d(TAG, "confirmCurrentPrompt()");
mHandler.post(mConfirm);
@@ -191,16 +182,14 @@
}
}
- public WindowManager.LayoutParams getClingWindowLayoutParams() {
+ private WindowManager.LayoutParams getClingWindowLayoutParams() {
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
- 0
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- ,
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
lp.setTitle("ImmersiveModeConfirmation");
@@ -209,7 +198,7 @@
return lp;
}
- public FrameLayout.LayoutParams getBubbleLayoutParams() {
+ private FrameLayout.LayoutParams getBubbleLayoutParams() {
return new FrameLayout.LayoutParams(
mContext.getResources().getDimensionPixelSize(
R.dimen.immersive_mode_cling_width),
@@ -220,7 +209,7 @@
/**
* @return the window token that's used by all ImmersiveModeConfirmation windows.
*/
- public IBinder getWindowToken() {
+ IBinder getWindowToken() {
return mWindowToken;
}
@@ -272,7 +261,7 @@
}
};
- public ClingWindowView(Context context, Runnable confirm) {
+ ClingWindowView(Context context, Runnable confirm) {
super(context);
mConfirm = confirm;
setBackground(mColor);
@@ -295,7 +284,7 @@
mClingLayout = (ViewGroup)
View.inflate(getContext(), R.layout.immersive_mode_cling, null);
- final Button ok = (Button) mClingLayout.findViewById(R.id.ok);
+ final Button ok = mClingLayout.findViewById(R.id.ok);
ok.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@@ -359,8 +348,7 @@
// we will be hiding the nav bar, so layout as if it's already hidden
mClingWindow.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
// show the confirmation
WindowManager.LayoutParams lp = getClingWindowLayoutParams();
@@ -371,9 +359,9 @@
@Override
public void run() {
if (DEBUG) Slog.d(TAG, "mConfirm.run()");
- if (!mConfirmed) {
- mConfirmed = true;
- saveSetting();
+ if (!sConfirmed) {
+ sConfirmed = true;
+ saveSetting(mContext);
}
handleHide();
}
@@ -383,6 +371,10 @@
private static final int SHOW = 1;
private static final int HIDE = 2;
+ H(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
switch(msg.what) {
@@ -396,16 +388,13 @@
}
}
- private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
- @Override
- public void onVrStateChanged(boolean enabled) throws RemoteException {
- mVrModeEnabled = enabled;
- if (mVrModeEnabled) {
- mHandler.removeMessages(H.SHOW);
- mHandler.sendEmptyMessage(H.HIDE);
- }
+ void onVrStateChangedLw(boolean enabled) {
+ mVrModeEnabled = enabled;
+ if (mVrModeEnabled) {
+ mHandler.removeMessages(H.SHOW);
+ mHandler.sendEmptyMessage(H.HIDE);
}
- };
+ }
void onLockTaskModeChangedLw(int lockTaskState) {
mLockTaskState = lockTaskState;
diff --git a/services/core/java/com/android/server/policy/NavigationBarExperiments.java b/services/core/java/com/android/server/wm/NavigationBarExperiments.java
similarity index 96%
rename from services/core/java/com/android/server/policy/NavigationBarExperiments.java
rename to services/core/java/com/android/server/wm/NavigationBarExperiments.java
index 06772e3..b74fb45 100644
--- a/services/core/java/com/android/server/policy/NavigationBarExperiments.java
+++ b/services/core/java/com/android/server/wm/NavigationBarExperiments.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.policy;
+package com.android.server.wm;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -25,9 +25,6 @@
import android.content.Context;
import android.graphics.Rect;
-import com.android.server.policy.WindowManagerPolicy.WindowState;
-import com.android.server.wm.WindowFrames;
-
/**
* This class acts as a proxy for Navigation Bar experiments enabled with custom overlays
* {@see OverlayManagerService}. By default with no overlays, this class will essentially do nothing
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index d21f67d..ba23258 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -514,8 +514,9 @@
*/
private void getInsetBounds(Rect outRect) {
synchronized (mService.mGlobalLock) {
- mService.mPolicy.getStableInsetsLw(mDisplayInfo.rotation, mDisplayInfo.logicalWidth,
- mDisplayInfo.logicalHeight, mDisplayInfo.displayCutout, mTmpInsets);
+ mDisplayContent.getDisplayPolicy().getStableInsetsLw(mDisplayInfo.rotation,
+ mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
+ mDisplayInfo.displayCutout, mTmpInsets);
outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, mTmpInsets.top + mScreenEdgeInsets.y,
mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x,
mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y);
diff --git a/services/core/java/com/android/server/policy/PolicyControl.java b/services/core/java/com/android/server/wm/PolicyControl.java
similarity index 92%
rename from services/core/java/com/android/server/policy/PolicyControl.java
rename to services/core/java/com/android/server/wm/PolicyControl.java
index 48e72bc..4c8ce9e 100644
--- a/services/core/java/com/android/server/policy/PolicyControl.java
+++ b/services/core/java/com/android/server/wm/PolicyControl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.policy;
+package com.android.server.wm;
import android.app.ActivityManager;
import android.content.Context;
@@ -26,8 +26,6 @@
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
-import com.android.server.policy.WindowManagerPolicy.WindowState;
-
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -49,9 +47,9 @@
* Separate multiple name-value pairs with ':'
* e.g. "immersive.status=apps:immersive.preconfirms=*"
*/
-public class PolicyControl {
- private static String TAG = "PolicyControl";
- private static boolean DEBUG = false;
+class PolicyControl {
+ private static final String TAG = "PolicyControl";
+ private static final boolean DEBUG = false;
private static final String NAME_IMMERSIVE_FULL = "immersive.full";
private static final String NAME_IMMERSIVE_STATUS = "immersive.status";
@@ -63,7 +61,7 @@
private static Filter sImmersiveStatusFilter;
private static Filter sImmersiveNavigationFilter;
- public static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
+ static int getSystemUiVisibility(WindowState win, LayoutParams attrs) {
attrs = attrs != null ? attrs : win.getAttrs();
int vis = win != null ? win.getSystemUiVisibility()
: (attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility);
@@ -84,7 +82,7 @@
return vis;
}
- public static int getWindowFlags(WindowState win, LayoutParams attrs) {
+ static int getWindowFlags(WindowState win, LayoutParams attrs) {
attrs = attrs != null ? attrs : win.getAttrs();
int flags = attrs.flags;
if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
@@ -98,7 +96,7 @@
return flags;
}
- public static int adjustClearableFlags(WindowState win, int clearableFlags) {
+ static int adjustClearableFlags(WindowState win, int clearableFlags) {
final LayoutParams attrs = win != null ? win.getAttrs() : null;
if (sImmersiveStatusFilter != null && sImmersiveStatusFilter.matches(attrs)) {
clearableFlags &= ~View.SYSTEM_UI_FLAG_FULLSCREEN;
@@ -106,28 +104,32 @@
return clearableFlags;
}
- public static boolean disableImmersiveConfirmation(String pkg) {
+ static boolean disableImmersiveConfirmation(String pkg) {
return (sImmersivePreconfirmationsFilter != null
&& sImmersivePreconfirmationsFilter.matches(pkg))
|| ActivityManager.isRunningInTestHarness();
}
- public static void reloadFromSetting(Context context) {
+ static boolean reloadFromSetting(Context context) {
if (DEBUG) Slog.d(TAG, "reloadFromSetting()");
String value = null;
try {
value = Settings.Global.getStringForUser(context.getContentResolver(),
Settings.Global.POLICY_CONTROL,
UserHandle.USER_CURRENT);
- if (sSettingValue != null && sSettingValue.equals(value)) return;
+ if (sSettingValue == value || sSettingValue != null && sSettingValue.equals(value)) {
+ return false;
+ }
setFilters(value);
sSettingValue = value;
} catch (Throwable t) {
Slog.w(TAG, "Error loading policy control, value=" + value, t);
+ return false;
}
+ return true;
}
- public static void dump(String prefix, PrintWriter pw) {
+ static void dump(String prefix, PrintWriter pw) {
dump("sImmersiveStatusFilter", sImmersiveStatusFilter, prefix, pw);
dump("sImmersiveNavigationFilter", sImmersiveNavigationFilter, prefix, pw);
dump("sImmersivePreconfirmationsFilter", sImmersivePreconfirmationsFilter, prefix, pw);
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 72e3562..b483fd3 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -120,13 +120,10 @@
// events.
int mTopFocusedDisplayId = INVALID_DISPLAY;
- // Only a seperate transaction until we seperate the apply surface changes
+ // Only a separate transaction until we separate the apply surface changes
// transaction from the global transaction.
private final SurfaceControl.Transaction mDisplayTransaction = new SurfaceControl.Transaction();
- private final Consumer<DisplayContent> mDisplayContentConfigChangesConsumer =
- mService.mPolicy::onConfigurationChanged;
-
private final Consumer<WindowState> mCloseSystemDialogsConsumer = w -> {
if (w.mHasSurface) {
try {
@@ -362,8 +359,6 @@
public void onConfigurationChanged(Configuration newParentConfig) {
prepareFreezingTaskBounds();
super.onConfigurationChanged(newParentConfig);
-
- forAllDisplays(mDisplayContentConfigChangesConsumer);
}
private void prepareFreezingTaskBounds() {
@@ -1052,6 +1047,12 @@
}
}
+ void forAllDisplayPolicies(Consumer<DisplayPolicy> callback) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ callback.accept(mChildren.get(i).getDisplayPolicy());
+ }
+ }
+
/**
* Get current topmost focused IME window in system.
* Will look on all displays in current Z-order.
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index baeedbc..35264a2 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -261,11 +261,12 @@
final DisplayContent displayContent = stack.getDisplayContent();
final DisplayInfo di = displayContent.getDisplayInfo();
final DisplayCutout displayCutout = di.displayCutout;
+ final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
// Get the insets and display bounds
- mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
+ displayPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
displayCutout, mTmpStableInsets);
- mService.mPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
+ displayPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
displayCutout, mTmpNonDecorInsets);
mTmpDisplayBounds.set(0, 0, di.logicalWidth, di.logicalHeight);
diff --git a/services/core/java/com/android/server/wm/StatusBarController.java b/services/core/java/com/android/server/wm/StatusBarController.java
new file mode 100644
index 0000000..b4de75b
--- /dev/null
+++ b/services/core/java/com/android/server/wm/StatusBarController.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.MATCH_PARENT;
+
+import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
+
+import android.app.StatusBarManager;
+import android.os.IBinder;
+import android.view.View;
+
+import com.android.server.statusbar.StatusBarManagerInternal;
+
+/**
+ * Implements status bar specific behavior.
+ */
+public class StatusBarController extends BarController {
+
+ private final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
+
+ private Runnable mAppTransitionPending = () -> {
+ StatusBarManagerInternal statusBar = getStatusBarInternal();
+ if (statusBar != null && mWin != null) {
+ statusBar.appTransitionPending(mWin.getDisplayId());
+ }
+ };
+
+ private Runnable mAppTransitionCancelled = () -> {
+ StatusBarManagerInternal statusBar = getStatusBarInternal();
+ if (statusBar != null && mWin != null) {
+ statusBar.appTransitionCancelled(mWin.getDisplayId());
+ }
+ };
+
+ private Runnable mAppTransitionFinished = () -> {
+ StatusBarManagerInternal statusBar = getStatusBarInternal();
+ if (statusBar != null && mWin != null) {
+ statusBar.appTransitionFinished(mWin.getDisplayId());
+ }
+ };
+
+ @Override
+ public void onAppTransitionPendingLocked() {
+ mHandler.post(mAppTransitionPending);
+ }
+
+ @Override
+ public int onAppTransitionStartingLocked(int transit, IBinder openToken,
+ IBinder closeToken, long duration, long statusBarAnimationStartTime,
+ long statusBarAnimationDuration) {
+ mHandler.post(() -> {
+ StatusBarManagerInternal statusBar = getStatusBarInternal();
+ if (statusBar != null && mWin != null) {
+ statusBar.appTransitionStarting(mWin.getDisplayId(),
+ statusBarAnimationStartTime, statusBarAnimationDuration);
+ }
+ });
+ return 0;
+ }
+
+ @Override
+ public void onAppTransitionCancelledLocked(int transit) {
+ mHandler.post(mAppTransitionCancelled);
+ }
+
+ @Override
+ public void onAppTransitionFinishedLocked(IBinder token) {
+ mHandler.post(mAppTransitionFinished);
+ }
+ };
+
+ StatusBarController() {
+ super("StatusBar",
+ View.STATUS_BAR_TRANSIENT,
+ View.STATUS_BAR_UNHIDE,
+ View.STATUS_BAR_TRANSLUCENT,
+ StatusBarManager.WINDOW_STATUS_BAR,
+ FLAG_TRANSLUCENT_STATUS,
+ View.STATUS_BAR_TRANSPARENT);
+ }
+
+ void setTopAppHidesStatusBar(boolean hidesStatusBar) {
+ StatusBarManagerInternal statusBar = getStatusBarInternal();
+ if (statusBar != null) {
+ statusBar.setTopAppHidesStatusBar(hidesStatusBar);
+ }
+ }
+
+ @Override
+ protected boolean skipAnimation() {
+ return mWin.getAttrs().height == MATCH_PARENT;
+ }
+
+ AppTransitionListener getAppTransitionListener() {
+ return mAppTransitionListener;
+ }
+}
diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
similarity index 93%
rename from services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
rename to services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
index d3cc8ef..bdb76c2 100644
--- a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/SystemGesturesPointerEventListener.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package com.android.server.policy;
+package com.android.server.wm;
import android.content.Context;
import android.os.Handler;
-import android.os.Looper;
import android.os.SystemClock;
import android.util.Slog;
import android.view.GestureDetector;
@@ -27,11 +26,11 @@
import android.view.WindowManagerPolicyConstants.PointerEventListener;
import android.widget.OverScroller;
-/*
+/**
* Listens for system-wide input gestures, firing callbacks when detected.
* @hide
*/
-public class SystemGesturesPointerEventListener implements PointerEventListener {
+class SystemGesturesPointerEventListener implements PointerEventListener {
private static final String TAG = "SystemGestures";
private static final boolean DEBUG = false;
private static final long SWIPE_TIMEOUT_MS = 500;
@@ -46,6 +45,7 @@
private static final int SWIPE_FROM_LEFT = 4;
private final Context mContext;
+ private final Handler mHandler;
private final int mSwipeStartThreshold;
private final int mSwipeDistanceThreshold;
private final Callbacks mCallbacks;
@@ -55,7 +55,6 @@
private final long[] mDownTime = new long[MAX_TRACKED_POINTERS];
private GestureDetector mGestureDetector;
- private OverScroller mOverscroller;
int screenHeight;
int screenWidth;
@@ -65,8 +64,9 @@
private boolean mMouseHoveringAtEdge;
private long mLastFlingTime;
- public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
+ SystemGesturesPointerEventListener(Context context, Handler handler, Callbacks callbacks) {
mContext = context;
+ mHandler = handler;
mCallbacks = checkNull("callbacks", callbacks);
mSwipeStartThreshold = checkNull("context", context).getResources()
.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
@@ -83,9 +83,7 @@
}
public void systemReady() {
- Handler h = new Handler(Looper.myLooper());
- mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), h);
- mOverscroller = new OverScroller(mContext);
+ mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), mHandler);
}
@Override
@@ -163,14 +161,14 @@
private void captureDown(MotionEvent event, int pointerIndex) {
final int pointerId = event.getPointerId(pointerIndex);
final int i = findIndex(pointerId);
- if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
- " down pointerIndex=" + pointerIndex + " trackingIndex=" + i);
+ if (DEBUG) Slog.d(TAG, "pointer " + pointerId
+ + " down pointerIndex=" + pointerIndex + " trackingIndex=" + i);
if (i != UNTRACKED_POINTER) {
mDownX[i] = event.getX(pointerIndex);
mDownY[i] = event.getY(pointerIndex);
mDownTime[i] = event.getEventTime();
- if (DEBUG) Slog.d(TAG, "pointer " + pointerId +
- " down x=" + mDownX[i] + " y=" + mDownY[i]);
+ if (DEBUG) Slog.d(TAG, "pointer " + pointerId
+ + " down x=" + mDownX[i] + " y=" + mDownY[i]);
}
}
@@ -242,6 +240,13 @@
}
private final class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener {
+
+ private OverScroller mOverscroller;
+
+ FlingGestureDetector() {
+ mOverscroller = new OverScroller(mContext);
+ }
+
@Override
public boolean onSingleTapUp(MotionEvent e) {
if (!mOverscroller.isFinished()) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 15de1ec..64f4ba5 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -521,7 +521,7 @@
// Snap the position to a target.
final int rotation = parentConfig.windowConfiguration.getRotation();
final int orientation = parentConfig.orientation;
- mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight,
+ mDisplayContent.getDisplayPolicy().getStableInsetsLw(rotation, displayWidth, displayHeight,
displayCutout, outBounds);
final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
mService.mContext.getResources(), displayWidth, displayHeight,
@@ -867,7 +867,8 @@
// and its bounds can be adjusted after that. The bounds of all other stacks are
// adjusted to occupy whatever screen space the docked stack isn't occupying.
final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout;
- mService.mPolicy.getStableInsetsLw(parentConfig.windowConfiguration.getRotation(),
+ mDisplayContent.getDisplayPolicy().getStableInsetsLw(
+ parentConfig.windowConfiguration.getRotation(),
displayRect.width(), displayRect.height(), displayCutout, mTmpRect2);
final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
displayRect.width(),
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index b096bf2..e83b863 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -392,11 +392,6 @@
public abstract boolean isStackVisible(int windowingMode);
/**
- * @return True if and only if the docked divider is currently in resize mode.
- */
- public abstract boolean isDockedDividerResizing();
-
- /**
* Requests the window manager to resend the windows for accessibility.
*/
public abstract void computeWindowsForAccessibility();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8d5cd78..39a8465 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -171,6 +171,8 @@
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
+import android.service.vr.IVrManager;
+import android.service.vr.IVrStateCallbacks;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -231,6 +233,7 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.LatencyTracker;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.view.WindowManagerPolicyThread;
import com.android.server.AnimationThread;
import com.android.server.DisplayThread;
@@ -373,6 +376,18 @@
boolean mKeyguardOrAodShowingOnDefaultDisplay;
// VR Vr2d Display Id.
int mVr2dDisplayId = INVALID_DISPLAY;
+ boolean mVrModeEnabled = false;
+
+ private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
+ @Override
+ public void onVrStateChanged(boolean enabled) {
+ synchronized (mGlobalLock) {
+ mVrModeEnabled = enabled;
+ mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
+ DisplayPolicy::onVrStateChangedLw, PooledLambda.__(), enabled));
+ }
+ }
+ };
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -528,6 +543,7 @@
boolean mForceDisplayEnabled = false;
boolean mShowingBootMessages = false;
boolean mBootAnimationStopped = false;
+ boolean mSystemReady = false;
// Following variables are for debugging screen wakelock only.
WindowState mLastWakeLockHoldingWindow = null;
@@ -579,9 +595,6 @@
final WallpaperVisibilityListeners mWallpaperVisibilityListeners =
new WallpaperVisibilityListeners();
- int mSystemDecorLayer = 0;
- final Rect mScreenRect = new Rect();
-
boolean mDisplayFrozen = false;
long mDisplayFreezeTime = 0;
int mLastDisplayFreezeDuration = 0;
@@ -597,11 +610,6 @@
boolean mClientFreezingScreen = false;
int mAppsFreezingScreen = 0;
- // Last systemUiVisibility we received from status bar.
- int mLastStatusBarVisibility = 0;
- // Last systemUiVisibility we dispatched to windows.
- int mLastDispatchedSystemUiVisibility = 0;
-
// State while inside of layoutAndPlaceSurfacesLocked().
boolean mFocusMayChange;
@@ -649,6 +657,10 @@
Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE);
private final Uri mAnimationDurationScaleUri =
Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE);
+ private final Uri mImmersiveModeConfirmationsUri =
+ Settings.Secure.getUriFor(Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS);
+ private final Uri mPolicyControlUri =
+ Settings.Global.getUriFor(Settings.Global.POLICY_CONTROL);
public SettingsObserver() {
super(new Handler());
@@ -661,6 +673,10 @@
UserHandle.USER_ALL);
resolver.registerContentObserver(mAnimationDurationScaleUri, false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(mImmersiveModeConfirmationsUri, false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(mPolicyControlUri, false, this,
+ UserHandle.USER_ALL);
}
@Override
@@ -669,23 +685,40 @@
return;
}
+ if (mImmersiveModeConfirmationsUri.equals(uri) || mPolicyControlUri.equals(uri)) {
+ updateSystemUiSettings();
+ return;
+ }
+
if (mDisplayInversionEnabledUri.equals(uri)) {
updateCircularDisplayMaskIfNeeded();
+ return;
+ }
+
+ @UpdateAnimationScaleMode
+ final int mode;
+ if (mWindowAnimationScaleUri.equals(uri)) {
+ mode = WINDOW_ANIMATION_SCALE;
+ } else if (mTransitionAnimationScaleUri.equals(uri)) {
+ mode = TRANSITION_ANIMATION_SCALE;
+ } else if (mAnimationDurationScaleUri.equals(uri)) {
+ mode = ANIMATION_DURATION_SCALE;
} else {
- @UpdateAnimationScaleMode
- final int mode;
- if (mWindowAnimationScaleUri.equals(uri)) {
- mode = WINDOW_ANIMATION_SCALE;
- } else if (mTransitionAnimationScaleUri.equals(uri)) {
- mode = TRANSITION_ANIMATION_SCALE;
- } else if (mAnimationDurationScaleUri.equals(uri)) {
- mode = ANIMATION_DURATION_SCALE;
- } else {
- // Ignoring unrecognized content changes
- return;
- }
- Message m = mH.obtainMessage(H.UPDATE_ANIMATION_SCALE, mode, 0);
- mH.sendMessage(m);
+ // Ignoring unrecognized content changes
+ return;
+ }
+ Message m = mH.obtainMessage(H.UPDATE_ANIMATION_SCALE, mode, 0);
+ mH.sendMessage(m);
+ }
+
+ void updateSystemUiSettings() {
+ boolean changed;
+ synchronized (mWindowMap) {
+ changed = ImmersiveModeConfirmation.loadSetting(mCurrentUserId, mContext)
+ || PolicyControl.reloadFromSetting(mContext);
+ }
+ if (changed) {
+ updateRotation(false /* alwaysSendConfiguration */, false /* forceRelayout */);
}
}
}
@@ -1286,10 +1319,11 @@
final boolean hasStatusBarServicePermission =
mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
== PackageManager.PERMISSION_GRANTED;
- mPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);
+ final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
+ displayPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
- res = mPolicy.prepareAddWindowLw(win, attrs);
+ res = displayPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
@@ -1422,9 +1456,8 @@
taskBounds = null;
floatingStack = false;
}
- if (mPolicy.getLayoutHintLw(win.mAttrs, taskBounds, displayFrames, floatingStack,
- outFrame, outContentInsets, outStableInsets, outOutsets,
- outDisplayCutout)) {
+ if (displayPolicy.getLayoutHintLw(win.mAttrs, taskBounds, displayFrames, floatingStack,
+ outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout)) {
res |= WindowManagerGlobal.ADD_FLAG_ALWAYS_CONSUME_NAV_BAR;
}
@@ -1842,6 +1875,8 @@
return 0;
}
displayId = win.getDisplayId();
+ final DisplayContent displayContent = win.getDisplayContent();
+ final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy();
WindowStateAnimator winAnimator = win.mWinAnimator;
if (viewVisibility != View.GONE) {
@@ -1857,7 +1892,7 @@
int attrChanges = 0;
int flagChanges = 0;
if (attrs != null) {
- mPolicy.adjustWindowParamsLw(win, attrs, hasStatusBarServicePermission);
+ displayPolicy.adjustWindowParamsLw(win, attrs, hasStatusBarServicePermission);
// if they don't have the permission, mask out the status bar bits
if (seq == win.mSeq) {
int systemUiVisibility = attrs.systemUiVisibility
@@ -1996,7 +2031,7 @@
try {
result = createSurfaceControl(outSurface, result, win, winAnimator);
} catch (Exception e) {
- win.getDisplayContent().getInputMonitor().updateInputWindowsLw(true /*force*/);
+ displayContent.getInputMonitor().updateInputWindowsLw(true /*force*/);
Slog.w(TAG_WM, "Exception thrown when creating surface for client "
+ client + " (" + win.mAttrs.getTitle() + ")",
@@ -2007,7 +2042,6 @@
if ((result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
focusMayChange = true;
}
- final DisplayContent displayContent = win.getDisplayContent();
if (win.mAttrs.type == TYPE_INPUT_METHOD
&& displayContent.mInputMethodWindow == null) {
displayContent.setInputMethodWindowLocked(win);
@@ -2052,35 +2086,34 @@
// updateFocusedWindowLocked() already assigned layers so we only need to
// reassign them at this point if the IM window state gets shuffled
boolean toBeDisplayed = (result & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0;
- final DisplayContent dc = win.getDisplayContent();
if (imMayMove) {
- dc.computeImeTarget(true /* updateImeTarget */);
+ displayContent.computeImeTarget(true /* updateImeTarget */);
if (toBeDisplayed) {
// Little hack here -- we -should- be able to rely on the function to return
// true if the IME has moved and needs its layer recomputed. However, if the IME
// was hidden and isn't actually moved in the list, its layer may be out of data
// so we make sure to recompute it.
- dc.assignWindowLayers(false /* setLayoutNeeded */);
+ displayContent.assignWindowLayers(false /* setLayoutNeeded */);
}
}
if (wallpaperMayMove) {
- win.getDisplayContent().pendingLayoutChanges |=
+ displayContent.pendingLayoutChanges |=
WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
}
if (win.mAppToken != null) {
- dc.mUnknownAppVisibilityController.notifyRelayouted(win.mAppToken);
+ displayContent.mUnknownAppVisibilityController.notifyRelayouted(win.mAppToken);
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
"relayoutWindow: updateOrientationFromAppTokens");
- configChanged = dc.updateOrientationFromAppTokens();
+ configChanged = displayContent.updateOrientationFromAppTokens();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
if (toBeDisplayed && win.mIsWallpaper) {
- DisplayInfo displayInfo = win.getDisplayContent().getDisplayInfo();
- dc.mWallpaperController.updateWallpaperOffset(
+ DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ displayContent.mWallpaperController.updateWallpaperOffset(
win, displayInfo.logicalWidth, displayInfo.logicalHeight, false);
}
if (win.mAppToken != null) {
@@ -2090,7 +2123,7 @@
winAnimator.mReportSurfaceResized = false;
result |= WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED;
}
- if (mPolicy.isNavBarForcedShownLw(win)) {
+ if (displayPolicy.isNavBarForcedShownLw(win)) {
result |= WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR;
}
if (!win.isGoneForLayoutLw()) {
@@ -2408,7 +2441,7 @@
mWaitingForConfig = true;
displayContent.setLayoutNeeded();
int anim[] = new int[2];
- mPolicy.selectRotationAnimationLw(anim);
+ displayContent.getDisplayPolicy().selectRotationAnimationLw(anim);
startFreezingDisplayLocked(anim[0], anim[1], displayContent);
config = new Configuration(mTempConfiguration);
@@ -2603,7 +2636,9 @@
}
}
- @Override
+ /**
+ * Notifies window manager that {@link DisplayPolicy#isShowingDreamLw} has changed.
+ */
public void notifyShowingDreamChanged() {
// TODO(multi-display): support show dream in multi-display.
notifyKeyguardFlagsChanged(null /* callback */, DEFAULT_DISPLAY);
@@ -2634,6 +2669,21 @@
mH.sendEmptyMessage(H.RECOMPUTE_FOCUS);
}
+ @Override
+ public void onPowerKeyDown(boolean isScreenOn) {
+ mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
+ DisplayPolicy::onPowerKeyDown, PooledLambda.__(), isScreenOn));
+ }
+
+ @Override
+ public void onUserSwitched() {
+ mSettingsObserver.updateSystemUiSettings();
+ synchronized (mWindowMap) {
+ // force a re-application of focused window sysui visibility on each display.
+ mRoot.forAllDisplayPolicies(DisplayPolicy::resetSystemUiVisibilityLw);
+ }
+ }
+
/**
* Starts deferring layout passes. Useful when doing multiple changes but to optimize
* performance, only one layout pass should be done. This can be called multiple times, and
@@ -2839,7 +2889,8 @@
public boolean isShowingDream() {
synchronized (mGlobalLock) {
- return mPolicy.isShowingDreamLw();
+ // TODO: fix this when dream can be shown on non-default display.
+ return getDefaultDisplayContentLocked().getDisplayPolicy().isShowingDreamLw();
}
}
@@ -3672,13 +3723,6 @@
}
@Override
- public WindowManagerPolicy.DisplayContentInfo getDefaultDisplayContentInfo() {
- synchronized (mGlobalLock) {
- return getDefaultDisplayContentLocked();
- }
- }
-
- @Override
public int getDefaultDisplayRotation() {
synchronized (mGlobalLock) {
return getDefaultDisplayContentLocked().getRotation();
@@ -4291,10 +4335,29 @@
}
public void systemReady() {
+ mSystemReady = true;
mPolicy.systemReady();
+ mRoot.forAllDisplayPolicies(DisplayPolicy::systemReady);
mTaskSnapshotController.systemReady();
mHasWideColorGamutSupport = queryWideColorGamutSupport();
mHasHdrSupport = queryHdrSupport();
+ UiThread.getHandler().post(mSettingsObserver::updateSystemUiSettings);
+ IVrManager vrManager = IVrManager.Stub.asInterface(
+ ServiceManager.getService(Context.VR_SERVICE));
+ if (vrManager != null) {
+ try {
+ final boolean vrModeEnabled = vrManager.getVrModeState();
+ synchronized (mGlobalLock) {
+ vrManager.registerListener(mVrStateCallbacks);
+ if (vrModeEnabled) {
+ mVrModeEnabled = vrModeEnabled;
+ mVrStateCallbacks.onVrStateChanged(vrModeEnabled);
+ }
+ }
+ } catch (RemoteException e) {
+ // Ignore, we cannot do anything if we failed to register VR mode listener
+ }
+ }
}
private static boolean queryWideColorGamutSupport() {
@@ -5382,7 +5445,8 @@
if (DEBUG_ORIENTATION) Slog.i(TAG_WM, "**** Dismissing screen rotation animation");
DisplayInfo displayInfo = displayContent.getDisplayInfo();
// Get rotation animation again, with new top window
- if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, false)) {
+ if (!displayContent.getDisplayPolicy()
+ .validateRotationAnimationLw(mExitAnimId, mEnterAnimId, false)) {
mExitAnimId = mEnterAnimId = 0;
}
if (screenRotationAnimation.dismiss(mTransaction, MAX_ANIMATION_DURATION,
@@ -5522,7 +5586,7 @@
}
@Override
- public void statusBarVisibilityChanged(int visibility) {
+ public void statusBarVisibilityChanged(int displayId, int visibility) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Caller does not hold permission "
@@ -5530,9 +5594,12 @@
}
synchronized (mGlobalLock) {
- mLastStatusBarVisibility = visibility;
- visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
- updateStatusBarVisibilityLocked(visibility);
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent != null) {
+ displayContent.statusBarVisibilityChanged(visibility);
+ } else {
+ Slog.w(TAG, "statusBarVisibilityChanged with invalid displayId=" + displayId);
+ }
}
}
@@ -5548,49 +5615,36 @@
}
}
- // TODO(multidisplay): StatusBar on multiple screens?
- private boolean updateStatusBarVisibilityLocked(int visibility) {
- if (mLastDispatchedSystemUiVisibility == visibility) {
- return false;
- }
- final int globalDiff = (visibility ^ mLastDispatchedSystemUiVisibility)
- // We are only interested in differences of one of the
- // clearable flags...
- & View.SYSTEM_UI_CLEARABLE_FLAGS
- // ...if it has actually been cleared.
- & ~visibility;
-
- mLastDispatchedSystemUiVisibility = visibility;
- mInputManager.setSystemUiVisibility(visibility);
- getDefaultDisplayContentLocked().updateSystemUiVisibility(visibility, globalDiff);
- return true;
- }
-
+ // TODO: Make the callers use getNavBarPosition(int) only.
+ /**
+ * Used by SystemUI and shared SystemUI libraries.
+ * @see DisplayPolicy#getNavBarPosition()
+ */
@Override
- public void reevaluateStatusBarVisibility() {
- synchronized (mGlobalLock) {
- int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
- if (updateStatusBarVisibilityLocked(visibility)) {
- mWindowPlacerLocked.requestTraversal();
- }
- }
+ @WindowManagerPolicy.NavigationBarPosition
+ public int getNavBarPosition() {
+ return getNavBarPosition(Display.DEFAULT_DISPLAY);
}
/**
* Used by ActivityManager to determine where to position an app with aspect ratio shorter then
* the screen is.
- * @see WindowManagerPolicy#getNavBarPosition()
+ * @see DisplayPolicy#getNavBarPosition()
*/
- @Override
@WindowManagerPolicy.NavigationBarPosition
- public int getNavBarPosition() {
+ public int getNavBarPosition(int displayId) {
synchronized (mGlobalLock) {
// Perform layout if it was scheduled before to make sure that we get correct nav bar
// position when doing rotations.
- final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
- defaultDisplayContent.performLayout(false /* initial */,
+ final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
+ if (displayContent == null) {
+ Slog.w(TAG, "getNavBarPosition with invalid displayId=" + displayId
+ + " callers=" + Debug.getCallers(3));
+ return -1;
+ }
+ displayContent.performLayout(false /* initial */,
false /* updateInputWindows */);
- return mPolicy.getNavBarPosition();
+ return displayContent.getDisplayPolicy().getNavBarPosition();
}
}
@@ -5776,11 +5830,6 @@
}
}
- @Override
- public int getDockedDividerInsetsLw() {
- return getDefaultDisplayContentLocked().getDockedDividerController().getContentInsets();
- }
-
private void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
mPolicy.dump(" ", pw, args);
@@ -5969,12 +6018,6 @@
mTaskSnapshotController.dump(pw, " ");
if (dumpAll) {
- pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
- pw.print(" mScreenRect="); pw.println(mScreenRect.toShortString());
- if (mLastStatusBarVisibility != 0) {
- pw.print(" mLastStatusBarVisibility=0x");
- pw.println(Integer.toHexString(mLastStatusBarVisibility));
- }
final WindowState imeWindow = mRoot.getCurrentInputMethodWindow();
if (imeWindow != null) {
pw.print(" mInputMethodWindow="); pw.println(imeWindow);
@@ -6007,6 +6050,7 @@
pw.print(" mRecentsAnimationController="); pw.println(mRecentsAnimationController);
mRecentsAnimationController.dump(pw, " ");
}
+ PolicyControl.dump(" ", pw);
}
}
@@ -6270,7 +6314,7 @@
public void onOverlayChanged() {
synchronized (mGlobalLock) {
mRoot.forAllDisplays(displayContent -> {
- mPolicy.onOverlayChangedLw(displayContent);
+ displayContent.getDisplayPolicy().onOverlayChangedLw();
displayContent.updateDisplayInfo();
});
requestTraversal();
@@ -6500,7 +6544,7 @@
final DisplayContent dc = mRoot.getDisplayContent(displayId);
if (dc != null) {
final DisplayInfo di = dc.getDisplayInfo();
- mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
+ dc.getDisplayPolicy().getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
di.displayCutout, outInsets);
}
}
@@ -7102,13 +7146,6 @@
}
@Override
- public boolean isDockedDividerResizing() {
- synchronized (mGlobalLock) {
- return getDefaultDisplayContentLocked().getDockedDividerController().isResizing();
- }
- }
-
- @Override
public void computeWindowsForAccessibility() {
final AccessibilityController accessibilityController;
synchronized (mGlobalLock) {
@@ -7367,9 +7404,11 @@
* {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
* {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
*/
- public void onLockTaskStateChanged(int lockTaskState) {
+ void onLockTaskStateChanged(int lockTaskState) {
+ // TODO: pass in displayId to determine which display the lock task state changed
synchronized (mGlobalLock) {
- mPolicy.onLockTaskStateChangedLw(lockTaskState);
+ mRoot.forAllDisplayPolicies(PooledLambda.obtainConsumer(
+ DisplayPolicy::onLockTaskStateChangedLw, PooledLambda.__(), lockTaskState));
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a117cf3..567b583 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -179,6 +179,7 @@
import android.view.InputChannel;
import android.view.InputEvent;
import android.view.InputEventReceiver;
+import android.view.InputWindowHandle;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
@@ -191,7 +192,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
-import android.view.InputWindowHandle;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
import com.android.server.wm.utils.InsetUtils;
@@ -1800,7 +1800,7 @@
// also been registered in display.
dc.mTapExcludeProvidingWindows.remove(this);
}
- mPolicy.removeWindowLw(this);
+ dc.getDisplayPolicy().removeWindowLw(this);
disposeInputChannel();
@@ -2982,7 +2982,7 @@
mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
reportDraw, mergedConfiguration, getBackdropFrame(frame), forceRelayout,
- mPolicy.isNavBarForcedShownLw(this), displayId,
+ getDisplayContent().getDisplayPolicy().isNavBarForcedShownLw(this), displayId,
new DisplayCutout.ParcelableWrapper(displayCutout));
mDragResizingChangeReported = true;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 15ea5b5..e090cc5 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1343,7 +1343,7 @@
// is running.
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WSA#applyAnimationLocked");
if (mWin.mToken.okToAnimate()) {
- int anim = mPolicy.selectAnimationLw(mWin, transit);
+ int anim = mWin.getDisplayContent().getDisplayPolicy().selectAnimationLw(mWin, transit);
int attr = -1;
Animation a = null;
if (anim != 0) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
new file mode 100644
index 0000000..05912a5
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/AbUpdateInstaller.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.app.admin.DevicePolicyManager.InstallUpdateCallback;
+import android.app.admin.StartInstallingUpdateCallback;
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.os.UpdateEngine;
+import android.os.UpdateEngineCallback;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+/**
+ * Used for installing an update on <a href="https://source.android.com/devices/tech/ota/ab">AB
+ * devices.</a>
+ * <p>This logic is specific to GOTA and should be modified by OEMs using a different AB update
+ * system.</p>
+ */
+class AbUpdateInstaller extends UpdateInstaller {
+ private static final String PAYLOAD_BIN = "payload.bin";
+ private static final String PAYLOAD_PROPERTIES_TXT = "payload_properties.txt";
+ //https://en.wikipedia.org/wiki/Zip_(file_format)#Local_file_header
+ private static final int OFFSET_TO_FILE_NAME = 30;
+ // kDownloadStateInitializationError constant from system/update_engine/common/error_code.h.
+ private static final int DOWNLOAD_STATE_INITIALIZATION_ERROR = 20;
+ private long mSizeForUpdate;
+ private long mOffsetForUpdate;
+ private List<String> mProperties;
+ private Enumeration<? extends ZipEntry> mEntries;
+ private ZipFile mPackedUpdateFile;
+ private static final Map<Integer, Integer> errorCodesMap = buildErrorCodesMap();
+ private static final Map<Integer, String> errorStringsMap = buildErrorStringsMap();
+ public static final String UNKNOWN_ERROR = "Unknown error with error code = ";
+ private boolean mUpdateInstalled;
+
+ private static Map<Integer, Integer> buildErrorCodesMap() {
+ Map<Integer, Integer> map = new HashMap<>();
+ map.put(UpdateEngine.ErrorCodeConstants.ERROR, InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+ map.put(
+ DOWNLOAD_STATE_INITIALIZATION_ERROR,
+ InstallUpdateCallback.UPDATE_ERROR_INCORRECT_OS_VERSION);
+
+ // Error constants corresponding to errors related to bad update file.
+ map.put(
+ UpdateEngine.ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR,
+ InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+ map.put(
+ UpdateEngine.ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR,
+ InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+ map.put(
+ UpdateEngine.ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR,
+ InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+ map.put(
+ UpdateEngine.ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR,
+ InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID);
+
+ // Error constants corresponding to errors related to devices bad state.
+ map.put(
+ UpdateEngine.ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR,
+ InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+ map.put(
+ UpdateEngine.ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR,
+ InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+ map.put(
+ UpdateEngine.ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR,
+ InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+ map.put(
+ UpdateEngine.ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE,
+ InstallUpdateCallback.UPDATE_ERROR_UNKNOWN);
+
+ return map;
+ }
+
+ private static Map<Integer, String> buildErrorStringsMap() {
+ Map<Integer, String> map = new HashMap<>();
+ map.put(UpdateEngine.ErrorCodeConstants.ERROR, UNKNOWN_ERROR);
+ map.put(
+ DOWNLOAD_STATE_INITIALIZATION_ERROR,
+ "The delta update payload was targeted for another version or the source partition"
+ + "was modified after it was installed");
+ map.put(
+ UpdateEngine.ErrorCodeConstants.POST_INSTALL_RUNNER_ERROR,
+ "Failed to finish the configured postinstall works.");
+ map.put(
+ UpdateEngine.ErrorCodeConstants.INSTALL_DEVICE_OPEN_ERROR,
+ "Failed to open one of the partitions it tried to write to or read data from.");
+ map.put(
+ UpdateEngine.ErrorCodeConstants.PAYLOAD_MISMATCHED_TYPE_ERROR,
+ "Payload mismatch error.");
+ map.put(
+ UpdateEngine.ErrorCodeConstants.DOWNLOAD_TRANSFER_ERROR,
+ "Failed to read the payload data from the given URL.");
+ map.put(
+ UpdateEngine.ErrorCodeConstants.PAYLOAD_HASH_MISMATCH_ERROR, "Payload hash error.");
+ map.put(
+ UpdateEngine.ErrorCodeConstants.PAYLOAD_SIZE_MISMATCH_ERROR,
+ "Payload size mismatch error.");
+ map.put(
+ UpdateEngine.ErrorCodeConstants.DOWNLOAD_PAYLOAD_VERIFICATION_ERROR,
+ "Failed to verify the signature of the payload.");
+ map.put(
+ UpdateEngine.ErrorCodeConstants.UPDATED_BUT_NOT_ACTIVE,
+ "The payload has been successfully installed,"
+ + "but the active slot was not flipped.");
+ return map;
+ }
+
+ AbUpdateInstaller(Context context, ParcelFileDescriptor updateFileDescriptor,
+ StartInstallingUpdateCallback callback, DevicePolicyManagerService.Injector injector,
+ DevicePolicyConstants constants) {
+ super(context, updateFileDescriptor, callback, injector, constants);
+ mUpdateInstalled = false;
+ }
+
+ @Override
+ public void installUpdateInThread() {
+ if (mUpdateInstalled) {
+ throw new IllegalStateException("installUpdateInThread can be called only once.");
+ }
+ try {
+ setState();
+ applyPayload(Paths.get(mCopiedUpdateFile.getAbsolutePath()).toUri().toString());
+ } catch (ZipException e) {
+ Log.w(UpdateInstaller.TAG, e);
+ notifyCallbackOnError(
+ InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+ Log.getStackTraceString(e));
+ } catch (IOException e) {
+ Log.w(UpdateInstaller.TAG, e);
+ notifyCallbackOnError(
+ InstallUpdateCallback.UPDATE_ERROR_UNKNOWN, Log.getStackTraceString(e));
+ }
+ }
+
+ private void setState() throws IOException {
+ mUpdateInstalled = true;
+ mPackedUpdateFile = new ZipFile(mCopiedUpdateFile);
+ mProperties = new ArrayList<>();
+ mSizeForUpdate = -1;
+ mOffsetForUpdate = 0;
+ mEntries = mPackedUpdateFile.entries();
+ }
+
+ private UpdateEngine buildBoundUpdateEngine() {
+ UpdateEngine updateEngine = new UpdateEngine();
+ updateEngine.bind(new DelegatingUpdateEngineCallback(this, updateEngine));
+ return updateEngine;
+ }
+
+ private void applyPayload(String updatePath) throws IOException {
+ if (!updateStateForPayload()) {
+ return;
+ }
+ String[] headerKeyValuePairs = mProperties.stream().toArray(String[]::new);
+ if (mSizeForUpdate == -1) {
+ Log.w(UpdateInstaller.TAG, "Failed to find payload entry in the given package.");
+ notifyCallbackOnError(
+ InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+ "Failed to find payload entry in the given package.");
+ return;
+ }
+
+ UpdateEngine updateEngine = buildBoundUpdateEngine();
+ updateEngine.applyPayload(
+ updatePath, mOffsetForUpdate, mSizeForUpdate, headerKeyValuePairs);
+ }
+
+ private boolean updateStateForPayload() throws IOException {
+ long offset = 0;
+ while (mEntries.hasMoreElements()) {
+ ZipEntry entry = mEntries.nextElement();
+
+ String name = entry.getName();
+ offset += buildOffsetForEntry(entry, name);
+ if (entry.isDirectory()) {
+ offset -= entry.getCompressedSize();
+ continue;
+ }
+ if (PAYLOAD_BIN.equals(name)) {
+ if (entry.getMethod() != ZipEntry.STORED) {
+ Log.w(UpdateInstaller.TAG, "Invalid compression method.");
+ notifyCallbackOnError(
+ InstallUpdateCallback.UPDATE_ERROR_UPDATE_FILE_INVALID,
+ "Invalid compression method.");
+ return false;
+ }
+ mSizeForUpdate = entry.getCompressedSize();
+ mOffsetForUpdate = offset - entry.getCompressedSize();
+ } else if (PAYLOAD_PROPERTIES_TXT.equals(name)) {
+ updatePropertiesForEntry(entry);
+ }
+ }
+ return true;
+ }
+
+ private long buildOffsetForEntry(ZipEntry entry, String name) {
+ return OFFSET_TO_FILE_NAME + name.length() + entry.getCompressedSize()
+ + (entry.getExtra() == null ? 0 : entry.getExtra().length);
+ }
+
+ private void updatePropertiesForEntry(ZipEntry entry) throws IOException {
+ try (BufferedReader bufferedReader = new BufferedReader(
+ new InputStreamReader(mPackedUpdateFile.getInputStream(entry)))) {
+ String line;
+ /* Neither @line nor @mProperties are size constraint since there is a few properties
+ with limited size. */
+ while ((line = bufferedReader.readLine()) != null) {
+ mProperties.add(line);
+ }
+ }
+ }
+
+ private static class DelegatingUpdateEngineCallback extends UpdateEngineCallback {
+ private UpdateInstaller mUpdateInstaller;
+ private UpdateEngine mUpdateEngine;
+
+ DelegatingUpdateEngineCallback(
+ UpdateInstaller updateInstaller, UpdateEngine updateEngine) {
+ mUpdateInstaller = updateInstaller;
+ mUpdateEngine = updateEngine;
+ }
+
+ @Override
+ public void onStatusUpdate(int statusCode, float percentage) {
+ return;
+ }
+
+ @Override
+ public void onPayloadApplicationComplete(int errorCode) {
+ mUpdateEngine.unbind();
+ if (errorCode == UpdateEngine.ErrorCodeConstants.SUCCESS) {
+ mUpdateInstaller.notifyCallbackOnSuccess();
+ } else {
+ mUpdateInstaller.notifyCallbackOnError(
+ errorCodesMap.getOrDefault(
+ errorCode, InstallUpdateCallback.UPDATE_ERROR_UNKNOWN),
+ errorStringsMap.getOrDefault(errorCode, UNKNOWN_ERROR + errorCode));
+ }
+ }
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 5926bdd..6462d16 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -17,7 +17,9 @@
import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
+import android.app.admin.StartInstallingUpdateCallback;
import android.content.ComponentName;
+import android.os.ParcelFileDescriptor;
import com.android.server.SystemService;
@@ -91,4 +93,8 @@
@Override
public void grantDeviceIdsAccessToProfileOwner(ComponentName who, int userId) { }
+
+ @Override
+ public void installUpdateFromFile(ComponentName admin,
+ ParcelFileDescriptor updateFileDescriptor, StartInstallingUpdateCallback listener) {}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
index 71fea02..fd59b43 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyConstants.java
@@ -42,6 +42,12 @@
private static final String DAS_DIED_SERVICE_STABLE_CONNECTION_THRESHOLD_SEC_KEY =
"das_died_service_stable_connection_threshold_sec";
+ private static final String BATTERY_THRESHOLD_NOT_CHARGING_KEY =
+ "battery_threshold_not_charging";
+
+ private static final String BATTERY_THRESHOLD_CHARGING_KEY =
+ "battery_threshold_charging";
+
/**
* The back-off before re-connecting, when a service binding died, due to the owner
* crashing repeatedly.
@@ -63,6 +69,17 @@
*/
public final long DAS_DIED_SERVICE_STABLE_CONNECTION_THRESHOLD_SEC;
+ /**
+ * Battery threshold for installing system update while the device is not charging.
+ */
+ public final int BATTERY_THRESHOLD_NOT_CHARGING;
+
+ /**
+ * Battery threshold for installing system update while the device is charging.
+ */
+ public final int BATTERY_THRESHOLD_CHARGING;
+
+
private DevicePolicyConstants(String settings) {
final KeyValueListParser parser = new KeyValueListParser(',');
@@ -87,6 +104,12 @@
DAS_DIED_SERVICE_STABLE_CONNECTION_THRESHOLD_SEC_KEY,
TimeUnit.MINUTES.toSeconds(2));
+ int batteryThresholdNotCharging = parser.getInt(
+ BATTERY_THRESHOLD_NOT_CHARGING_KEY, 40);
+
+ int batteryThresholdCharging = parser.getInt(
+ BATTERY_THRESHOLD_CHARGING_KEY, 20);
+
// Set minimum: 5 seconds.
dasDiedServiceReconnectBackoffSec = Math.max(5, dasDiedServiceReconnectBackoffSec);
@@ -103,6 +126,8 @@
DAS_DIED_SERVICE_RECONNECT_MAX_BACKOFF_SEC = dasDiedServiceReconnectMaxBackoffSec;
DAS_DIED_SERVICE_STABLE_CONNECTION_THRESHOLD_SEC =
dasDiedServiceStableConnectionThresholdSec;
+ BATTERY_THRESHOLD_NOT_CHARGING = batteryThresholdNotCharging;
+ BATTERY_THRESHOLD_CHARGING = batteryThresholdCharging;
}
public static DevicePolicyConstants loadFromString(String settings) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index bbbc40c..7751b4a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -113,6 +113,7 @@
import android.app.admin.PasswordMetrics;
import android.app.admin.SecurityLog;
import android.app.admin.SecurityLog.SecurityEvent;
+import android.app.admin.StartInstallingUpdateCallback;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.app.backup.IBackupManager;
@@ -379,6 +380,8 @@
private static final Set<String> GLOBAL_SETTINGS_DEPRECATED;
private static final Set<String> SYSTEM_SETTINGS_WHITELIST;
private static final Set<Integer> DA_DISALLOWED_POLICIES;
+ private static final String AB_DEVICE_KEY = "ro.build.ab_update";
+
static {
SECURE_SETTINGS_WHITELIST = new ArraySet<>();
SECURE_SETTINGS_WHITELIST.add(Settings.Secure.DEFAULT_INPUT_METHOD);
@@ -13315,4 +13318,30 @@
return mInjector.settingsGlobalGetString(PRIVATE_DNS_SPECIFIER);
}
+
+ @Override
+ public void installUpdateFromFile(ComponentName admin,
+ ParcelFileDescriptor updateFileDescriptor, StartInstallingUpdateCallback callback) {
+ enforceDeviceOwner(admin);
+ final long id = mInjector.binderClearCallingIdentity();
+ try {
+ UpdateInstaller updateInstaller;
+ if (isDeviceAB()) {
+ updateInstaller = new AbUpdateInstaller(
+ mContext, updateFileDescriptor, callback, mInjector, mConstants);
+ } else {
+ updateInstaller = new NonAbUpdateInstaller(
+ mContext, updateFileDescriptor, callback, mInjector, mConstants);
+ }
+ updateInstaller.startInstallUpdate();
+ } finally {
+ mInjector.binderRestoreCallingIdentity(id);
+ }
+ }
+
+
+ private boolean isDeviceAB() {
+ return "true".equalsIgnoreCase(android.os.SystemProperties
+ .get(AB_DEVICE_KEY, ""));
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java
new file mode 100644
index 0000000..5f1e926
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NonAbUpdateInstaller.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.StartInstallingUpdateCallback;
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.os.RecoverySystem;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * Used for installing an update for <a href="https://source.android.com/devices/tech/ota/nonab">non
+ * AB</a> devices.
+ */
+class NonAbUpdateInstaller extends UpdateInstaller {
+ NonAbUpdateInstaller(Context context,
+ ParcelFileDescriptor updateFileDescriptor,
+ StartInstallingUpdateCallback callback, DevicePolicyManagerService.Injector injector,
+ DevicePolicyConstants constants) {
+ super(context, updateFileDescriptor, callback, injector, constants);
+ }
+
+ @Override
+ public void installUpdateInThread() {
+ try {
+ RecoverySystem.installPackage(mContext, mCopiedUpdateFile);
+ notifyCallbackOnSuccess();
+ } catch (IOException e) {
+ Log.w(TAG, "IO error while trying to install non AB update.", e);
+ notifyCallbackOnError(
+ DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
+ Log.getStackTraceString(e));
+ }
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
new file mode 100644
index 0000000..7910598
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/UpdateInstaller.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.StartInstallingUpdateCallback;
+import android.content.Context;
+import android.os.BatteryManager;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+abstract class UpdateInstaller {
+ private StartInstallingUpdateCallback mCallback;
+ private ParcelFileDescriptor mUpdateFileDescriptor;
+ private DevicePolicyConstants mConstants;
+ protected Context mContext;
+ protected File mCopiedUpdateFile;
+
+ static final String TAG = "UpdateInstaller";
+ private DevicePolicyManagerService.Injector mInjector;
+
+ protected UpdateInstaller(Context context, ParcelFileDescriptor updateFileDescriptor,
+ StartInstallingUpdateCallback callback, DevicePolicyManagerService.Injector injector,
+ DevicePolicyConstants constants) {
+ mContext = context;
+ mCallback = callback;
+ mUpdateFileDescriptor = updateFileDescriptor;
+ mInjector = injector;
+ mConstants = constants;
+ }
+
+ public abstract void installUpdateInThread();
+
+ public void startInstallUpdate() {
+ if (!checkIfBatteryIsSufficient()) {
+ notifyCallbackOnError(
+ DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_BATTERY_LOW,
+ "The battery level must be above "
+ + mConstants.BATTERY_THRESHOLD_NOT_CHARGING + " while not charging or"
+ + "above " + mConstants.BATTERY_THRESHOLD_CHARGING + " while charging");
+ return;
+ }
+ Thread thread = new Thread(() -> {
+ mCopiedUpdateFile = copyUpdateFileToDataOtaPackageDir();
+ if (mCopiedUpdateFile == null) {
+ notifyCallbackOnError(
+ DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
+ "Error while copying file.");
+ return;
+ }
+ installUpdateInThread();
+ });
+ thread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ thread.start();
+ }
+
+ private boolean checkIfBatteryIsSufficient() {
+ BatteryManager batteryManager =
+ (BatteryManager) mContext.getSystemService(Context.BATTERY_SERVICE);
+ if (batteryManager != null) {
+ int chargePercentage = batteryManager
+ .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
+ return batteryManager.isCharging()
+ ? chargePercentage >= mConstants.BATTERY_THRESHOLD_CHARGING
+ : chargePercentage >= mConstants.BATTERY_THRESHOLD_NOT_CHARGING;
+ }
+ return false;
+ }
+
+ private File copyUpdateFileToDataOtaPackageDir() {
+ try {
+ File destination = createNewFileWithPermissions();
+ copyToFile(destination);
+ return destination;
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to copy update file to OTA directory", e);
+ notifyCallbackOnError(
+ DevicePolicyManager.InstallUpdateCallback.UPDATE_ERROR_UNKNOWN,
+ Log.getStackTraceString(e));
+ return null;
+ }
+ }
+
+ private File createNewFileWithPermissions() throws IOException {
+ File destination = File.createTempFile(
+ "update", ".zip", new File(Environment.getDataDirectory() + "/ota_package"));
+ FileUtils.setPermissions(
+ /* path= */ destination,
+ /* mode= */ FileUtils.S_IRWXU | FileUtils.S_IRGRP | FileUtils.S_IROTH,
+ /* uid= */ -1, /* gid= */ -1);
+ return destination;
+ }
+
+ private void copyToFile(File destination) throws IOException {
+ try (OutputStream out = new FileOutputStream(destination);
+ InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
+ mUpdateFileDescriptor)) {
+ FileUtils.copy(in, out);
+ }
+ }
+
+ void cleanupUpdateFile() {
+ if (mCopiedUpdateFile.exists()) {
+ mCopiedUpdateFile.delete();
+ }
+ }
+
+ protected void notifyCallbackOnError(int errorCode, String errorMessage) {
+ cleanupUpdateFile();
+ try {
+ mCallback.onStartInstallingUpdateError(errorCode, errorMessage);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error while calling callback", e);
+ }
+ }
+
+ protected void notifyCallbackOnSuccess() {
+ cleanupUpdateFile();
+ mInjector.powerManagerReboot(PowerManager.REBOOT_REQUESTED_BY_DEVICE_OWNER);
+ }
+}
diff --git a/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java b/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java
index 57e954f..08fbf55 100644
--- a/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java
+++ b/services/intelligence/java/com/android/server/intelligence/ContentCaptureSession.java
@@ -24,11 +24,14 @@
import android.service.intelligence.InteractionSessionId;
import android.service.intelligence.SnapshotData;
import android.util.Slog;
+import android.view.autofill.AutofillId;
+import android.view.autofill.IAutoFillManagerClient;
import android.view.intelligence.ContentCaptureEvent;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import com.android.server.AbstractRemoteService;
+import com.android.server.intelligence.IntelligenceManagerInternal.AugmentedAutofillCallback;
import com.android.server.intelligence.RemoteIntelligenceService.RemoteIntelligenceServiceCallbacks;
import java.io.PrintWriter;
@@ -39,12 +42,12 @@
private static final String TAG = "ContentCaptureSession";
private final Object mLock;
- private final IBinder mActivityToken;
-
+ final IBinder mActivityToken;
private final IntelligencePerUserService mService;
private final RemoteIntelligenceService mRemoteService;
private final InteractionContext mInterationContext;
private final InteractionSessionId mId;
+ private AugmentedAutofillCallback mAutofillCallback;
ContentCaptureSession(@NonNull Context context, int userId, @NonNull Object lock,
@NonNull IBinder activityToken, @NonNull IntelligencePerUserService service,
@@ -92,6 +95,18 @@
}
/**
+ * Requests the service to autofill the given field.
+ */
+ public AugmentedAutofillCallback requestAutofillLocked(@NonNull IAutoFillManagerClient client,
+ int autofillSessionId, @NonNull AutofillId focusedId) {
+ mRemoteService.onRequestAutofillLocked(mId, client, autofillSessionId, focusedId);
+ if (mAutofillCallback == null) {
+ mAutofillCallback = () -> mRemoteService.onDestroyAutofillWindowsRequest(mId);
+ }
+ return mAutofillCallback;
+ }
+
+ /**
* Cleans up the session and removes it from the service.
*
* @param notifyRemoteService whether it should trigger a {@link
@@ -119,6 +134,11 @@
if (mService.isVerbose()) {
Slog.v(TAG, "destroyLocked(notifyRemoteService=" + notifyRemoteService + ")");
}
+ if (mAutofillCallback != null) {
+ mAutofillCallback.destroy();
+ mAutofillCallback = null;
+ }
+
// TODO(b/111276913): must call client to set session as FINISHED_BY_SERVER
if (notifyRemoteService) {
mRemoteService.onSessionLifecycleRequest(/* context= */ null, mId);
@@ -152,6 +172,8 @@
pw.print(prefix); pw.print("id: "); mId.dump(pw); pw.println();
pw.print(prefix); pw.print("context: "); mInterationContext.dump(pw); pw.println();
pw.print(prefix); pw.print("activity token: "); pw.println(mActivityToken);
+ pw.print(prefix); pw.print("has autofill callback: ");
+ pw.println(mAutofillCallback != null);
}
@Override
diff --git a/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java b/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java
index a7f45ee..38810dd 100644
--- a/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java
+++ b/services/intelligence/java/com/android/server/intelligence/IntelligenceManagerService.java
@@ -27,6 +27,8 @@
import android.os.IBinder;
import android.os.UserManager;
import android.service.intelligence.InteractionSessionId;
+import android.view.autofill.AutofillId;
+import android.view.autofill.IAutoFillManagerClient;
import android.view.intelligence.ContentCaptureEvent;
import android.view.intelligence.IIntelligenceManager;
@@ -86,20 +88,6 @@
service.destroyLocked();
}
- /**
- * Notifies the intelligence service of new assist data for the given activity.
- *
- * @return {@code false} if there was no service set for the given user
- */
- private boolean sendActivityAssistDataLocked(@UserIdInt int userId,
- @NonNull IBinder activityToken, @NonNull Bundle data) {
- final IntelligencePerUserService service = peekServiceForUserLocked(userId);
- if (service != null) {
- return service.sendActivityAssistDataLocked(activityToken, data);
- }
- return false;
- }
-
private ActivityManagerInternal getAmInternal() {
synchronized (mLock) {
if (mAm == null) {
@@ -112,7 +100,7 @@
final class IntelligenceManagerServiceStub extends IIntelligenceManager.Stub {
@Override
- public void startSession(int userId, @NonNull IBinder activityToken,
+ public void startSession(@UserIdInt int userId, @NonNull IBinder activityToken,
@NonNull ComponentName componentName, @NonNull InteractionSessionId sessionId,
int flags, @NonNull IResultReceiver result) {
Preconditions.checkNotNull(activityToken);
@@ -134,7 +122,7 @@
}
@Override
- public void sendEvents(int userId, @NonNull InteractionSessionId sessionId,
+ public void sendEvents(@UserIdInt int userId, @NonNull InteractionSessionId sessionId,
@NonNull List<ContentCaptureEvent> events) {
Preconditions.checkNotNull(sessionId);
Preconditions.checkNotNull(events);
@@ -146,7 +134,7 @@
}
@Override
- public void finishSession(int userId, @NonNull InteractionSessionId sessionId) {
+ public void finishSession(@UserIdInt int userId, @NonNull InteractionSessionId sessionId) {
Preconditions.checkNotNull(sessionId);
synchronized (mLock) {
@@ -168,14 +156,13 @@
private final class LocalService extends IntelligenceManagerInternal {
@Override
- public boolean isIntelligenceServiceForUser(int uid, int userId) {
+ public boolean isIntelligenceServiceForUser(int uid, @UserIdInt int userId) {
synchronized (mLock) {
final IntelligencePerUserService service = peekServiceForUserLocked(userId);
if (service != null) {
return service.isIntelligenceServiceForUserLocked(uid);
}
}
-
return false;
}
@@ -183,8 +170,26 @@
public boolean sendActivityAssistData(@UserIdInt int userId, @NonNull IBinder activityToken,
@NonNull Bundle data) {
synchronized (mLock) {
- return sendActivityAssistDataLocked(userId, activityToken, data);
+ final IntelligencePerUserService service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ return service.sendActivityAssistDataLocked(activityToken, data);
+ }
}
+ return false;
+ }
+
+ @Override
+ public AugmentedAutofillCallback requestAutofill(@UserIdInt int userId,
+ @NonNull IAutoFillManagerClient client, @NonNull IBinder activityToken,
+ int autofillSessionId, @NonNull AutofillId focusedId) {
+ synchronized (mLock) {
+ final IntelligencePerUserService service = peekServiceForUserLocked(userId);
+ if (service != null) {
+ return service.requestAutofill(client, activityToken, autofillSessionId,
+ focusedId);
+ }
+ }
+ return null;
}
}
}
diff --git a/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java b/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java
index 9694ab9..051f0d6 100644
--- a/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java
+++ b/services/intelligence/java/com/android/server/intelligence/IntelligencePerUserService.java
@@ -22,6 +22,7 @@
import android.Manifest;
import android.annotation.NonNull;
+import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
@@ -36,12 +37,15 @@
import android.service.intelligence.SnapshotData;
import android.util.ArrayMap;
import android.util.Slog;
+import android.view.autofill.AutofillId;
+import android.view.autofill.IAutoFillManagerClient;
import android.view.intelligence.ContentCaptureEvent;
import android.view.intelligence.IntelligenceManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
import com.android.server.AbstractPerUserSystemService;
+import com.android.server.intelligence.IntelligenceManagerInternal.AugmentedAutofillCallback;
import java.io.PrintWriter;
import java.util.List;
@@ -62,7 +66,7 @@
// TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
protected IntelligencePerUserService(
- IntelligenceManagerService master, Object lock, int userId) {
+ IntelligenceManagerService master, Object lock, @UserIdInt int userId) {
super(master, lock, userId);
}
@@ -210,6 +214,17 @@
return uid == getServiceUidLocked();
}
+ @GuardedBy("mLock")
+ private ContentCaptureSession getSession(@NonNull IBinder activityToken) {
+ for (int i = 0; i < mSessions.size(); i++) {
+ final ContentCaptureSession session = mSessions.valueAt(i);
+ if (session.mActivityToken.equals(activityToken)) {
+ return session;
+ }
+ }
+ return null;
+ }
+
/**
* Destroys the service and all state associated with it.
*
@@ -226,6 +241,22 @@
mSessions.clear();
}
+ public AugmentedAutofillCallback requestAutofill(@NonNull IAutoFillManagerClient client,
+ @NonNull IBinder activityToken, int autofillSessionId, @NonNull AutofillId focusedId) {
+ synchronized (mLock) {
+ final ContentCaptureSession session = getSession(activityToken);
+ if (session != null) {
+ // TODO(b/111330312): log metrics
+ if (mMaster.verbose) Slog.v(TAG, "requestAugmentedAutofill()");
+ return session.requestAutofillLocked(client, autofillSessionId, focusedId);
+ }
+ if (mMaster.debug) {
+ Slog.d(TAG, "requestAutofill(): no session for " + activityToken);
+ }
+ return null;
+ }
+ }
+
@Override
protected void dumpLocked(String prefix, PrintWriter pw) {
super.dumpLocked(prefix, pw);
diff --git a/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java b/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java
index a27c1cf..00c5b6a 100644
--- a/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java
+++ b/services/intelligence/java/com/android/server/intelligence/RemoteIntelligenceService.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;
@@ -28,8 +29,12 @@
import android.service.intelligence.SnapshotData;
import android.text.format.DateUtils;
import android.util.Slog;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillManager;
+import android.view.autofill.IAutoFillManagerClient;
import android.view.intelligence.ContentCaptureEvent;
+import com.android.internal.os.IResultReceiver;
import com.android.server.AbstractRemoteService;
import java.util.List;
@@ -39,7 +44,7 @@
private static final String TAG = "RemoteIntelligenceService";
private static final long TIMEOUT_IDLE_BIND_MILLIS = 2 * DateUtils.MINUTE_IN_MILLIS;
- private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.MINUTE_IN_MILLIS;
+ private static final long TIMEOUT_REMOTE_REQUEST_MILLIS = 2 * DateUtils.SECOND_IN_MILLIS;
private final RemoteIntelligenceServiceCallbacks mCallbacks;
private IIntelligenceService mService;
@@ -101,6 +106,25 @@
scheduleRequest(new PendingOnActivitySnapshotRequest(this, sessionId, snapshotData));
}
+ /**
+ * Called by {@link ContentCaptureSession} to request augmented autofill.
+ */
+ public void onRequestAutofillLocked(@NonNull InteractionSessionId sessionId,
+ @NonNull IAutoFillManagerClient client, int autofillSessionId,
+ @NonNull AutofillId focusedId) {
+ cancelScheduledUnbind();
+ scheduleRequest(new PendingAutofillRequest(this, sessionId, client, autofillSessionId,
+ focusedId));
+ }
+
+ /**
+ * Called by {@link ContentCaptureSession} when it's time to destroy all augmented autofill
+ * requests.
+ */
+ public void onDestroyAutofillWindowsRequest(@NonNull InteractionSessionId sessionId) {
+ cancelScheduledUnbind();
+ scheduleRequest(new PendingDestroyAutofillWindowsRequest(this, sessionId));
+ }
private abstract static class MyPendingRequest
extends PendingRequest<RemoteIntelligenceService> {
@@ -124,8 +148,9 @@
final RemoteIntelligenceService remoteService = getService();
if (remoteService != null) {
try {
- myRun(remoteService);
// We don't expect the service to call us back, so we finish right away.
+ myRun(remoteService);
+ // TODO(b/111330312): not true anymore!!
finish();
} catch (RemoteException e) {
Slog.w(TAG, "exception handling " + getClass().getSimpleName() + " for "
@@ -191,6 +216,53 @@
}
}
+ private static final class PendingAutofillRequest extends MyPendingRequest {
+ private final @NonNull AutofillId mFocusedId;
+ private final @NonNull IAutoFillManagerClient mClient;
+ private final int mAutofillSessionId;
+
+ protected PendingAutofillRequest(@NonNull RemoteIntelligenceService service,
+ @NonNull InteractionSessionId sessionId, @NonNull IAutoFillManagerClient client,
+ int autofillSessionId, @NonNull AutofillId focusedId) {
+ super(service, sessionId);
+ mClient = client;
+ mAutofillSessionId = autofillSessionId;
+ mFocusedId = focusedId;
+ }
+
+ @Override // from MyPendingRequest
+ public void myRun(@NonNull RemoteIntelligenceService remoteService) throws RemoteException {
+ final IResultReceiver receiver = new IResultReceiver.Stub() {
+
+ @Override
+ public void send(int resultCode, Bundle resultData) throws RemoteException {
+ final IBinder realClient = resultData
+ .getBinder(AutofillManager.EXTRA_AUGMENTED_AUTOFILL_CLIENT);
+ remoteService.mService.onAutofillRequest(mSessionId, realClient,
+ mAutofillSessionId, mFocusedId);
+ }
+ };
+
+ // TODO(b/111330312): set cancellation signal, timeout (from both mClient and service),
+ // cache IAugmentedAutofillManagerClient reference, etc...
+ mClient.getAugmentedAutofillClient(receiver);
+ }
+ }
+
+ private static final class PendingDestroyAutofillWindowsRequest extends MyPendingRequest {
+
+ protected PendingDestroyAutofillWindowsRequest(@NonNull RemoteIntelligenceService service,
+ @NonNull InteractionSessionId sessionId) {
+ super(service, sessionId);
+ }
+
+ @Override
+ protected void myRun(@NonNull RemoteIntelligenceService service) throws RemoteException {
+ service.mService.onDestroyAutofillWindowsRequest(mSessionId);
+ // TODO(b/111330312): implement timeout
+ }
+ }
+
public interface RemoteIntelligenceServiceCallbacks extends VultureCallback {
// To keep it simple, we use the same callback for all failures / timeouts.
void onFailureOrTimeout(boolean timedOut);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f8ac41f..56f7cff 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -36,7 +36,6 @@
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
import android.hardware.display.ColorDisplayManager;
-import android.hardware.display.DisplayManagerInternal;
import android.os.BaseBundle;
import android.os.Binder;
import android.os.Build;
@@ -717,17 +716,9 @@
// Manages Overlay packages
traceBeginAndSlog("StartOverlayManagerService");
- OverlayManagerService overlayManagerService = new OverlayManagerService(
- mSystemContext, installer);
- mSystemServiceManager.startService(overlayManagerService);
+ mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
traceEnd();
- if (SystemProperties.getInt("persist.sys.displayinset.top", 0) > 0) {
- // DisplayManager needs the overlay immediately.
- overlayManagerService.updateSystemUiContext();
- LocalServices.getService(DisplayManagerInternal.class).onOverlayChanged();
- }
-
// The sensor service needs access to package manager service, app ops
// service, and permissions service, therefore we start it after them.
// Start sensor service in a separate thread. Completion should be checked
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
index 565152c..6f10ed5 100644
--- a/services/robotests/Android.mk
+++ b/services/robotests/Android.mk
@@ -26,6 +26,7 @@
LOCAL_PRIVILEGED_MODULE := true
LOCAL_STATIC_JAVA_LIBRARIES := \
+ bmgrlib \
services.backup \
services.core \
services.net
diff --git a/services/robotests/src/com/android/commands/bmgr/BmgrTest.java b/services/robotests/src/com/android/commands/bmgr/BmgrTest.java
new file mode 100644
index 0000000..1705f5b
--- /dev/null
+++ b/services/robotests/src/com/android/commands/bmgr/BmgrTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.bmgr;
+
+import static org.mockito.Mockito.verify;
+
+import android.app.backup.IBackupManager;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+/** Unit tests for {@link com.android.commands.bmgr.Bmgr}. */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class BmgrTest {
+ @Mock private IBackupManager mBackupManager;
+ private Bmgr mBmgr;
+
+ /** Common setup run before each test method. */
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mBmgr = new Bmgr(mBackupManager);
+ }
+
+ /**
+ * Test that bmgr uses the default user {@link UserHandle.USER_SYSTEM} if no user is specified.
+ */
+ @Test
+ public void testRun_whenUserNotSpecified_callsBackupManagerAsSystemUser() throws Exception {
+ mBmgr.run(new String[] {"run"});
+
+ verify(mBackupManager).isBackupServiceActive(UserHandle.USER_SYSTEM);
+ }
+
+ /** Test that bmgr uses the specified user if an user is specified. */
+ @Test
+ public void testRun_whenUserSpecified_callsBackupManagerAsSpecifiedUser() throws Exception {
+ mBmgr.run(new String[] {"--user", "10"});
+
+ verify(mBackupManager).isBackupServiceActive(10);
+ }
+}
diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp
new file mode 100644
index 0000000..ebc816d
--- /dev/null
+++ b/services/tests/mockingservicestests/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "FrameworksMockingServicesTests",
+
+ srcs: ["src/**/*.java"],
+
+ static_libs: [
+ "services.core",
+ "services.net",
+ "androidx.test.runner",
+ "mockito-target-extended-minus-junit4",
+ "platform-test-annotations",
+ ],
+
+ libs: [
+ "android.test.mock",
+ "android.test.base",
+ "android.test.runner",
+ ],
+
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+
+ certificate: "platform",
+ platform_apis: true,
+ test_suites: ["device-tests"],
+
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/services/tests/mockingservicestests/Android.mk b/services/tests/mockingservicestests/Android.mk
deleted file mode 100644
index b21b3e4..0000000
--- a/services/tests/mockingservicestests/Android.mk
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- services.core \
- services.net \
- androidx.test.runner \
- mockito-target-extended-minus-junit4 \
- platform-test-annotations \
-
-LOCAL_JAVA_LIBRARIES := android.test.mock android.test.base android.test.runner
-
-LOCAL_JNI_SHARED_LIBRARIES := \
- libdexmakerjvmtiagent \
- libstaticjvmtiagent \
-
-LOCAL_CERTIFICATE := platform
-LOCAL_PACKAGE_NAME := FrameworksMockingServicesTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
new file mode 100644
index 0000000..e804342
--- /dev/null
+++ b/services/tests/servicestests/Android.bp
@@ -0,0 +1,104 @@
+//########################################################################
+// Build FrameworksServicesTests package
+//########################################################################
+
+android_test {
+ name: "FrameworksServicesTests",
+
+ // Include all test java files.
+ srcs: [
+ "src/**/*.java",
+
+ "aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl",
+ "aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl",
+
+ "test-apps/JobTestApp/src/**/*.java",
+
+ "test-apps/SuspendTestApp/src/**/*.java",
+ ],
+ static_libs: [
+ "frameworks-base-testutils",
+ "services.accessibility",
+ "services.appwidget",
+ "services.autofill",
+ "services.backup",
+ "services.core",
+ "services.devicepolicy",
+ "services.net",
+ "services.usage",
+ "guava",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "mockito-target-minus-junit4",
+ "platform-test-annotations",
+ "ShortcutManagerTestUtils",
+ "truth-prebuilt",
+ "testables",
+ "testng",
+ "ub-uiautomator",
+ "platformprotosnano",
+ "hamcrest-library",
+ "servicestests-utils",
+ ],
+
+ aidl: {
+ local_include_dirs: ["aidl"],
+ },
+
+ libs: [
+ "android.hidl.manager-V1.0-java",
+ "android.hardware.tv.cec-V1.0-java",
+ "android.test.mock",
+ "android.test.base",
+ "android.test.runner",
+ ],
+
+ platform_apis: true,
+ test_suites: ["device-tests"],
+
+ certificate: "platform",
+
+ // These are not normally accessible from apps so they must be explicitly included.
+ jni_libs: [
+ "libbacktrace",
+ "libbase",
+ "libbinder",
+ "libbinderthreadstate",
+ "libc++",
+ "libcutils",
+ "liblog",
+ "liblzma",
+ "libnativehelper",
+ "libnetdaidl",
+ "libui",
+ "libunwind",
+ "libutils",
+ ],
+
+ dxflags: ["--multi-dex"],
+
+ optimize: {
+ enabled: false,
+ },
+}
+
+java_library {
+ name: "servicestests-utils",
+ srcs: [
+ "utils/**/*.java",
+ ],
+ static_libs: [
+ "android-support-test",
+ "mockito-target-minus-junit4",
+ ],
+ libs: [
+ "android.test.runner",
+ ],
+}
+
+filegroup {
+ name: "servicestests-SuspendTestApp-files",
+ srcs: [
+ "src/com/android/server/pm/SuspendPackagesTest.java",
+ ],
+}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
deleted file mode 100644
index e2f8995..0000000
--- a/services/tests/servicestests/Android.mk
+++ /dev/null
@@ -1,83 +0,0 @@
-#########################################################################
-# Build FrameworksServicesTests package
-#########################################################################
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-java-files-under, utils) \
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- frameworks-base-testutils \
- services.accessibility \
- services.appwidget \
- services.autofill \
- services.backup \
- services.core \
- services.devicepolicy \
- services.net \
- services.usage \
- guava \
- androidx.test.runner \
- androidx.test.rules \
- mockito-target-minus-junit4 \
- platform-test-annotations \
- ShortcutManagerTestUtils \
- truth-prebuilt \
- testables \
- testng \
- ub-uiautomator\
- platformprotosnano \
- hamcrest-library
-
-LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl
-
-LOCAL_SRC_FILES += aidl/com/android/servicestests/aidl/INetworkStateObserver.aidl \
- aidl/com/android/servicestests/aidl/ICmdReceiverService.aidl
-LOCAL_SRC_FILES += $(call all-java-files-under, test-apps/JobTestApp/src)
-LOCAL_SRC_FILES += $(call all-java-files-under, test-apps/SuspendTestApp/src)
-
-LOCAL_JAVA_LIBRARIES := \
- android.hidl.manager-V1.0-java \
- android.hardware.tv.cec-V1.0-java \
- android.test.mock \
- android.test.base android.test.runner \
-
-LOCAL_PACKAGE_NAME := FrameworksServicesTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_CERTIFICATE := platform
-
-# These are not normally accessible from apps so they must be explicitly included.
-LOCAL_JNI_SHARED_LIBRARIES := \
- libbacktrace \
- libbase \
- libbinder \
- libbinderthreadstate \
- libc++ \
- libcutils \
- liblog \
- liblzma \
- libnativehelper \
- libnetdaidl \
- libui \
- libunwind \
- libutils
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_DX_FLAGS := --multi-dex
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/tests/servicestests/aidl/Android.bp b/services/tests/servicestests/aidl/Android.bp
new file mode 100644
index 0000000..d4e53dd
--- /dev/null
+++ b/services/tests/servicestests/aidl/Android.bp
@@ -0,0 +1,22 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_library {
+ name: "servicestests-aidl",
+ sdk_version: "current",
+ srcs: [
+ "com/android/servicestests/aidl/INetworkStateObserver.aidl",
+ "com/android/servicestests/aidl/ICmdReceiverService.aidl",
+ ],
+}
diff --git a/services/tests/servicestests/aidl/Android.mk b/services/tests/servicestests/aidl/Android.mk
deleted file mode 100644
index 166da1d..0000000
--- a/services/tests/servicestests/aidl/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-LOCAL_SRC_FILES := \
- com/android/servicestests/aidl/INetworkStateObserver.aidl \
- com/android/servicestests/aidl/ICmdReceiverService.aidl
-LOCAL_MODULE := servicestests-aidl
-include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerInsetsTest.java b/services/tests/servicestests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
similarity index 71%
rename from services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerInsetsTest.java
rename to services/tests/servicestests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
index f024fe7..18bd2e4 100644
--- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerInsetsTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayPolicyInsetsTests.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.policy;
+package com.android.server.wm;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
@@ -25,36 +25,27 @@
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
-import android.view.Display;
import android.view.DisplayInfo;
import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ErrorCollector;
+import org.junit.runner.RunWith;
-/**
- * Build/Install/Run:
- * atest WmTests:PhoneWindowManagerInsetsTest
- */
+@RunWith(AndroidJUnit4.class)
@SmallTest
@Presubmit
-public class PhoneWindowManagerInsetsTest extends PhoneWindowManagerTestBase {
+public class DisplayPolicyInsetsTests extends DisplayPolicyTestsBase {
@Rule
public final ErrorCollector mErrorCollector = new ErrorCollector();
- @Before
- public void setUp() throws Exception {
- addStatusBar();
- addNavigationBar();
- }
-
@Test
public void portrait() {
- DisplayInfo di = displayInfoForRotation(ROTATION_0, false /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_0, false /* withCutout */);
verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT);
@@ -63,7 +54,7 @@
@Test
public void portrait_withCutout() {
- DisplayInfo di = displayInfoForRotation(ROTATION_0, true /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_0, true /* withCutout */);
verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
verifyNonDecorInsets(di, 0, DISPLAY_CUTOUT_HEIGHT, 0, NAV_BAR_HEIGHT);
@@ -72,7 +63,7 @@
@Test
public void landscape() {
- DisplayInfo di = displayInfoForRotation(ROTATION_90, false /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_90, false /* withCutout */);
verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
verifyNonDecorInsets(di, 0, 0, NAV_BAR_HEIGHT, 0);
@@ -81,7 +72,7 @@
@Test
public void landscape_withCutout() {
- DisplayInfo di = displayInfoForRotation(ROTATION_90, true /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_90, true /* withCutout */);
verifyStableInsets(di, DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
verifyNonDecorInsets(di, DISPLAY_CUTOUT_HEIGHT, 0, NAV_BAR_HEIGHT, 0);
@@ -90,7 +81,7 @@
@Test
public void seascape() {
- DisplayInfo di = displayInfoForRotation(ROTATION_270, false /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_270, false /* withCutout */);
verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
verifyNonDecorInsets(di, NAV_BAR_HEIGHT, 0, 0, 0);
@@ -99,7 +90,7 @@
@Test
public void seascape_withCutout() {
- DisplayInfo di = displayInfoForRotation(ROTATION_270, true /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_270, true /* withCutout */);
verifyStableInsets(di, NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
verifyNonDecorInsets(di, NAV_BAR_HEIGHT, 0, DISPLAY_CUTOUT_HEIGHT, 0);
@@ -108,7 +99,7 @@
@Test
public void upsideDown() {
- DisplayInfo di = displayInfoForRotation(ROTATION_180, false /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_180, false /* withCutout */);
verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT);
verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT);
@@ -117,7 +108,7 @@
@Test
public void upsideDown_withCutout() {
- DisplayInfo di = displayInfoForRotation(ROTATION_180, true /* withCutout */);
+ final DisplayInfo di = displayInfoForRotation(ROTATION_180, true /* withCutout */);
verifyStableInsets(di, 0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT + DISPLAY_CUTOUT_HEIGHT);
verifyNonDecorInsets(di, 0, 0, 0, NAV_BAR_HEIGHT + DISPLAY_CUTOUT_HEIGHT);
@@ -151,35 +142,39 @@
private Rect getStableInsetsLw(DisplayInfo di) {
Rect result = new Rect();
- mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
+ mDisplayPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
di.displayCutout, result);
return result;
}
private Rect getNonDecorInsetsLw(DisplayInfo di) {
Rect result = new Rect();
- mPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
+ mDisplayPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
di.displayCutout, result);
return result;
}
private int getNonDecorDisplayWidth(DisplayInfo di) {
- return mPolicy.getNonDecorDisplayWidth(di.logicalWidth, di.logicalHeight, di.rotation,
- 0 /* ui */, Display.DEFAULT_DISPLAY, di.displayCutout);
+ return mDisplayPolicy.getNonDecorDisplayWidth(di.logicalWidth, di.logicalHeight,
+ di.rotation, 0 /* ui */, di.displayCutout);
}
private int getNonDecorDisplayHeight(DisplayInfo di) {
- return mPolicy.getNonDecorDisplayHeight(di.logicalWidth, di.logicalHeight, di.rotation,
- 0 /* ui */, Display.DEFAULT_DISPLAY, di.displayCutout);
+ return mDisplayPolicy.getNonDecorDisplayHeight(di.logicalWidth, di.logicalHeight,
+ di.rotation, 0 /* ui */, di.displayCutout);
}
private int getConfigDisplayWidth(DisplayInfo di) {
- return mPolicy.getConfigDisplayWidth(di.logicalWidth, di.logicalHeight, di.rotation,
- 0 /* ui */, Display.DEFAULT_DISPLAY, di.displayCutout);
+ return mDisplayPolicy.getConfigDisplayWidth(di.logicalWidth, di.logicalHeight,
+ di.rotation, 0 /* ui */, di.displayCutout);
}
private int getConfigDisplayHeight(DisplayInfo di) {
- return mPolicy.getConfigDisplayHeight(di.logicalWidth, di.logicalHeight, di.rotation,
- 0 /* ui */, Display.DEFAULT_DISPLAY, di.displayCutout);
+ return mDisplayPolicy.getConfigDisplayHeight(di.logicalWidth, di.logicalHeight,
+ di.rotation, 0 /* ui */, di.displayCutout);
+ }
+
+ private static DisplayInfo displayInfoForRotation(int rotation, boolean withDisplayCutout) {
+ return displayInfoAndCutoutForRotation(rotation, withDisplayCutout).first;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
new file mode 100644
index 0000000..a91c5e7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
+
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.util.Pair;
+import android.view.DisplayCutout;
+import android.view.DisplayInfo;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.wm.utils.WmDisplayCutout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase {
+
+ private DisplayFrames mFrames;
+ private WindowState mWindow;
+ private int mRotation = ROTATION_0;
+ private boolean mHasDisplayCutout;
+
+ @Before
+ public void setUp() throws Exception {
+ updateDisplayFrames();
+
+ mWindow = spy(createWindow(null, TYPE_APPLICATION, "window"));
+ // We only test window frames set by DisplayPolicy, so here prevents computeFrameLw from
+ // changing those frames.
+ doNothing().when(mWindow).computeFrameLw();
+
+ final WindowManager.LayoutParams attrs = mWindow.mAttrs;
+ attrs.width = MATCH_PARENT;
+ attrs.height = MATCH_PARENT;
+ attrs.flags =
+ FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ attrs.format = PixelFormat.TRANSLUCENT;
+ }
+
+ public void setRotation(int rotation) {
+ mRotation = rotation;
+ updateDisplayFrames();
+ }
+
+ public void addDisplayCutout() {
+ mHasDisplayCutout = true;
+ updateDisplayFrames();
+ }
+
+ private void updateDisplayFrames() {
+ final Pair<DisplayInfo, WmDisplayCutout> info = displayInfoAndCutoutForRotation(mRotation,
+ mHasDisplayCutout);
+ mFrames = new DisplayFrames(mDisplayContent.getDisplayId(), info.first, info.second);
+ }
+
+ @Test
+ public void layoutWindowLw_appDrawsBars() {
+ mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+ assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+ assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_appWontDrawBars() {
+ mWindow.mAttrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDecorFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
+ }
+
+ @Test
+ public void layoutWindowLw_appWontDrawBars_forceStatus() throws Exception {
+ mWindow.mAttrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ mWindow.mAttrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDecorFrame(), 0, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
+ }
+
+ @Test
+ public void addingWindow_doesNotTamperWithSysuiFlags() {
+ mWindow.mAttrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ addWindow(mWindow);
+
+ assertEquals(0, mWindow.mAttrs.systemUiVisibility);
+ assertEquals(0, mWindow.mAttrs.subtreeSystemUiVisibility);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout() {
+ addDisplayCutout();
+
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+ assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_never() {
+ addDisplayCutout();
+
+ mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_layoutFullscreen() {
+ addDisplayCutout();
+
+ mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+ assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+ assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_fullscreen() {
+ addDisplayCutout();
+
+ mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getParentFrame(), STATUS_BAR_HEIGHT, 0);
+ assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_fullscreenInCutout() {
+ addDisplayCutout();
+
+ mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
+ mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getParentFrame(), 0, 0);
+ assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDecorFrame(), 0, 0);
+ assertInsetByTopBottom(mWindow.getDisplayFrameLw(), 0, 0);
+ }
+
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_landscape() {
+ addDisplayCutout();
+ setRotation(ROTATION_90);
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getContentFrameLw(),
+ DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_seascape() {
+ addDisplayCutout();
+ setRotation(ROTATION_270);
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetBy(mWindow.getParentFrame(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
+ assertInsetBy(mWindow.getStableFrameLw(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
+ assertInsetBy(mWindow.getContentFrameLw(),
+ NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
+ assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
+ assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_fullscreen_landscape() {
+ addDisplayCutout();
+ setRotation(ROTATION_90);
+
+ mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetBy(mWindow.getParentFrame(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
+ assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getContentFrameLw(),
+ DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_floatingInScreen() {
+ addDisplayCutout();
+
+ mWindow.mAttrs.flags = FLAG_LAYOUT_IN_SCREEN;
+ mWindow.mAttrs.type = TYPE_APPLICATION_OVERLAY;
+ mWindow.mAttrs.width = DISPLAY_WIDTH;
+ mWindow.mAttrs.height = DISPLAY_HEIGHT;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetByTopBottom(mWindow.getParentFrame(), 0, NAV_BAR_HEIGHT);
+ assertInsetByTopBottom(mWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+ }
+
+ @Test
+ public void layoutWindowLw_withDisplayCutout_fullscreenInCutout_landscape() {
+ addDisplayCutout();
+ setRotation(ROTATION_90);
+
+ mWindow.mAttrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+ addWindow(mWindow);
+
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+ mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+ assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
+ assertInsetBy(mWindow.getStableFrameLw(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getContentFrameLw(),
+ DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
+ assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
+ }
+
+ @Test
+ public void layoutHint_appWindow() {
+ // Initialize DisplayFrames
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+
+ final Rect outFrame = new Rect();
+ final Rect outContentInsets = new Rect();
+ final Rect outStableInsets = new Rect();
+ final Rect outOutsets = new Rect();
+ final DisplayCutout.ParcelableWrapper outDisplayCutout =
+ new DisplayCutout.ParcelableWrapper();
+
+ mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, null, mFrames,
+ false /* floatingStack */, outFrame, outContentInsets, outStableInsets, outOutsets,
+ outDisplayCutout);
+
+ assertThat(outFrame, is(mFrames.mUnrestricted));
+ assertThat(outContentInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
+ assertThat(outStableInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
+ assertThat(outOutsets, is(new Rect()));
+ assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
+ }
+
+ @Test
+ public void layoutHint_appWindowInTask() {
+ // Initialize DisplayFrames
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+
+ final Rect taskBounds = new Rect(100, 100, 200, 200);
+
+ final Rect outFrame = new Rect();
+ final Rect outContentInsets = new Rect();
+ final Rect outStableInsets = new Rect();
+ final Rect outOutsets = new Rect();
+ final DisplayCutout.ParcelableWrapper outDisplayCutout =
+ new DisplayCutout.ParcelableWrapper();
+
+ mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
+ false /* floatingStack */, outFrame, outContentInsets, outStableInsets, outOutsets,
+ outDisplayCutout);
+
+ assertThat(outFrame, is(taskBounds));
+ assertThat(outContentInsets, is(new Rect()));
+ assertThat(outStableInsets, is(new Rect()));
+ assertThat(outOutsets, is(new Rect()));
+ assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
+ }
+
+ @Test
+ public void layoutHint_appWindowInTask_outsideContentFrame() {
+ // Initialize DisplayFrames
+ mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+
+ // Task is in the nav bar area (usually does not happen, but this is similar enough to the
+ // possible overlap with the IME)
+ final Rect taskBounds = new Rect(100, mFrames.mContent.bottom + 1,
+ 200, mFrames.mContent.bottom + 10);
+
+ final Rect outFrame = new Rect();
+ final Rect outContentInsets = new Rect();
+ final Rect outStableInsets = new Rect();
+ final Rect outOutsets = new Rect();
+ final DisplayCutout.ParcelableWrapper outDisplayCutout =
+ new DisplayCutout.ParcelableWrapper();
+
+ mDisplayPolicy.getLayoutHintLw(mWindow.mAttrs, taskBounds, mFrames,
+ true /* floatingStack */, outFrame, outContentInsets, outStableInsets, outOutsets,
+ outDisplayCutout);
+
+ assertThat(outFrame, is(taskBounds));
+ assertThat(outContentInsets, is(new Rect()));
+ assertThat(outStableInsets, is(new Rect()));
+ assertThat(outOutsets, is(new Rect()));
+ assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
+ }
+
+ /**
+ * Asserts that {@code actual} is inset by the given amounts from the full display rect.
+ *
+ * Convenience wrapper for when only the top and bottom inset are non-zero.
+ */
+ private void assertInsetByTopBottom(Rect actual, int expectedInsetTop,
+ int expectedInsetBottom) {
+ assertInsetBy(actual, 0, expectedInsetTop, 0, expectedInsetBottom);
+ }
+
+ /** Asserts that {@code actual} is inset by the given amounts from the full display rect. */
+ private void assertInsetBy(Rect actual, int expectedInsetLeft, int expectedInsetTop,
+ int expectedInsetRight, int expectedInsetBottom) {
+ assertEquals(new Rect(expectedInsetLeft, expectedInsetTop,
+ mFrames.mDisplayWidth - expectedInsetRight,
+ mFrames.mDisplayHeight - expectedInsetBottom), actual);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayPolicyTests.java
new file mode 100644
index 0000000..07d5fea
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
+import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.graphics.PixelFormat;
+import android.platform.test.annotations.Presubmit;
+import android.view.WindowManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class DisplayPolicyTests extends WindowTestsBase {
+
+ private WindowState createOpaqueFullscreen(boolean hasLightNavBar) {
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, "opaqueFullscreen");
+ final WindowManager.LayoutParams attrs = win.mAttrs;
+ attrs.width = MATCH_PARENT;
+ attrs.height = MATCH_PARENT;
+ attrs.flags =
+ FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+ attrs.format = PixelFormat.OPAQUE;
+ attrs.systemUiVisibility = attrs.subtreeSystemUiVisibility = win.mSystemUiVisibility =
+ hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0;
+ return win;
+ }
+
+ private WindowState createDimmingDialogWindow(boolean canBeImTarget) {
+ final WindowState win = spy(createWindow(null, TYPE_APPLICATION, "dimmingDialog"));
+ final WindowManager.LayoutParams attrs = win.mAttrs;
+ attrs.width = WRAP_CONTENT;
+ attrs.height = WRAP_CONTENT;
+ attrs.flags = FLAG_DIM_BEHIND | (canBeImTarget ? 0 : FLAG_ALT_FOCUSABLE_IM);
+ attrs.format = PixelFormat.TRANSLUCENT;
+ when(win.isDimming()).thenReturn(true);
+ return win;
+ }
+
+ private WindowState createInputMethodWindow(boolean visible, boolean drawNavBar,
+ boolean hasLightNavBar) {
+ final WindowState win = createWindow(null, TYPE_INPUT_METHOD, "inputMethod");
+ final WindowManager.LayoutParams attrs = win.mAttrs;
+ attrs.width = MATCH_PARENT;
+ attrs.height = MATCH_PARENT;
+ attrs.flags = FLAG_NOT_FOCUSABLE | FLAG_LAYOUT_IN_SCREEN
+ | (drawNavBar ? FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS : 0);
+ attrs.format = PixelFormat.TRANSPARENT;
+ attrs.systemUiVisibility = attrs.subtreeSystemUiVisibility = win.mSystemUiVisibility =
+ hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0;
+ win.mHasSurface = visible;
+ return win;
+ }
+
+ @Test
+ public void testChooseNavigationColorWindowLw() {
+ final WindowState opaque = createOpaqueFullscreen(false);
+
+ final WindowState dimmingImTarget = createDimmingDialogWindow(true);
+ final WindowState dimmingNonImTarget = createDimmingDialogWindow(false);
+
+ final WindowState visibleIme = createInputMethodWindow(true, true, false);
+ final WindowState invisibleIme = createInputMethodWindow(false, true, false);
+ final WindowState imeNonDrawNavBar = createInputMethodWindow(true, false, false);
+
+ // If everything is null, return null
+ assertNull(null, DisplayPolicy.chooseNavigationColorWindowLw(
+ null, null, null, NAV_BAR_BOTTOM));
+
+ assertEquals(opaque, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, opaque, null, NAV_BAR_BOTTOM));
+ assertEquals(dimmingImTarget, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, dimmingImTarget, null, NAV_BAR_BOTTOM));
+ assertEquals(dimmingNonImTarget, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, dimmingNonImTarget, null, NAV_BAR_BOTTOM));
+
+ assertEquals(visibleIme, DisplayPolicy.chooseNavigationColorWindowLw(
+ null, null, visibleIme, NAV_BAR_BOTTOM));
+ assertEquals(visibleIme, DisplayPolicy.chooseNavigationColorWindowLw(
+ null, dimmingImTarget, visibleIme, NAV_BAR_BOTTOM));
+ assertEquals(dimmingNonImTarget, DisplayPolicy.chooseNavigationColorWindowLw(
+ null, dimmingNonImTarget, visibleIme, NAV_BAR_BOTTOM));
+ assertEquals(visibleIme, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, opaque, visibleIme, NAV_BAR_BOTTOM));
+ assertEquals(visibleIme, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, dimmingImTarget, visibleIme, NAV_BAR_BOTTOM));
+ assertEquals(dimmingNonImTarget, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, dimmingNonImTarget, visibleIme, NAV_BAR_BOTTOM));
+
+ assertEquals(opaque, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, opaque, invisibleIme, NAV_BAR_BOTTOM));
+ assertEquals(opaque, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, opaque, invisibleIme, NAV_BAR_BOTTOM));
+ assertEquals(opaque, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, opaque, visibleIme, NAV_BAR_RIGHT));
+
+ // Only IME windows that have FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS should be navigation color
+ // window.
+ assertEquals(opaque, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, opaque, imeNonDrawNavBar, NAV_BAR_BOTTOM));
+ assertEquals(dimmingImTarget, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, dimmingImTarget, imeNonDrawNavBar, NAV_BAR_BOTTOM));
+ assertEquals(dimmingNonImTarget, DisplayPolicy.chooseNavigationColorWindowLw(
+ opaque, dimmingNonImTarget, imeNonDrawNavBar, NAV_BAR_BOTTOM));
+ }
+
+ @Test
+ public void testUpdateLightNavigationBarLw() {
+ final WindowState opaqueDarkNavBar = createOpaqueFullscreen(false);
+ final WindowState opaqueLightNavBar = createOpaqueFullscreen(true);
+
+ final WindowState dimming = createDimmingDialogWindow(false);
+
+ final WindowState imeDrawDarkNavBar = createInputMethodWindow(true, true, false);
+ final WindowState imeDrawLightNavBar = createInputMethodWindow(true, true, true);
+
+ assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+ DisplayPolicy.updateLightNavigationBarLw(
+ SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null,
+ null, null));
+
+ // Opaque top fullscreen window overrides SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR flag.
+ assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ 0, opaqueDarkNavBar, opaqueDarkNavBar, null, opaqueDarkNavBar));
+ assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, opaqueDarkNavBar, null,
+ opaqueDarkNavBar));
+ assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+ DisplayPolicy.updateLightNavigationBarLw(0, opaqueLightNavBar,
+ opaqueLightNavBar, null, opaqueLightNavBar));
+ assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+ DisplayPolicy.updateLightNavigationBarLw(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+ opaqueLightNavBar, opaqueLightNavBar, null, opaqueLightNavBar));
+
+ // Dimming window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.
+ assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ 0, opaqueDarkNavBar, dimming, null, dimming));
+ assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ 0, opaqueLightNavBar, dimming, null, dimming));
+ assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, dimming, null, dimming));
+ assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, null, dimming));
+ assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, imeDrawLightNavBar,
+ dimming));
+
+ // IME window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
+ assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null, imeDrawDarkNavBar,
+ imeDrawDarkNavBar));
+
+ // Even if the top fullscreen has SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, IME window wins.
+ assertEquals(0, DisplayPolicy.updateLightNavigationBarLw(
+ SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, opaqueLightNavBar,
+ imeDrawDarkNavBar, imeDrawDarkNavBar));
+
+ // IME window should be able to use SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.
+ assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
+ DisplayPolicy.updateLightNavigationBarLw(0, opaqueDarkNavBar,
+ opaqueDarkNavBar, imeDrawLightNavBar, imeDrawLightNavBar));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/DisplayPolicyTestsBase.java
new file mode 100644
index 0000000..1d63c57
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM;
+import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
+import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT;
+import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static com.android.server.wm.utils.CoordinateTransforms.transformPhysicalToLogicalCoordinates;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.os.IBinder;
+import android.testing.TestableResources;
+import android.util.Pair;
+import android.view.DisplayCutout;
+import android.view.DisplayInfo;
+import android.view.Gravity;
+import android.view.View;
+import android.view.WindowManagerGlobal;
+
+import com.android.internal.R;
+import com.android.server.wm.utils.WmDisplayCutout;
+
+import org.junit.Before;
+
+public class DisplayPolicyTestsBase extends WindowTestsBase {
+
+ static final int DISPLAY_WIDTH = 500;
+ static final int DISPLAY_HEIGHT = 1000;
+ static final int DISPLAY_DENSITY = 320;
+
+ static final int STATUS_BAR_HEIGHT = 10;
+ static final int NAV_BAR_HEIGHT = 15;
+ static final int DISPLAY_CUTOUT_HEIGHT = 8;
+
+ DisplayPolicy mDisplayPolicy;
+
+ @Before
+ public void setUpBase() {
+ super.setUpBase();
+ mDisplayPolicy = spy(mDisplayContent.getDisplayPolicy());
+
+ final TestContextWrapper context =
+ new TestContextWrapper(mDisplayPolicy.getSystemUiContext());
+ final TestableResources resources = context.getResourceMocker();
+ resources.addOverride(R.dimen.status_bar_height_portrait, STATUS_BAR_HEIGHT);
+ resources.addOverride(R.dimen.status_bar_height_landscape, STATUS_BAR_HEIGHT);
+ resources.addOverride(R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
+ resources.addOverride(R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT);
+ resources.addOverride(R.dimen.navigation_bar_width, NAV_BAR_HEIGHT);
+ when(mDisplayPolicy.getSystemUiContext()).thenReturn(context);
+ when(mDisplayPolicy.hasNavigationBar()).thenReturn(true);
+
+ final int shortSizeDp =
+ Math.min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * DENSITY_DEFAULT / DISPLAY_DENSITY;
+ final int longSizeDp =
+ Math.min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * DENSITY_DEFAULT / DISPLAY_DENSITY;
+ mDisplayContent.getDisplayRotation().configure(
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, shortSizeDp, longSizeDp);
+ mDisplayPolicy.configure(DISPLAY_WIDTH, DISPLAY_HEIGHT, shortSizeDp);
+ mDisplayPolicy.onConfigurationChanged();
+
+ mStatusBarWindow.mAttrs.gravity = Gravity.TOP;
+ addWindow(mStatusBarWindow);
+ mDisplayPolicy.mLastSystemUiFlags |= View.STATUS_BAR_TRANSPARENT;
+
+ mNavBarWindow.mAttrs.gravity = Gravity.BOTTOM;
+ addWindow(mNavBarWindow);
+ mDisplayPolicy.mLastSystemUiFlags |= View.NAVIGATION_BAR_TRANSPARENT;
+ }
+
+ void addWindow(WindowState win) {
+ mDisplayPolicy.adjustWindowParamsLw(win, win.mAttrs, true /* hasStatusBarPermission */);
+ assertEquals(WindowManagerGlobal.ADD_OKAY,
+ mDisplayPolicy.prepareAddWindowLw(win, win.mAttrs));
+ win.mHasSurface = true;
+ }
+
+ static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation,
+ boolean withDisplayCutout) {
+ final DisplayInfo info = new DisplayInfo();
+ WmDisplayCutout cutout = null;
+
+ final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
+ info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
+ info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
+ info.rotation = rotation;
+ if (withDisplayCutout) {
+ cutout = WmDisplayCutout.computeSafeInsets(
+ displayCutoutForRotation(rotation), info.logicalWidth,
+ info.logicalHeight);
+ info.displayCutout = cutout.getDisplayCutout();
+ } else {
+ info.displayCutout = null;
+ }
+ return Pair.create(info, cutout);
+ }
+
+ private static DisplayCutout displayCutoutForRotation(int rotation) {
+ final RectF rectF =
+ new RectF(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT);
+
+ final Matrix m = new Matrix();
+ transformPhysicalToLogicalCoordinates(rotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, m);
+ m.mapRect(rectF);
+
+ int pos = -1;
+ switch (rotation) {
+ case ROTATION_0:
+ pos = BOUNDS_POSITION_TOP;
+ break;
+ case ROTATION_90:
+ pos = BOUNDS_POSITION_LEFT;
+ break;
+ case ROTATION_180:
+ pos = BOUNDS_POSITION_BOTTOM;
+ break;
+ case ROTATION_270:
+ pos = BOUNDS_POSITION_RIGHT;
+ break;
+ }
+
+ return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top,
+ (int) rectF.right, (int) rectF.bottom, pos);
+ }
+
+ static class TestContextWrapper extends ContextWrapper {
+ private final TestableResources mResourceMocker;
+
+ TestContextWrapper(Context targetContext) {
+ super(targetContext);
+ mResourceMocker = new TestableResources(targetContext.getResources());
+ }
+
+ @Override
+ public int checkPermission(String permission, int pid, int uid) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+
+ @Override
+ public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
+ return PackageManager.PERMISSION_GRANTED;
+ }
+
+ @Override
+ public Resources getResources() {
+ return mResourceMocker.getResources();
+ }
+
+ TestableResources getResourceMocker() {
+ return mResourceMocker;
+ }
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DockedStackDividerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DockedStackDividerControllerTests.java
new file mode 100644
index 0000000..a04bf16
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/DockedStackDividerControllerTests.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class DockedStackDividerControllerTests {
+
+ @Test
+ public void testIsDockSideAllowedDockTop() {
+ // Docked top is always allowed
+ assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT,
+ NAV_BAR_BOTTOM, true /* navigationBarCanMove */));
+ assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT,
+ NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
+ }
+
+ @Test
+ public void testIsDockSideAllowedDockBottom() {
+ // Cannot dock bottom
+ assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_BOTTOM, DOCKED_LEFT,
+ NAV_BAR_BOTTOM, true /* navigationBarCanMove */));
+ }
+
+ @Test
+ public void testIsDockSideAllowedNavigationBarMovable() {
+ assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT,
+ NAV_BAR_BOTTOM, true /* navigationBarCanMove */));
+ assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT,
+ NAV_BAR_LEFT, true /* navigationBarCanMove */));
+ assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT,
+ NAV_BAR_RIGHT, true /* navigationBarCanMove */));
+ assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT,
+ NAV_BAR_BOTTOM, true /* navigationBarCanMove */));
+ assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT,
+ NAV_BAR_RIGHT, true /* navigationBarCanMove */));
+ assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT,
+ NAV_BAR_LEFT, true /* navigationBarCanMove */));
+ }
+
+ @Test
+ public void testIsDockSideAllowedNavigationBarNotMovable() {
+ // Navigation bar is not movable such as tablets
+ assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT,
+ NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
+ assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_TOP,
+ NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
+ assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_LEFT, DOCKED_RIGHT,
+ NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
+ assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT,
+ NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
+ assertFalse(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_TOP,
+ NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
+ assertTrue(DockedStackDividerController.isDockSideAllowed(DOCKED_RIGHT, DOCKED_RIGHT,
+ NAV_BAR_BOTTOM, false /* navigationBarCanMove */));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index fe5fc06..ee3bba7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -123,6 +123,8 @@
final AppWindowToken hiddenAppWindow = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
hiddenAppWindow.setHidden(true);
+ mDisplayContent.getConfiguration().windowConfiguration.setRotation(
+ mDisplayContent.getRotation());
mController.initialize(mDisplayContent, ACTIVITY_TYPE_HOME, new SparseBooleanArray());
// Ensure that we are animating the target activity as well
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 0165e7d..7b542cb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -26,12 +26,10 @@
import android.content.Context;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
-import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.proto.ProtoOutputStream;
-import android.view.DisplayCutout;
import android.view.IWindow;
import android.view.IWindowManager;
import android.view.KeyEvent;
@@ -48,7 +46,6 @@
class TestWindowManagerPolicy implements WindowManagerPolicy {
private final Supplier<WindowManagerService> mWmSupplier;
- int rotationToReport = 0;
boolean keyguardShowingAndNotOccluded = false;
private Runnable mRunnableWhenAddingSplashScreen;
@@ -81,11 +78,6 @@
}
@Override
- public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
- boolean hasStatusBarServicePermission) {
- }
-
- @Override
public void adjustConfigurationLw(Configuration config, int keyboardPresence,
int navigationPresence) {
}
@@ -96,30 +88,6 @@
}
@Override
- public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
- int displayId, DisplayCutout displayCutout) {
- return 0;
- }
-
- @Override
- public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
- int displayId, DisplayCutout displayCutout) {
- return 0;
- }
-
- @Override
- public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
- int displayId, DisplayCutout displayCutout) {
- return 0;
- }
-
- @Override
- public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
- int displayId, DisplayCutout displayCutout) {
- return 0;
- }
-
- @Override
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
return attrs.type == TYPE_STATUS_BAR;
}
@@ -166,28 +134,7 @@
}
@Override
- public int prepareAddWindowLw(WindowState win,
- WindowManager.LayoutParams attrs) {
- return 0;
- }
-
- @Override
- public void removeWindowLw(WindowState win) {
- }
-
- @Override
- public int selectAnimationLw(WindowState win, int transit) {
- return 0;
- }
-
- @Override
- public void selectRotationAnimationLw(int[] anim) {
- }
-
- @Override
- public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
- boolean forceDefault) {
- return false;
+ public void setKeyguardCandidateLw(WindowState win) {
}
@Override
@@ -222,32 +169,11 @@
}
@Override
- public int getSystemDecorLayerLw() {
- return 0;
+ public void applyKeyguardPolicyLw(WindowState win, WindowState imeTarget) {
}
@Override
- public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
- }
-
- @Override
- public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
- WindowState attached, WindowState imeTarget) {
- }
-
- @Override
- public int finishPostLayoutPolicyLw() {
- return 0;
- }
-
- @Override
- public boolean allowAppAnimationsLw() {
- return false;
- }
-
- @Override
- public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
- return 0;
+ public void setAllowLockscreenWhenOn(int displayId, boolean allow) {
}
@Override
@@ -349,11 +275,6 @@
}
@Override
- public boolean isShowingDreamLw() {
- return false;
- }
-
- @Override
public void onKeyguardOccludedChangedLw(boolean occluded) {
}
@@ -399,11 +320,6 @@
}
@Override
- public int adjustSystemUiVisibilityLw(int visibility) {
- return 0;
- }
-
- @Override
public boolean hasNavigationBar() {
return false;
}
@@ -421,6 +337,16 @@
}
@Override
+ public boolean isUserSetupComplete() {
+ return false;
+ }
+
+ @Override
+ public int getUiMode() {
+ return 0;
+ }
+
+ @Override
public void setCurrentUserLw(int newUserId) {
}
@@ -446,43 +372,6 @@
}
@Override
- public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
- DisplayCutout cutout, Rect outInsets) {
- }
-
- @Override
- public boolean isNavBarForcedShownLw(WindowState win) {
- return false;
- }
-
- @NavigationBarPosition
- @Override
- public int getNavBarPosition() {
- return NAV_BAR_BOTTOM;
- }
-
- @Override
- public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
- DisplayCutout cutout, Rect outInsets) {
- }
-
- @Override
- public boolean isDockSideAllowed(int dockSide, int originalDockSide, int displayWidth,
- int displayHeight, int displayRotation) {
- return false;
- }
-
- @Override
- public void onConfigurationChanged(DisplayContentInfo displayContentInfo) {
- }
-
- @Override
- public boolean shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation,
- int newRotation) {
- return false;
- }
-
- @Override
public void setPipVisibilityLw(boolean visible) {
}
@@ -508,10 +397,6 @@
}
@Override
- public void onLockTaskStateChangedLw(int lockTaskState) {
- }
-
- @Override
public boolean setAodShowing(boolean aodShowing) {
return false;
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index b0c8d8b..227eb00 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -113,9 +113,6 @@
@Before
public void setUp() throws Exception {
- // Just any non zero value.
- mWm.mSystemDecorLayer = 10000;
-
mWindowToken = WindowTestUtils.createTestAppWindowToken(
mWm.getDefaultDisplayContentLocked());
mStubStack = new TaskStack(mWm, 0, null);
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index d6fea09..60c0459 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -28,19 +28,15 @@
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.content.ComponentName;
-import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
-import android.view.Display;
import android.view.IApplicationToken;
import android.view.IWindow;
-import android.view.Surface;
import android.view.SurfaceControl.Transaction;
import android.view.WindowManager;
@@ -53,37 +49,6 @@
public class WindowTestUtils {
private static int sNextTaskId = 0;
- /** An extension of {@link DisplayContent} to gain package scoped access. */
- public static class TestDisplayContent extends DisplayContent {
-
- private TestDisplayContent(Display display, WindowManagerService service,
- DisplayWindowController controller) {
- super(display, service, controller);
- }
-
- /** Create a mocked default {@link DisplayContent}. */
- public static TestDisplayContent create(Context context) {
- final TestDisplayContent displayContent = mock(TestDisplayContent.class);
- displayContent.isDefaultDisplay = true;
-
- final DisplayPolicy displayPolicy = mock(DisplayPolicy.class);
- when(displayPolicy.navigationBarCanMove()).thenReturn(true);
- when(displayPolicy.hasNavigationBar()).thenReturn(true);
-
- final DisplayRotation displayRotation = new DisplayRotation(
- mock(WindowManagerService.class), displayContent, displayPolicy,
- context, new Object());
- displayRotation.mPortraitRotation = Surface.ROTATION_0;
- displayRotation.mLandscapeRotation = Surface.ROTATION_90;
- displayRotation.mUpsideDownRotation = Surface.ROTATION_180;
- displayRotation.mSeascapeRotation = Surface.ROTATION_270;
-
- when(displayContent.getDisplayRotation()).thenReturn(displayRotation);
-
- return displayContent;
- }
- }
-
/**
* Creates a mock instance of {@link StackWindowController}.
*/
diff --git a/services/tests/servicestests/test-apps/Android.mk b/services/tests/servicestests/test-apps/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/services/tests/servicestests/test-apps/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/Android.bp b/services/tests/servicestests/test-apps/ConnTestApp/Android.bp
new file mode 100644
index 0000000..13e6644
--- /dev/null
+++ b/services/tests/servicestests/test-apps/ConnTestApp/Android.bp
@@ -0,0 +1,31 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "ConnTestApp",
+
+ test_suites: ["device-tests"],
+
+ static_libs: ["servicestests-aidl"],
+ srcs: ["**/*.java"],
+
+ platform_apis: true,
+ certificate: "platform",
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
deleted file mode 100644
index 18b8c2d..0000000
--- a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := servicestests-aidl
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := ConnTestApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/JobTestApp/Android.bp b/services/tests/servicestests/test-apps/JobTestApp/Android.bp
new file mode 100644
index 0000000..ae1eca7
--- /dev/null
+++ b/services/tests/servicestests/test-apps/JobTestApp/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "JobTestApp",
+
+ sdk_version: "current",
+
+ test_suites: ["device-tests"],
+
+ srcs: ["**/*.java"],
+
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/services/tests/servicestests/test-apps/JobTestApp/Android.mk b/services/tests/servicestests/test-apps/JobTestApp/Android.mk
deleted file mode 100644
index 7893c91..0000000
--- a/services/tests/servicestests/test-apps/JobTestApp/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := JobTestApp
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/Android.bp b/services/tests/servicestests/test-apps/SuspendTestApp/Android.bp
new file mode 100644
index 0000000..7257275
--- /dev/null
+++ b/services/tests/servicestests/test-apps/SuspendTestApp/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test_helper_app {
+ name: "SuspendTestApp",
+
+ test_suites: ["device-tests"],
+
+ static_libs: [
+ "androidx.test.runner",
+ "ub-uiautomator",
+ ],
+
+ srcs: [
+ "**/*.java",
+ ":servicestests-SuspendTestApp-files",
+ ],
+
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+
+ platform_apis: true,
+
+}
diff --git a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk b/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
deleted file mode 100644
index ab222b9..0000000
--- a/services/tests/servicestests/test-apps/SuspendTestApp/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.runner ub-uiautomator
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_SRC_FILES += ../../src/com/android/server/pm/SuspendPackagesTest.java
-
-LOCAL_PACKAGE_NAME := SuspendTestApp
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
\ No newline at end of file
diff --git a/services/tests/shortcutmanagerutils/Android.bp b/services/tests/shortcutmanagerutils/Android.bp
new file mode 100644
index 0000000..c2cb6881
--- /dev/null
+++ b/services/tests/shortcutmanagerutils/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_library {
+ name: "ShortcutManagerTestUtils",
+
+ srcs: ["src/**/*.java"],
+
+ libs: [
+ "mockito-target",
+ "android.test.runner.stubs",
+ ],
+
+ sdk_version: "test_current",
+}
diff --git a/services/tests/shortcutmanagerutils/Android.mk b/services/tests/shortcutmanagerutils/Android.mk
deleted file mode 100644
index 019bcbd3..0000000
--- a/services/tests/shortcutmanagerutils/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := \
- mockito-target \
- android.test.runner.stubs
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := ShortcutManagerTestUtils
-
-LOCAL_SDK_VERSION := test_current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
new file mode 100644
index 0000000..ca8cc0d
--- /dev/null
+++ b/services/tests/uiservicestests/Android.bp
@@ -0,0 +1,58 @@
+//########################################################################
+// Build FrameworksUiServicesTests package
+//########################################################################
+
+android_test {
+ name: "FrameworksUiServicesTests",
+
+ // Include test java files
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ static_libs: [
+ "services.accessibility",
+ "services.core",
+ "services.devicepolicy",
+ "services.net",
+ "services.usage",
+ "guava",
+ "android-support-test",
+ "mockito-target-inline-minus-junit4",
+ "platform-test-annotations",
+ "testables",
+ ],
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+
+ dxflags: ["--multi-dex"],
+
+ platform_apis: true,
+ test_suites: ["device-tests"],
+
+ certificate: "platform",
+
+ compile_multilib: "both",
+
+ // These are not normally accessible from apps so they must be explicitly included.
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libmultiplejvmtiagentsinterferenceagent",
+ "libbacktrace",
+ "libbase",
+ "libbinder",
+ "libbinderthreadstate",
+ "libc++",
+ "libcutils",
+ "liblog",
+ "liblzma",
+ "libnativehelper",
+ "libnetdaidl",
+ "libui",
+ "libunwindstack",
+ "libutils",
+ ],
+}
diff --git a/services/tests/uiservicestests/Android.mk b/services/tests/uiservicestests/Android.mk
deleted file mode 100644
index f3f4355..0000000
--- a/services/tests/uiservicestests/Android.mk
+++ /dev/null
@@ -1,61 +0,0 @@
-#########################################################################
-# Build FrameworksUiServicesTests package
-#########################################################################
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include test java files and source from notifications package.
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- $(call all-java-files-under, ../../core/java/com/android/server/notification) \
- $(call all-java-files-under, ../../core/java/com/android/server/slice) \
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- services.accessibility \
- services.core \
- services.devicepolicy \
- services.net \
- services.usage \
- guava \
- android-support-test \
- mockito-target-inline-minus-junit4 \
- platform-test-annotations \
- testables
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_DX_FLAGS := --multi-dex
-
-LOCAL_PACKAGE_NAME := FrameworksUiServicesTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_CERTIFICATE := platform
-
-LOCAL_MULTILIB := both
-
-# These are not normally accessible from apps so they must be explicitly included.
-LOCAL_JNI_SHARED_LIBRARIES := \
- libdexmakerjvmtiagent \
- libmultiplejvmtiagentsinterferenceagent \
- libbacktrace \
- libbase \
- libbinder \
- libbinderthreadstate \
- libc++ \
- libcutils \
- liblog \
- liblzma \
- libnativehelper \
- libnetdaidl \
- libui \
- libunwindstack \
- libutils
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-include $(BUILD_PACKAGE)
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 3266b8b..f11492a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -38,10 +38,8 @@
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.os.Build.VERSION_CODES.O_MR1;
import static android.os.Build.VERSION_CODES.P;
-import static android.service.notification.NotificationListenerService.Ranking
- .USER_SENTIMENT_NEGATIVE;
-import static android.service.notification.NotificationListenerService.Ranking
- .USER_SENTIMENT_NEUTRAL;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -68,16 +66,15 @@
import android.app.ActivityManager;
import android.app.AppOpsManager;
-import android.app.Application;
import android.app.IActivityManager;
import android.app.INotificationManager;
+import android.app.ITransientNotification;
+import android.app.IUriGrantsManager;
import android.app.Notification;
import android.app.Notification.MessagingStyle.Message;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
-import android.app.ITransientNotification;
-import android.app.IUriGrantsManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.usage.UsageStatsManagerInternal;
import android.companion.ICompanionDeviceManager;
@@ -100,7 +97,6 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.os.UserManager;
import android.provider.MediaStore;
import android.provider.Settings.Secure;
import android.service.notification.Adjustment;
@@ -116,7 +112,6 @@
import android.text.Html;
import android.util.ArrayMap;
import android.util.AtomicFile;
-import android.util.Log;
import com.android.internal.R;
import com.android.internal.statusbar.NotificationVisibility;
@@ -288,6 +283,7 @@
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
+ when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG});
// write to a test file; the system file isn't readable from tests
mFile = new File(mContext.getCacheDir(), "test.xml");
@@ -1735,7 +1731,8 @@
}
@Test
- public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess() throws Exception {
+ public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()
+ throws Exception {
mService.setPreferencesHelper(mPreferencesHelper);
when(mCompanionMgr.getAssociations(PKG, mUid)).thenReturn(new ArrayList<>());
when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false);
@@ -2509,6 +2506,7 @@
mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey());
assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied());
+ verify(mAssistants).notifyAssistantNotificationDirectReplyLocked(eq(r.sbn));
}
@Test
@@ -2517,8 +2515,11 @@
mService.addNotification(r);
mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, true);
+ verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.sbn), eq(true), eq((true)));
assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
+
mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, false);
+ verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.sbn), eq(true), eq((false)));
assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
}
@@ -2529,8 +2530,12 @@
mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true);
assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
+ verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.sbn), eq(false), eq((true)));
+
mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, false);
assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded());
+ verify(mAssistants).notifyAssistantExpansionChangedLocked(
+ eq(r.sbn), eq(false), eq((false)));
}
@Test
@@ -3459,11 +3464,12 @@
ApplicationInfo info = new ApplicationInfo();
info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(info);
+ when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
- assertTrue(mService.isCallerInstantApp("any", 45770, 0));
+ assertTrue(mService.isCallerInstantApp(45770, 0));
info.privateFlags = 0;
- assertFalse(mService.isCallerInstantApp("any", 575370, 0));
+ assertFalse(mService.isCallerInstantApp(575370, 0));
}
@Test
@@ -3472,8 +3478,9 @@
info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT;
when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(10))).thenReturn(info);
when(mPackageManager.getApplicationInfo(anyString(), anyInt(), eq(0))).thenReturn(null);
+ when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"});
- assertTrue(mService.isCallerInstantApp("any", 68638450, 10));
+ assertTrue(mService.isCallerInstantApp(68638450, 10));
}
@Test
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
new file mode 100644
index 0000000..cdba9a1
--- /dev/null
+++ b/services/tests/wmtests/Android.bp
@@ -0,0 +1,52 @@
+//########################################################################
+// Build WmTests package
+//########################################################################
+
+android_test {
+ name: "WmTests",
+
+ // We only want this apk build for tests.
+
+ // Include all test java files.
+ srcs: [
+ "src/**/*.java",
+ ],
+
+ static_libs: [
+ "frameworks-base-testutils",
+ "services.core",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "mockito-target-extended-minus-junit4",
+ "platform-test-annotations",
+ "servicestests-utils",
+ "truth-prebuilt",
+ "testables",
+ "ub-uiautomator",
+ "hamcrest-library",
+ ],
+
+ libs: [
+ "android.test.mock",
+ "android.test.base",
+ "android.test.runner",
+ ],
+
+ // These are not normally accessible from apps so they must be explicitly included.
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+
+ platform_apis: true,
+ test_suites: ["device-tests"],
+
+ certificate: "platform",
+
+ dxflags: ["--multi-dex"],
+
+ optimize: {
+ enabled: false,
+ },
+
+}
diff --git a/services/tests/wmtests/Android.mk b/services/tests/wmtests/Android.mk
deleted file mode 100644
index 67c2860..0000000
--- a/services/tests/wmtests/Android.mk
+++ /dev/null
@@ -1,53 +0,0 @@
-#########################################################################
-# Build WmTests package
-#########################################################################
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-java-files-under, ../servicestests/utils) \
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- frameworks-base-testutils \
- services.core \
- androidx.test.runner \
- androidx.test.rules \
- mockito-target-extended-minus-junit4 \
- platform-test-annotations \
- truth-prebuilt \
- testables \
- ub-uiautomator \
- hamcrest-library
-
-LOCAL_JAVA_LIBRARIES := \
- android.test.mock \
- android.test.base \
- android.test.runner \
-
-# These are not normally accessible from apps so they must be explicitly included.
-LOCAL_JNI_SHARED_LIBRARIES := \
- libdexmakerjvmtiagent \
- libstaticjvmtiagent \
-
-LOCAL_PACKAGE_NAME := WmTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_CERTIFICATE := platform
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_DX_FLAGS := --multi-dex
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/tests/wmtests/src/com/android/server/policy/FakeWindowState.java b/services/tests/wmtests/src/com/android/server/policy/FakeWindowState.java
deleted file mode 100644
index d4f2b06..0000000
--- a/services/tests/wmtests/src/com/android/server/policy/FakeWindowState.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.policy;
-
-import android.graphics.Rect;
-import android.util.proto.ProtoOutputStream;
-import android.view.Display;
-import android.view.IApplicationToken;
-import android.view.WindowManager;
-
-import com.android.server.wm.WindowFrames;
-
-public class FakeWindowState implements WindowManagerPolicy.WindowState {
-
- private WindowFrames mWindowFrames = new WindowFrames();
-
- public WindowManager.LayoutParams attrs;
- public int displayId;
- public boolean isVoiceInteraction;
- public boolean inMultiWindowMode;
- public boolean visible = true;
- public int surfaceLayer = 1;
- public boolean isDimming = false;
-
- public boolean policyVisible = true;
-
- @Override
- public int getOwningUid() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public String getOwningPackage() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public void computeFrameLw() {
- }
-
- @Override
- public Rect getFrameLw() {
- return mWindowFrames.mParentFrame;
- }
-
- @Override
- public Rect getDisplayFrameLw() {
- return mWindowFrames.mDisplayFrame;
- }
-
- @Override
- public Rect getOverscanFrameLw() {
- return mWindowFrames.mOverscanFrame;
- }
-
- @Override
- public Rect getContentFrameLw() {
- return mWindowFrames.mContentFrame;
- }
-
- @Override
- public Rect getVisibleFrameLw() {
- return mWindowFrames.mVisibleFrame;
- }
-
- public Rect getStableFrame() {
- return mWindowFrames.mStableFrame;
- }
-
- public Rect getDecorFrame() {
- return mWindowFrames.mDecorFrame;
- }
-
- @Override
- public boolean getGivenInsetsPendingLw() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public Rect getGivenContentInsetsLw() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public Rect getGivenVisibleInsetsLw() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public WindowManager.LayoutParams getAttrs() {
- return attrs;
- }
-
- @Override
- public boolean getNeedsMenuLw(WindowManagerPolicy.WindowState bottom) {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public int getSystemUiVisibility() {
- return attrs.systemUiVisibility | attrs.subtreeSystemUiVisibility;
- }
-
- @Override
- public int getSurfaceLayer() {
- return surfaceLayer;
- }
-
- @Override
- public int getBaseType() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public IApplicationToken getAppToken() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public boolean isVoiceInteraction() {
- return isVoiceInteraction;
- }
-
- @Override
- public boolean hasAppShownWindows() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public boolean isVisibleLw() {
- return visible && policyVisible;
- }
-
- @Override
- public boolean isDisplayedLw() {
- return isVisibleLw();
- }
-
- @Override
- public boolean isAnimatingLw() {
- return false;
- }
-
- @Override
- public boolean canAffectSystemUiFlags() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public boolean isGoneForLayoutLw() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public boolean isDrawnLw() {
- return true;
- }
-
- @Override
- public boolean hasDrawnLw() {
- return true;
- }
-
- @Override
- public boolean hideLw(boolean doAnimation) {
- if (!policyVisible) {
- return false;
- }
- policyVisible = false;
- return true;
- }
-
- @Override
- public boolean showLw(boolean doAnimation) {
- if (policyVisible) {
- return false;
- }
- policyVisible = true;
- return true;
- }
-
- @Override
- public boolean isAlive() {
- return true;
- }
-
- @Override
- public boolean isDefaultDisplay() {
- return displayId == Display.DEFAULT_DISPLAY;
- }
-
- @Override
- public boolean isDimming() {
- return isDimming;
- }
-
- @Override
- public int getWindowingMode() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public boolean isInMultiWindowMode() {
- return inMultiWindowMode;
- }
-
- @Override
- public int getRotationAnimationHint() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public boolean isInputMethodWindow() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public int getDisplayId() {
- return displayId;
- }
-
- @Override
- public boolean canAcquireSleepToken() {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public boolean canReceiveKeys() {
- return false;
- }
-
- @Override
- public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
- throw new UnsupportedOperationException("not implemented");
- }
-
- @Override
- public WindowFrames getWindowFrames() {
- return mWindowFrames;
- }
-
- @Override
- public boolean isInputMethodTarget() {
- return false;
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
deleted file mode 100644
index e8f767a..0000000
--- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerLayoutTest.java
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.policy;
-
-import static android.view.Surface.ROTATION_270;
-import static android.view.Surface.ROTATION_90;
-import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
-import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
-
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
-
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-import android.view.DisplayCutout;
-import android.view.WindowManager;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Before;
-import org.junit.Test;
-
-/**
- * Build/Install/Run:
- * atest WmTests:PhoneWindowManagerLayoutTest
- */
-@SmallTest
-@Presubmit
-public class PhoneWindowManagerLayoutTest extends PhoneWindowManagerTestBase {
-
- private FakeWindowState mAppWindow;
-
- @Before
- public void setUp() throws Exception {
- mAppWindow = new FakeWindowState();
- mAppWindow.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT,
- TYPE_APPLICATION,
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
- PixelFormat.TRANSLUCENT);
-
- addStatusBar();
- addNavigationBar();
- }
-
- @Test
- public void layoutWindowLw_appDrawsBars() {
- mAppWindow.attrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetByTopBottom(mAppWindow.getFrameLw(), 0, 0);
- assertInsetByTopBottom(mAppWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getDecorFrame(), 0, 0);
- assertInsetBy(mAppWindow.getDisplayFrameLw(), 0, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_appWontDrawBars() {
- mAppWindow.attrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetByTopBottom(mAppWindow.getFrameLw(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getDecorFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
- }
-
- @Test
- public void layoutWindowLw_appWontDrawBars_forceStatus() {
- mAppWindow.attrs.flags &= ~FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mAppWindow.attrs.privateFlags |= PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetByTopBottom(mAppWindow.getFrameLw(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getDecorFrame(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getDisplayFrameLw(), 0, NAV_BAR_HEIGHT);
- }
-
- @Test
- public void addingWindow_doesNotTamperWithSysuiFlags() {
- mAppWindow.attrs.flags |= FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
- mPolicy.addWindow(mAppWindow);
-
- assertEquals(0, mAppWindow.attrs.systemUiVisibility);
- assertEquals(0, mAppWindow.attrs.subtreeSystemUiVisibility);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout() {
- addDisplayCutout();
-
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetByTopBottom(mAppWindow.getFrameLw(), 0, 0);
- assertInsetByTopBottom(mAppWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mAppWindow.getDisplayFrameLw(), 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withhDisplayCutout_never() {
- addDisplayCutout();
-
- mAppWindow.attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetByTopBottom(mAppWindow.getFrameLw(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mAppWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mAppWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_layoutFullscreen() {
- addDisplayCutout();
-
- mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetByTopBottom(mAppWindow.getFrameLw(), 0, 0);
- assertInsetByTopBottom(mAppWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getDecorFrame(), 0, 0);
- assertInsetBy(mAppWindow.getDisplayFrameLw(), 0, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_fullscreen() {
- addDisplayCutout();
-
- mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetByTopBottom(mAppWindow.getFrameLw(), STATUS_BAR_HEIGHT, 0);
- assertInsetByTopBottom(mAppWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mAppWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_fullscreenInCutout() {
- addDisplayCutout();
-
- mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_FULLSCREEN;
- mAppWindow.attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetByTopBottom(mAppWindow.getFrameLw(), 0, 0);
- assertInsetByTopBottom(mAppWindow.getStableFrame(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getDecorFrame(), 0, 0);
- assertInsetByTopBottom(mAppWindow.getDisplayFrameLw(), 0, 0);
- }
-
-
- @Test
- public void layoutWindowLw_withDisplayCutout_landscape() {
- addDisplayCutout();
- setRotation(ROTATION_90);
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetBy(mAppWindow.getFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mAppWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mAppWindow.getContentFrameLw(),
- DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mAppWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mAppWindow.getDisplayFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_seascape() {
- addDisplayCutout();
- setRotation(ROTATION_270);
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetBy(mAppWindow.getFrameLw(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
- assertInsetBy(mAppWindow.getStableFrame(), NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, 0, 0);
- assertInsetBy(mAppWindow.getContentFrameLw(),
- NAV_BAR_HEIGHT, STATUS_BAR_HEIGHT, DISPLAY_CUTOUT_HEIGHT, 0);
- assertInsetBy(mAppWindow.getDecorFrame(), 0, 0, 0, 0);
- assertInsetBy(mAppWindow.getDisplayFrameLw(), 0, 0, DISPLAY_CUTOUT_HEIGHT, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_fullscreen_landscape() {
- addDisplayCutout();
- setRotation(ROTATION_90);
-
- mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetBy(mAppWindow.getFrameLw(), DISPLAY_CUTOUT_HEIGHT, 0, 0, 0);
- assertInsetBy(mAppWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mAppWindow.getContentFrameLw(),
- DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mAppWindow.getDecorFrame(), 0, 0, 0, 0);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_floatingInScreen() {
- addDisplayCutout();
-
- mAppWindow.attrs.flags = FLAG_LAYOUT_IN_SCREEN;
- mAppWindow.attrs.type = TYPE_APPLICATION_OVERLAY;
- mAppWindow.attrs.width = DISPLAY_WIDTH;
- mAppWindow.attrs.height = DISPLAY_HEIGHT;
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetByTopBottom(mAppWindow.getFrameLw(), 0, NAV_BAR_HEIGHT);
- assertInsetByTopBottom(mAppWindow.getDisplayFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
- }
-
- @Test
- public void layoutWindowLw_withDisplayCutout_fullscreenInCutout_landscape() {
- addDisplayCutout();
- setRotation(ROTATION_90);
-
- mAppWindow.attrs.subtreeSystemUiVisibility |= SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
- mAppWindow.attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- mPolicy.addWindow(mAppWindow);
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
- mPolicy.layoutWindowLw(mAppWindow, null, mFrames);
-
- assertInsetBy(mAppWindow.getFrameLw(), 0, 0, 0, 0);
- assertInsetBy(mAppWindow.getStableFrame(), 0, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mAppWindow.getContentFrameLw(),
- DISPLAY_CUTOUT_HEIGHT, STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT, 0);
- assertInsetBy(mAppWindow.getDecorFrame(), 0, 0, 0, 0);
- }
-
- @Test
- public void layoutHint_screenDecorWindow() {
- addDisplayCutout();
- mAppWindow.attrs.privateFlags |= PRIVATE_FLAG_IS_SCREEN_DECOR;
-
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-
- final Rect frame = new Rect();
- final Rect content = new Rect();
- final Rect stable = new Rect();
- final Rect outsets = new Rect();
- final DisplayCutout.ParcelableWrapper cutout = new DisplayCutout.ParcelableWrapper();
- mPolicy.getLayoutHintLw(mAppWindow.attrs, null /* taskBounds */, mFrames,
- false /* floatingStack */, frame, content, stable, outsets, cutout);
-
- assertThat(frame, equalTo(mFrames.mUnrestricted));
- assertThat(content, equalTo(new Rect()));
- assertThat(stable, equalTo(new Rect()));
- assertThat(outsets, equalTo(new Rect()));
- assertThat(cutout.get(), equalTo(DisplayCutout.NO_CUTOUT));
- }
-
- @Test
- public void layoutHint_appWindow() {
- // Initialize DisplayFrames
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-
- final Rect outFrame = new Rect();
- final Rect outContentInsets = new Rect();
- final Rect outStableInsets = new Rect();
- final Rect outOutsets = new Rect();
- final DisplayCutout.ParcelableWrapper outDisplayCutout =
- new DisplayCutout.ParcelableWrapper();
-
- mPolicy.getLayoutHintLw(mAppWindow.attrs, null, mFrames, false /* floatingStack */,
- outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout);
-
- assertThat(outFrame, is(mFrames.mUnrestricted));
- assertThat(outContentInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
- assertThat(outStableInsets, is(new Rect(0, STATUS_BAR_HEIGHT, 0, NAV_BAR_HEIGHT)));
- assertThat(outOutsets, is(new Rect()));
- assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
- }
-
- @Test
- public void layoutHint_appWindowInTask() {
- // Initialize DisplayFrames
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-
- final Rect taskBounds = new Rect(100, 100, 200, 200);
-
- final Rect outFrame = new Rect();
- final Rect outContentInsets = new Rect();
- final Rect outStableInsets = new Rect();
- final Rect outOutsets = new Rect();
- final DisplayCutout.ParcelableWrapper outDisplayCutout =
- new DisplayCutout.ParcelableWrapper();
-
- mPolicy.getLayoutHintLw(mAppWindow.attrs, taskBounds, mFrames, false /* floatingStack */,
- outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout);
-
- assertThat(outFrame, is(taskBounds));
- assertThat(outContentInsets, is(new Rect()));
- assertThat(outStableInsets, is(new Rect()));
- assertThat(outOutsets, is(new Rect()));
- assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
- }
-
- @Test
- public void layoutHint_appWindowInTask_outsideContentFrame() {
- // Initialize DisplayFrames
- mPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
-
- // Task is in the nav bar area (usually does not happen, but this is similar enough to the
- // possible overlap with the IME)
- final Rect taskBounds = new Rect(100, mFrames.mContent.bottom + 1,
- 200, mFrames.mContent.bottom + 10);
-
- final Rect outFrame = new Rect();
- final Rect outContentInsets = new Rect();
- final Rect outStableInsets = new Rect();
- final Rect outOutsets = new Rect();
- final DisplayCutout.ParcelableWrapper outDisplayCutout =
- new DisplayCutout.ParcelableWrapper();
-
- mPolicy.getLayoutHintLw(mAppWindow.attrs, taskBounds, mFrames, true /* floatingStack */,
- outFrame, outContentInsets, outStableInsets, outOutsets, outDisplayCutout);
-
- assertThat(outFrame, is(taskBounds));
- assertThat(outContentInsets, is(new Rect()));
- assertThat(outStableInsets, is(new Rect()));
- assertThat(outOutsets, is(new Rect()));
- assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTest.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTest.java
deleted file mode 100644
index 6c44d65..0000000
--- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTest.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.policy;
-
-import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
-import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_RIGHT;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import android.graphics.PixelFormat;
-import android.platform.test.annotations.Presubmit;
-import android.view.WindowManager;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-/**
- * Build/Install/Run:
- * atest WmTests:PhoneWindowManagerTest
- */
-@SmallTest
-@Presubmit
-public class PhoneWindowManagerTest {
-
- private static FakeWindowState createOpaqueFullscreen(boolean hasLightNavBar) {
- final FakeWindowState state = new FakeWindowState();
- state.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT,
- TYPE_BASE_APPLICATION,
- FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR | FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
- PixelFormat.OPAQUE);
- state.attrs.subtreeSystemUiVisibility =
- hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0;
- return state;
- }
-
- private static FakeWindowState createDimmingDialogWindow(boolean canBeImTarget) {
- final FakeWindowState state = new FakeWindowState();
- state.attrs = new WindowManager.LayoutParams(WRAP_CONTENT, WRAP_CONTENT,
- TYPE_APPLICATION,
- FLAG_DIM_BEHIND | (canBeImTarget ? 0 : FLAG_ALT_FOCUSABLE_IM),
- PixelFormat.TRANSLUCENT);
- state.isDimming = true;
- return state;
- }
-
- private static FakeWindowState createInputMethodWindow(boolean visible, boolean drawNavBar,
- boolean hasLightNavBar) {
- final FakeWindowState state = new FakeWindowState();
- state.attrs = new WindowManager.LayoutParams(MATCH_PARENT, MATCH_PARENT,
- TYPE_INPUT_METHOD,
- FLAG_NOT_FOCUSABLE | FLAG_LAYOUT_IN_SCREEN
- | (drawNavBar ? FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS : 0),
- PixelFormat.TRANSPARENT);
- state.attrs.subtreeSystemUiVisibility =
- hasLightNavBar ? SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR : 0;
- state.visible = visible;
- state.policyVisible = visible;
- return state;
- }
-
-
- @Test
- public void testChooseNavigationColorWindowLw() {
- final FakeWindowState opaque = createOpaqueFullscreen(false);
-
- final FakeWindowState dimmingImTarget = createDimmingDialogWindow(true);
- final FakeWindowState dimmingNonImTarget = createDimmingDialogWindow(false);
-
- final FakeWindowState visibleIme = createInputMethodWindow(true, true, false);
- final FakeWindowState invisibleIme = createInputMethodWindow(false, true, false);
- final FakeWindowState imeNonDrawNavBar = createInputMethodWindow(true, false, false);
-
- // If everything is null, return null
- assertNull(null, PhoneWindowManager.chooseNavigationColorWindowLw(
- null, null, null, NAV_BAR_BOTTOM));
-
- assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, opaque, null, NAV_BAR_BOTTOM));
- assertEquals(dimmingImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, dimmingImTarget, null, NAV_BAR_BOTTOM));
- assertEquals(dimmingNonImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, dimmingNonImTarget, null, NAV_BAR_BOTTOM));
-
- assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw(
- null, null, visibleIme, NAV_BAR_BOTTOM));
- assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw(
- null, dimmingImTarget, visibleIme, NAV_BAR_BOTTOM));
- assertEquals(dimmingNonImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
- null, dimmingNonImTarget, visibleIme, NAV_BAR_BOTTOM));
- assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, opaque, visibleIme, NAV_BAR_BOTTOM));
- assertEquals(visibleIme, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, dimmingImTarget, visibleIme, NAV_BAR_BOTTOM));
- assertEquals(dimmingNonImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, dimmingNonImTarget, visibleIme, NAV_BAR_BOTTOM));
-
- assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, opaque, invisibleIme, NAV_BAR_BOTTOM));
- assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, opaque, invisibleIme, NAV_BAR_BOTTOM));
- assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, opaque, visibleIme, NAV_BAR_RIGHT));
-
- // Only IME windows that have FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS should be navigation color
- // window.
- assertEquals(opaque, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, opaque, imeNonDrawNavBar, NAV_BAR_BOTTOM));
- assertEquals(dimmingImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, dimmingImTarget, imeNonDrawNavBar, NAV_BAR_BOTTOM));
- assertEquals(dimmingNonImTarget, PhoneWindowManager.chooseNavigationColorWindowLw(
- opaque, dimmingNonImTarget, imeNonDrawNavBar, NAV_BAR_BOTTOM));
- }
-
- @Test
- public void testUpdateLightNavigationBarLw() {
- final FakeWindowState opaqueDarkNavBar = createOpaqueFullscreen(false);
- final FakeWindowState opaqueLightNavBar = createOpaqueFullscreen(true);
-
- final FakeWindowState dimming = createDimmingDialogWindow(false);
-
- final FakeWindowState imeDrawDarkNavBar = createInputMethodWindow(true, true, false);
- final FakeWindowState imeDrawLightNavBar = createInputMethodWindow(true, true, true);
-
- assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
- PhoneWindowManager.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null,
- null, null));
-
- // Opaque top fullscreen window overrides SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR flag.
- assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
- 0, opaqueDarkNavBar, opaqueDarkNavBar, null, opaqueDarkNavBar));
- assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, opaqueDarkNavBar, null,
- opaqueDarkNavBar));
- assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
- PhoneWindowManager.updateLightNavigationBarLw(0, opaqueLightNavBar,
- opaqueLightNavBar, null, opaqueLightNavBar));
- assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
- PhoneWindowManager.updateLightNavigationBarLw(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
- opaqueLightNavBar, opaqueLightNavBar, null, opaqueLightNavBar));
-
- // Dimming window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.
- assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
- 0, opaqueDarkNavBar, dimming, null, dimming));
- assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
- 0, opaqueLightNavBar, dimming, null, dimming));
- assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueDarkNavBar, dimming, null, dimming));
- assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, null, dimming));
- assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, dimming, imeDrawLightNavBar,
- dimming));
-
- // IME window clears SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
- assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, null, null, imeDrawDarkNavBar,
- imeDrawDarkNavBar));
-
- // Even if the top fullscreen has SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, IME window wins.
- assertEquals(0, PhoneWindowManager.updateLightNavigationBarLw(
- SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, opaqueLightNavBar, opaqueLightNavBar,
- imeDrawDarkNavBar, imeDrawDarkNavBar));
-
- // IME window should be able to use SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR.
- assertEquals(SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR,
- PhoneWindowManager.updateLightNavigationBarLw(0, opaqueDarkNavBar,
- opaqueDarkNavBar, imeDrawLightNavBar, imeDrawLightNavBar));
- }
-
- @Test
- public void testIsDockSideAllowedDockTop() {
- // Docked top is always allowed
- assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT, NAV_BAR_BOTTOM,
- true /* navigationBarCanMove */));
- assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_TOP, DOCKED_LEFT, NAV_BAR_BOTTOM,
- false /* navigationBarCanMove */));
- }
-
- @Test
- public void testIsDockSideAllowedDockBottom() {
- // Cannot dock bottom
- assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_BOTTOM, DOCKED_LEFT, NAV_BAR_BOTTOM,
- true /* navigationBarCanMove */));
- }
-
- @Test
- public void testIsDockSideAllowedNavigationBarMovable() {
- assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_BOTTOM,
- true /* navigationBarCanMove */));
- assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_LEFT,
- true /* navigationBarCanMove */));
- assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_RIGHT,
- true /* navigationBarCanMove */));
- assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_BOTTOM,
- true /* navigationBarCanMove */));
- assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_RIGHT,
- true /* navigationBarCanMove */));
- assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_LEFT,
- true /* navigationBarCanMove */));
- }
-
- @Test
- public void testIsDockSideAllowedNavigationBarNotMovable() {
- // Navigation bar is not movable such as tablets
- assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_LEFT, NAV_BAR_BOTTOM,
- false /* navigationBarCanMove */));
- assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_TOP, NAV_BAR_BOTTOM,
- false /* navigationBarCanMove */));
- assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_LEFT, DOCKED_RIGHT, NAV_BAR_BOTTOM,
- false /* navigationBarCanMove */));
- assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_LEFT, NAV_BAR_BOTTOM,
- false /* navigationBarCanMove */));
- assertFalse(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_TOP, NAV_BAR_BOTTOM,
- false /* navigationBarCanMove */));
- assertTrue(PhoneWindowManager.isDockSideAllowed(DOCKED_RIGHT, DOCKED_RIGHT, NAV_BAR_BOTTOM,
- false /* navigationBarCanMove */));
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
deleted file mode 100644
index 02a33e0..0000000
--- a/services/tests/wmtests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.policy;
-
-import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM;
-import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
-import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT;
-import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
-import static android.view.Surface.ROTATION_270;
-import static android.view.Surface.ROTATION_90;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.server.wm.utils.CoordinateTransforms
- .transformPhysicalToLogicalCoordinates;
-
-import static org.junit.Assert.assertEquals;
-
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.Matrix;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.os.IBinder;
-import android.os.UserHandle;
-import android.testing.TestableResources;
-import android.util.Pair;
-import android.view.Display;
-import android.view.DisplayCutout;
-import android.view.DisplayInfo;
-import android.view.Gravity;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.IAccessibilityManager;
-
-import com.android.server.policy.keyguard.KeyguardServiceDelegate;
-import com.android.server.wm.DisplayFrames;
-import com.android.server.wm.WindowTestUtils.TestDisplayContent;
-import com.android.server.wm.utils.WmDisplayCutout;
-
-import org.junit.Before;
-
-class PhoneWindowManagerTestBase {
- static final int DISPLAY_WIDTH = 500;
- static final int DISPLAY_HEIGHT = 1000;
-
- static final int STATUS_BAR_HEIGHT = 10;
- static final int NAV_BAR_HEIGHT = 15;
- static final int DISPLAY_CUTOUT_HEIGHT = 8;
-
- TestablePhoneWindowManager mPolicy;
- TestContextWrapper mContext;
- DisplayFrames mFrames;
-
- FakeWindowState mStatusBar;
- FakeWindowState mNavigationBar;
- private boolean mHasDisplayCutout;
- private int mRotation = ROTATION_0;
-
- @Before
- public void setUpBase() {
- mContext = new TestContextWrapper(getInstrumentation().getTargetContext());
- mContext.getResourceMocker().addOverride(
- com.android.internal.R.dimen.status_bar_height_portrait, STATUS_BAR_HEIGHT);
- mContext.getResourceMocker().addOverride(
- com.android.internal.R.dimen.status_bar_height_landscape, STATUS_BAR_HEIGHT);
- mContext.getResourceMocker().addOverride(
- com.android.internal.R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
- mContext.getResourceMocker().addOverride(
- com.android.internal.R.dimen.navigation_bar_height_landscape, NAV_BAR_HEIGHT);
- mContext.getResourceMocker().addOverride(
- com.android.internal.R.dimen.navigation_bar_width, NAV_BAR_HEIGHT);
-
- mPolicy = TestablePhoneWindowManager.create(mContext);
-
- updateDisplayFrames();
- }
-
- public void setRotation(int rotation) {
- mRotation = rotation;
- updateDisplayFrames();
- }
-
- private void updateDisplayFrames() {
- Pair<DisplayInfo, WmDisplayCutout> info = displayInfoAndCutoutForRotation(mRotation,
- mHasDisplayCutout);
- mFrames = new DisplayFrames(Display.DEFAULT_DISPLAY, info.first, info.second);
- }
-
- public void addStatusBar() {
- mStatusBar = new FakeWindowState();
- mStatusBar.attrs = new WindowManager.LayoutParams(MATCH_PARENT, STATUS_BAR_HEIGHT,
- TYPE_STATUS_BAR, 0 /* flags */, PixelFormat.TRANSLUCENT);
- mStatusBar.attrs.gravity = Gravity.TOP;
-
- mPolicy.addWindow(mStatusBar);
- mPolicy.mLastSystemUiFlags |= View.STATUS_BAR_TRANSPARENT;
- }
-
- public void addNavigationBar() {
- mNavigationBar = new FakeWindowState();
- mNavigationBar.attrs = new WindowManager.LayoutParams(MATCH_PARENT, NAV_BAR_HEIGHT,
- TYPE_NAVIGATION_BAR, 0 /* flags */, PixelFormat.TRANSLUCENT);
- mNavigationBar.attrs.gravity = Gravity.BOTTOM;
-
- mPolicy.addWindow(mNavigationBar);
- mPolicy.mLastSystemUiFlags |= View.NAVIGATION_BAR_TRANSPARENT;
- }
-
- public void addDisplayCutout() {
- mHasDisplayCutout = true;
- updateDisplayFrames();
- }
-
- /** Asserts that {@code actual} is inset by the given amounts from the full display rect. */
- public void assertInsetBy(Rect actual, int expectedInsetLeft, int expectedInsetTop,
- int expectedInsetRight, int expectedInsetBottom) {
- assertEquals(new Rect(expectedInsetLeft, expectedInsetTop,
- mFrames.mDisplayWidth - expectedInsetRight,
- mFrames.mDisplayHeight - expectedInsetBottom), actual);
- }
-
- /**
- * Asserts that {@code actual} is inset by the given amounts from the full display rect.
- *
- * Convenience wrapper for when only the top and bottom inset are non-zero.
- */
- public void assertInsetByTopBottom(Rect actual, int expectedInsetTop, int expectedInsetBottom) {
- assertInsetBy(actual, 0, expectedInsetTop, 0, expectedInsetBottom);
- }
-
- public static DisplayInfo displayInfoForRotation(int rotation, boolean withDisplayCutout) {
- return displayInfoAndCutoutForRotation(rotation, withDisplayCutout).first;
- }
- public static Pair<DisplayInfo, WmDisplayCutout> displayInfoAndCutoutForRotation(int rotation,
- boolean withDisplayCutout) {
- DisplayInfo info = new DisplayInfo();
- WmDisplayCutout cutout = null;
-
- final boolean flippedDimensions = rotation == ROTATION_90 || rotation == ROTATION_270;
- info.logicalWidth = flippedDimensions ? DISPLAY_HEIGHT : DISPLAY_WIDTH;
- info.logicalHeight = flippedDimensions ? DISPLAY_WIDTH : DISPLAY_HEIGHT;
- info.rotation = rotation;
- if (withDisplayCutout) {
- cutout = WmDisplayCutout.computeSafeInsets(
- displayCutoutForRotation(rotation), info.logicalWidth,
- info.logicalHeight);
- info.displayCutout = cutout.getDisplayCutout();
- } else {
- info.displayCutout = null;
- }
- return Pair.create(info, cutout);
- }
-
- private static DisplayCutout displayCutoutForRotation(int rotation) {
- RectF rectF = new RectF(DISPLAY_WIDTH / 4, 0, DISPLAY_WIDTH * 3 / 4, DISPLAY_CUTOUT_HEIGHT);
-
- Matrix m = new Matrix();
- transformPhysicalToLogicalCoordinates(rotation, DISPLAY_WIDTH, DISPLAY_HEIGHT, m);
- m.mapRect(rectF);
-
- int pos = -1;
- switch (rotation) {
- case ROTATION_0:
- pos = BOUNDS_POSITION_TOP;
- break;
- case ROTATION_90:
- pos = BOUNDS_POSITION_LEFT;
- break;
- case ROTATION_180:
- pos = BOUNDS_POSITION_BOTTOM;
- break;
- case ROTATION_270:
- pos = BOUNDS_POSITION_RIGHT;
- break;
- }
-
-
- return DisplayCutout.fromBoundingRect((int) rectF.left, (int) rectF.top,
- (int) rectF.right, (int) rectF.bottom, pos);
- }
-
- static class TestContextWrapper extends ContextWrapper {
- private final TestableResources mResourceMocker;
-
- TestContextWrapper(Context targetContext) {
- super(targetContext);
- mResourceMocker = new TestableResources(targetContext.getResources());
- }
-
- @Override
- public int checkPermission(String permission, int pid, int uid) {
- return PackageManager.PERMISSION_GRANTED;
- }
-
- @Override
- public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
- return PackageManager.PERMISSION_GRANTED;
- }
-
- @Override
- public Resources getResources() {
- return mResourceMocker.getResources();
- }
-
- public TestableResources getResourceMocker() {
- return mResourceMocker;
- }
- }
-
- static class TestablePhoneWindowManager extends PhoneWindowManager {
-
- TestablePhoneWindowManager() {
- }
-
- @Override
- void initializeHdmiState() {
- // Do nothing.
- }
-
- @Override
- Context getSystemUiContext() {
- return mContext;
- }
-
- void addWindow(WindowState state) {
- if (state instanceof FakeWindowState) {
- ((FakeWindowState) state).surfaceLayer =
- getWindowLayerFromTypeLw(state.getAttrs().type,
- true /* canAddInternalSystemWindow */);
- }
- adjustWindowParamsLw(state, state.getAttrs(), true /* hasStatusBarPermission */);
- assertEquals(WindowManagerGlobal.ADD_OKAY, prepareAddWindowLw(state, state.getAttrs()));
- }
-
- public static TestablePhoneWindowManager create(Context context) {
- TestablePhoneWindowManager[] policy = new TestablePhoneWindowManager[1];
- getInstrumentation().runOnMainSync(() -> {
- policy[0] = new TestablePhoneWindowManager();
- policy[0].mContext = context;
- policy[0].mKeyguardDelegate = mock(KeyguardServiceDelegate.class);
- policy[0].mAccessibilityManager = new AccessibilityManager(context,
- mock(IAccessibilityManager.class), UserHandle.USER_CURRENT);
- policy[0].mSystemGestures = mock(SystemGesturesPointerEventListener.class);
-
- final TestDisplayContent displayContent = TestDisplayContent.create(context);
- policy[0].setDefaultDisplay(displayContent);
- policy[0].onConfigurationChanged(displayContent);
- });
- return policy[0];
- }
- }
-}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 6ed83de..170bd33 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -163,7 +163,8 @@
private void verifyPositionWithLimitedAspectRatio(int navBarPosition, Rect taskBounds,
float aspectRatio, Rect expectedActivityBounds) {
// Verify with nav bar on the right.
- when(mService.mWindowManager.getNavBarPosition()).thenReturn(navBarPosition);
+ when(mService.mWindowManager.getNavBarPosition(mActivity.getDisplayId()))
+ .thenReturn(navBarPosition);
mTask.getConfiguration().windowConfiguration.setAppBounds(taskBounds);
mActivity.info.maxAspectRatio = aspectRatio;
mActivity.ensureActivityConfiguration(
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 152831f..4f573a4 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -27,8 +27,6 @@
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START;
-import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
-import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_FOREGROUND_SERVICE_STOP;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_NOTIFICATION_SEEN;
@@ -846,8 +844,6 @@
// Inform listeners if necessary
if ((event.mEventType == UsageEvents.Event.MOVE_TO_FOREGROUND
|| event.mEventType == UsageEvents.Event.MOVE_TO_BACKGROUND
- || event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_START
- || event.mEventType == UsageEvents.Event.FOREGROUND_SERVICE_STOP
|| event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION
|| event.mEventType == UsageEvents.Event.USER_INTERACTION
|| event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN
@@ -900,10 +896,6 @@
switch (eventType) {
case UsageEvents.Event.MOVE_TO_FOREGROUND: return REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
case UsageEvents.Event.MOVE_TO_BACKGROUND: return REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
- case UsageEvents.Event.FOREGROUND_SERVICE_START:
- return REASON_SUB_USAGE_FOREGROUND_SERVICE_START;
- case UsageEvents.Event.FOREGROUND_SERVICE_STOP:
- return REASON_SUB_USAGE_FOREGROUND_SERVICE_STOP;
case UsageEvents.Event.SYSTEM_INTERACTION: return REASON_SUB_USAGE_SYSTEM_INTERACTION;
case UsageEvents.Event.USER_INTERACTION: return REASON_SUB_USAGE_USER_INTERACTION;
case UsageEvents.Event.NOTIFICATION_SEEN: return REASON_SUB_USAGE_NOTIFICATION_SEEN;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index d940620..01e566c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -20,6 +20,7 @@
import android.app.usage.UsageStats;
import android.content.res.Configuration;
import android.util.ArrayMap;
+import android.util.Log;
import com.android.internal.util.XmlUtils;
@@ -89,11 +90,23 @@
// Apply the offset to the beginTime to find the absolute time.
stats.mLastTimeUsed = statsOut.beginTime + XmlUtils.readLongAttribute(
parser, LAST_TIME_ACTIVE_ATTR);
- stats.mLastTimeForegroundServiceUsed = statsOut.beginTime + XmlUtils.readLongAttribute(
- parser, LAST_TIME_SERVICE_USED_ATTR);
+
+ try {
+ stats.mLastTimeForegroundServiceUsed = statsOut.beginTime + XmlUtils.readLongAttribute(
+ parser, LAST_TIME_SERVICE_USED_ATTR);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to parse mLastTimeForegroundServiceUsed", e);
+ }
+
stats.mTotalTimeInForeground = XmlUtils.readLongAttribute(parser, TOTAL_TIME_ACTIVE_ATTR);
- stats.mTotalTimeForegroundServiceUsed = XmlUtils.readLongAttribute(parser,
+
+ try {
+ stats.mTotalTimeForegroundServiceUsed = XmlUtils.readLongAttribute(parser,
TOTAL_TIME_SERVICE_USED_ATTR);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to parse mTotalTimeForegroundServiceUsed", e);
+ }
+
stats.mLastEvent = XmlUtils.readIntAttribute(parser, LAST_EVENT_ATTR);
stats.mAppLaunchCount = XmlUtils.readIntAttribute(parser, APP_LAUNCH_COUNT_ATTR,
0);
@@ -350,8 +363,17 @@
}
statsOut.endTime = statsOut.beginTime + XmlUtils.readLongAttribute(parser, END_TIME_ATTR);
- statsOut.majorVersion = XmlUtils.readIntAttribute(parser, MAJOR_VERSION_ATTR);
- statsOut.minorVersion = XmlUtils.readIntAttribute(parser, MINOR_VERSION_ATTR);
+ try {
+ statsOut.majorVersion = XmlUtils.readIntAttribute(parser, MAJOR_VERSION_ATTR);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to parse majorVersion", e);
+ }
+
+ try {
+ statsOut.minorVersion = XmlUtils.readIntAttribute(parser, MINOR_VERSION_ATTR);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to parse minorVersion", e);
+ }
int eventCode;
int outerDepth = parser.getDepth();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 5ad7c30..185c886 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1838,6 +1838,13 @@
"notify_international_call_on_wfc_bool";
/**
+ * Flag to hide Preset APN details. If true, user cannot enter ApnEditor view of Preset APN,
+ * and cannot view details of the APN. If false, user can enter ApnEditor view of Preset APN.
+ * Default value is false.
+ */
+ public static final String KEY_HIDE_PRESET_APN_DETAILS_BOOL = "hide_preset_apn_details_bool";
+
+ /**
* Flag specifying whether to show an alert dialog for video call charges.
* By default this value is {@code false}.
* @hide
@@ -2643,6 +2650,7 @@
sDefaults.putBoolean(KEY_DISPLAY_VOICEMAIL_NUMBER_AS_DEFAULT_CALL_FORWARDING_NUMBER_BOOL,
false);
sDefaults.putBoolean(KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL, false);
+ sDefaults.putBoolean(KEY_HIDE_PRESET_APN_DETAILS_BOOL, false);
sDefaults.putBoolean(KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL, false);
sDefaults.putStringArray(KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY,
null);
diff --git a/telephony/java/android/telephony/MbmsGroupCallSession.java b/telephony/java/android/telephony/MbmsGroupCallSession.java
index e373797..269cda1 100644
--- a/telephony/java/android/telephony/MbmsGroupCallSession.java
+++ b/telephony/java/android/telephony/MbmsGroupCallSession.java
@@ -37,6 +37,7 @@
import android.util.ArraySet;
import android.util.Log;
+import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -107,14 +108,14 @@
* {@link MbmsGroupCallSession} that you received before calling this method again.
*
* @param context The {@link Context} to use.
- * @param executor The executor on which you wish to execute callbacks.
* @param subscriptionId The subscription ID to use.
+ * @param executor The executor on which you wish to execute callbacks.
* @param callback A callback object on which you wish to receive results of asynchronous
* operations.
* @return An instance of {@link MbmsGroupCallSession}, or null if an error occurred.
*/
public static @Nullable MbmsGroupCallSession create(@NonNull Context context,
- @NonNull Executor executor, int subscriptionId,
+ int subscriptionId, @NonNull Executor executor,
final @NonNull MbmsGroupCallSessionCallback callback) {
if (!sIsInitialized.compareAndSet(false, true)) {
throw new IllegalStateException("Cannot create two instances of MbmsGroupCallSession");
@@ -138,11 +139,11 @@
/**
* Create a new {@link MbmsGroupCallSession} using the system default data subscription ID.
- * See {@link #create(Context, Executor, int, MbmsGroupCallSessionCallback)}.
+ * See {@link #create(Context, int, Executor, MbmsGroupCallSessionCallback)}.
*/
public static MbmsGroupCallSession create(@NonNull Context context,
@NonNull Executor executor, @NonNull MbmsGroupCallSessionCallback callback) {
- return create(context, executor, SubscriptionManager.getDefaultSubscriptionId(), callback);
+ return create(context, SubscriptionManager.getDefaultSubscriptionId(), executor, callback);
}
/**
@@ -153,7 +154,7 @@
* instance of {@link MbmsGroupCallSessionCallback}, but callbacks that have already been
* enqueued will still be delivered.
*
- * It is safe to call {@link #create(Context, Executor, int, MbmsGroupCallSessionCallback)} to
+ * It is safe to call {@link #create(Context, int, Executor, MbmsGroupCallSessionCallback)} to
* obtain another instance of {@link MbmsGroupCallSession} immediately after this method
* returns.
*
@@ -189,18 +190,19 @@
* Asynchronous errors through the callback include any of the errors in
* {@link MbmsErrors.GeneralErrors}.
*
- * @param executor The executor on which you wish to execute callbacks for this stream.
* @param tmgi The TMGI, an identifier for the group call you want to join.
- * @param saiArray An array of SAIs for the group call that should be negotiated separately with
+ * @param saiList A list of SAIs for the group call that should be negotiated separately with
* the carrier.
- * @param frequencyArray An array of frequencies for the group call that should be negotiated
+ * @param frequencyList A lost of frequencies for the group call that should be negotiated
* separately with the carrier.
+ * @param executor The executor on which you wish to execute callbacks for this stream.
* @param callback The callback that you want to receive information about the call on.
* @return An instance of {@link GroupCall} through which the call can be controlled.
* May be {@code null} if an error occurred.
*/
- public @Nullable GroupCall startGroupCall(@NonNull Executor executor, long tmgi, int[] saiArray,
- int[] frequencyArray, @NonNull GroupCallCallback callback) {
+ public @Nullable GroupCall startGroupCall(long tmgi, @NonNull List<Integer> saiList,
+ @NonNull List<Integer> frequencyList, @NonNull Executor executor,
+ @NonNull GroupCallCallback callback) {
IMbmsGroupCallService groupCallService = mService.get();
if (groupCallService == null) {
throw new IllegalStateException("Middleware not yet bound");
@@ -215,7 +217,7 @@
try {
int returnCode = groupCallService.startGroupCall(
- mSubscriptionId, tmgi, saiArray, frequencyArray, serviceCallback);
+ mSubscriptionId, tmgi, saiList, frequencyList, serviceCallback);
if (returnCode == MbmsErrors.UNKNOWN) {
// Unbind and throw an obvious error
close();
diff --git a/telephony/java/android/telephony/mbms/GroupCall.java b/telephony/java/android/telephony/mbms/GroupCall.java
index 9aca18e..25e274e 100644
--- a/telephony/java/android/telephony/mbms/GroupCall.java
+++ b/telephony/java/android/telephony/mbms/GroupCall.java
@@ -17,6 +17,7 @@
package android.telephony.mbms;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.os.RemoteException;
import android.telephony.MbmsGroupCallSession;
import android.telephony.mbms.vendor.IMbmsGroupCallService;
@@ -24,6 +25,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
/**
* Class used to represent a single MBMS group call. After a call has been started with
@@ -41,8 +43,26 @@
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "STATE_" }, value = {STATE_STOPPED, STATE_STARTED, STATE_STALLED})
public @interface GroupCallState {}
+
+ /**
+ * Indicates that the group call is in a stopped state
+ *
+ * This can be reported after network action or after calling {@link #close}.
+ */
public static final int STATE_STOPPED = 1;
+
+ /**
+ * Indicates that the group call is started.
+ *
+ * Data can be transmitted and received in this state.
+ */
public static final int STATE_STARTED = 2;
+
+ /**
+ * Indicates that the group call is stalled.
+ *
+ * This may be due to a network issue or the device being temporarily out of range.
+ */
public static final int STATE_STALLED = 3;
/**
@@ -122,16 +142,17 @@
* Send an update to the middleware when the SAI (Service Area Identifier) list and frequency
* information of the group call has * changed. Callers must obtain this information from the
* wireless carrier independently.
- * @param saiArray New array of SAIs that the call is available on.
- * @param frequencyArray New array of frequencies that the call is available on.
+ * @param saiList New list of SAIs that the call is available on.
+ * @param frequencyList New list of frequencies that the call is available on.
*/
- public void updateGroupCall(int[] saiArray, int[] frequencyArray) {
+ public void updateGroupCall(@NonNull List<Integer> saiList,
+ @NonNull List<Integer> frequencyList) {
if (mService == null) {
throw new IllegalStateException("No group call service attached");
}
try {
- mService.updateGroupCall(mSubscriptionId, mTmgi, saiArray, frequencyArray);
+ mService.updateGroupCall(mSubscriptionId, mTmgi, saiList, frequencyList);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote process died");
mService = null;
diff --git a/telephony/java/android/telephony/mbms/GroupCallCallback.java b/telephony/java/android/telephony/mbms/GroupCallCallback.java
index 001bb02..77e36bb 100644
--- a/telephony/java/android/telephony/mbms/GroupCallCallback.java
+++ b/telephony/java/android/telephony/mbms/GroupCallCallback.java
@@ -17,6 +17,7 @@
package android.telephony.mbms;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.Nullable;
import java.lang.annotation.Retention;
@@ -26,7 +27,7 @@
* A callback class for use when the application is in a group call. The middleware
* will provide updates on the status of the call via this callback.
*/
-public class GroupCallCallback {
+public interface GroupCallCallback {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
@@ -40,7 +41,7 @@
MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE,
MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM,
MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED}, prefix = { "ERROR_" })
- private @interface GroupCallError{}
+ @interface GroupCallError{}
/**
* Indicates broadcast signal strength is not available for this call.
@@ -48,7 +49,7 @@
* This may be due to the call no longer being available due to geography
* or timing (end of service)
*/
- public static final int SIGNAL_STRENGTH_UNAVAILABLE = -1;
+ int SIGNAL_STRENGTH_UNAVAILABLE = -1;
/**
* Called by the middleware when it has detected an error condition in this group call. The
@@ -56,9 +57,7 @@
* @param errorCode The error code.
* @param message A human-readable message generated by the middleware for debugging purposes.
*/
- public void onError(@GroupCallError int errorCode, @Nullable String message) {
- // default implementation empty
- }
+ void onError(@GroupCallError int errorCode, @Nullable String message);
/**
* Called to indicate this call has changed state.
@@ -66,10 +65,8 @@
* See {@link GroupCall#STATE_STOPPED}, {@link GroupCall#STATE_STARTED}
* and {@link GroupCall#STATE_STALLED}.
*/
- public void onGroupCallStateChanged(@GroupCall.GroupCallState int state,
- @GroupCall.GroupCallStateChangeReason int reason) {
- // default implementation empty
- }
+ void onGroupCallStateChanged(@GroupCall.GroupCallState int state,
+ @GroupCall.GroupCallStateChangeReason int reason);
/**
* Broadcast Signal Strength updated.
@@ -81,7 +78,5 @@
* {@link #SIGNAL_STRENGTH_UNAVAILABLE} if broadcast is not available
* for this call due to timing, geography or popularity.
*/
- public void onBroadcastSignalStrengthUpdated(int signalStrength) {
- // default implementation empty
- }
+ void onBroadcastSignalStrengthUpdated(@IntRange(from = -1, to = 4) int signalStrength);
}
diff --git a/telephony/java/android/telephony/mbms/MbmsErrors.java b/telephony/java/android/telephony/mbms/MbmsErrors.java
index 7c4321b..52e4d33 100644
--- a/telephony/java/android/telephony/mbms/MbmsErrors.java
+++ b/telephony/java/android/telephony/mbms/MbmsErrors.java
@@ -140,5 +140,21 @@
public static final int ERROR_UNKNOWN_FILE_INFO = 403;
}
+ /**
+ * Indicates the errors that are applicable only to the group call use-case.
+ */
+ public static class GroupCallErrors {
+ private GroupCallErrors() { }
+ /** Indicates that the middleware was unable to start the group call. */
+ public static final int ERROR_UNABLE_TO_START_SERVICE = 501;
+
+ /**
+ * Indicates that the app called
+ * {@link android.telephony.MbmsGroupCallSession#startGroupCall} more than once for the
+ * same {@code tmgi}.
+ */
+ public static final int ERROR_DUPLICATE_START_GROUP_CALL = 502;
+ }
+
private MbmsErrors() {}
}
diff --git a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
index 7da734e..04e7ba1 100644
--- a/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsGroupCallSessionCallback.java
@@ -17,6 +17,7 @@
package android.telephony.mbms;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.telephony.MbmsGroupCallSession;
@@ -29,9 +30,9 @@
/**
* A callback class that is used to receive information from the middleware on MBMS group-call
* services. An instance of this object should be passed into
- * {@link MbmsGroupCallSession#create(Context, Executor, int, MbmsGroupCallSessionCallback)}.
+ * {@link MbmsGroupCallSession#create(Context, int, Executor, MbmsGroupCallSessionCallback)}.
*/
-public class MbmsGroupCallSessionCallback {
+public interface MbmsGroupCallSessionCallback {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
@@ -48,7 +49,7 @@
MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE,
MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM,
MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED}, prefix = { "ERROR_" })
- private @interface GroupCallError{}
+ @interface GroupCallError{}
/**
* Called by the middleware when it has detected an error condition. The possible error codes
@@ -56,8 +57,7 @@
* @param errorCode The error code.
* @param message A human-readable message generated by the middleware for debugging purposes.
*/
- public void onError(@GroupCallError int errorCode, @Nullable String message) {
- }
+ void onError(@GroupCallError int errorCode, @Nullable String message);
/**
* Indicates that the list of currently available SAIs has been updated. The app may use this
@@ -70,21 +70,22 @@
* @param availableSais A list of lists of available SAIS in neighboring cells, where each list
* contains the available SAIs in an individual cell.
*/
- public void onAvailableSaisUpdated(List<Integer> currentSais,
- List<List<Integer>> availableSais) {
- }
+ void onAvailableSaisUpdated(@NonNull List<Integer> currentSais,
+ @NonNull List<List<Integer>> availableSais);
/**
* Called soon after the app calls {@link MbmsGroupCallSession#create}. The information supplied
- * via this callback may be used to establish a data-link interface with the modem before the
- * middleware is ready.
- * Note that this method may be called before {@link #onMiddlewareReady()}.
+ * via this callback may be used to establish a data-link interface with the modem.
+ *
+ * In order to establish the data-link interface, the multicast IP and port must be obtained
+ * out-of-band from the carrier. A {@link java.net.MulticastSocket} may then be constructed
+ * using a {@link java.net.NetworkInterface} with the name and interface supplied by this
+ * callback.
*
* @param interfaceName The interface name for the data link.
* @param index The index for the data link.
*/
- public void onServiceInterfaceAvailable(String interfaceName, int index) {
- }
+ void onServiceInterfaceAvailable(@NonNull String interfaceName, int index);
/**
* Called to indicate that the middleware has been initialized and is ready.
@@ -94,6 +95,5 @@
* delivered via {@link #onError(int, String)} with error code
* {@link MbmsErrors.GeneralErrors#ERROR_MIDDLEWARE_NOT_YET_READY}.
*/
- public void onMiddlewareReady() {
- }
+ void onMiddlewareReady();
}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
index 721256a..44cc24a 100755
--- a/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsGroupCallService.aidl
@@ -29,11 +29,11 @@
void stopGroupCall(int subId, long tmgi);
- void updateGroupCall(int subscriptionId, long tmgi, in int[] saiArray,
- in int[] frequencyArray);
+ void updateGroupCall(int subscriptionId, long tmgi, in List saiList,
+ in List frequencyList);
- int startGroupCall(int subscriptionId, long tmgi, in int[] saiArray,
- in int[] frequencyArray, IGroupCallCallback callback);
+ int startGroupCall(int subscriptionId, long tmgi, in List saiList,
+ in List frequencyList, IGroupCallCallback callback);
void dispose(int subId);
}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java
index 3734ca7..e86a47d 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsGroupCallServiceBase.java
@@ -115,15 +115,16 @@
}
@Override
- public void updateGroupCall(int subscriptionId, long tmgi, int[] saiArray,
- int[] frequencyArray) {
+ public void updateGroupCall(int subscriptionId, long tmgi, List saiList,
+ List frequencyList) {
MbmsGroupCallServiceBase.this.updateGroupCall(
- subscriptionId, tmgi, saiArray, frequencyArray);
+ subscriptionId, tmgi, saiList, frequencyList);
}
@Override
- public int startGroupCall(final int subscriptionId, final long tmgi, final int[] saiArray,
- final int[] frequencyArray, final IGroupCallCallback callback)
+ public int startGroupCall(final int subscriptionId, final long tmgi,
+ final List saiList,
+ final List frequencyList, final IGroupCallCallback callback)
throws RemoteException {
if (callback == null) {
throw new NullPointerException("Callback must not be null");
@@ -132,7 +133,7 @@
final int uid = Binder.getCallingUid();
int result = MbmsGroupCallServiceBase.this.startGroupCall(
- subscriptionId, tmgi, saiArray, frequencyArray, new GroupCallCallback() {
+ subscriptionId, tmgi, saiList, frequencyList, new GroupCallCallback() {
@Override
public void onError(final int errorCode, final String message) {
try {
@@ -209,13 +210,13 @@
*
* @param subscriptionId The subscription id to use.
* @param tmgi The TMGI, an identifier for the group call.
- * @param saiArray An array of SAIs for the group call.
- * @param frequencyArray An array of frequencies for the group call.
+ * @param saiList A list of SAIs for the group call.
+ * @param frequencyList A list of frequencies for the group call.
* @param callback The callback object on which the app wishes to receive updates.
* @return Any error in {@link MbmsErrors.GeneralErrors}
*/
- public int startGroupCall(int subscriptionId, long tmgi, int[] saiArray, int[] frequencyArray,
- GroupCallCallback callback) {
+ public int startGroupCall(int subscriptionId, long tmgi, List<Integer> saiList,
+ List<Integer> frequencyList, GroupCallCallback callback) {
throw new UnsupportedOperationException("Not implemented");
}
@@ -237,11 +238,11 @@
/**
* Called when the app receives new SAI and frequency information for the group call identified
* by {@code tmgi}.
- * @param saiArray New array of SAIs that the call is available on.
- * @param frequencyArray New array of frequencies that the call is available on.
+ * @param saiList New list of SAIs that the call is available on.
+ * @param frequencyList New list of frequencies that the call is available on.
*/
- public void updateGroupCall(int subscriptionId, long tmgi, int[] saiArray,
- int[] frequencyArray) {
+ public void updateGroupCall(int subscriptionId, long tmgi, List<Integer> saiList,
+ List<Integer> frequencyList) {
throw new UnsupportedOperationException("Not implemented");
}
diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java
index 771faaf..be1a455 100644
--- a/tests/net/java/android/net/IpSecConfigTest.java
+++ b/tests/net/java/android/net/IpSecConfigTest.java
@@ -47,6 +47,7 @@
assertNull(c.getEncryption());
assertNull(c.getAuthentication());
assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId());
+ assertEquals(0, c.getXfrmInterfaceId());
}
private IpSecConfig getSampleConfig() {
@@ -77,6 +78,7 @@
c.setNattKeepaliveInterval(42);
c.setMarkValue(12);
c.setMarkMask(23);
+ c.setXfrmInterfaceId(34);
return c;
}
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 9b919abf..4dc0341 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -71,6 +71,9 @@
private final LinkAddress mLocalInnerAddress;
private final int mFamily;
+ private static final int[] ADDRESS_FAMILIES =
+ new int[] {AF_INET, AF_INET6};
+
@Parameterized.Parameters
public static Collection ipSecConfigs() {
return Arrays.asList(
@@ -196,6 +199,7 @@
anyString(),
eq(TEST_SPI),
anyInt(),
+ anyInt(),
anyInt());
// Verify quota and RefcountedResource objects cleaned up
@@ -231,6 +235,7 @@
anyString(),
eq(TEST_SPI),
anyInt(),
+ anyInt(),
anyInt());
// Verify quota and RefcountedResource objects cleaned up
@@ -304,7 +309,8 @@
eq((authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0),
eq(config.getEncapType()),
eq(encapSocketPort),
- eq(config.getEncapRemotePort()));
+ eq(config.getEncapRemotePort()),
+ eq(config.getXfrmInterfaceId()));
}
@Test
@@ -430,6 +436,7 @@
anyString(),
eq(TEST_SPI),
anyInt(),
+ anyInt(),
anyInt());
// quota is not released until the SPI is released by the Transform
assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
@@ -452,6 +459,7 @@
anyString(),
eq(TEST_SPI),
anyInt(),
+ anyInt(),
anyInt());
// Verify quota and RefcountedResource objects cleaned up
@@ -469,6 +477,7 @@
anyString(),
anyInt(),
anyInt(),
+ anyInt(),
anyInt());
assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
@@ -504,6 +513,7 @@
anyString(),
eq(TEST_SPI),
anyInt(),
+ anyInt(),
anyInt());
// Verify quota and RefcountedResource objects cleaned up
@@ -572,11 +582,12 @@
assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
verify(mMockNetd)
- .addVirtualTunnelInterface(
+ .ipSecAddTunnelInterface(
eq(createTunnelResp.interfaceName),
eq(mSourceAddr),
eq(mDestinationAddr),
anyInt(),
+ anyInt(),
anyInt());
}
@@ -591,7 +602,7 @@
// Verify quota and RefcountedResource objects cleaned up
assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
- verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
+ verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
try {
userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
createTunnelResp.resourceId);
@@ -614,7 +625,7 @@
// Verify quota and RefcountedResource objects cleaned up
assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
- verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
+ verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
try {
userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
createTunnelResp.resourceId);
@@ -624,6 +635,41 @@
}
@Test
+ public void testApplyTunnelModeTransform() throws Exception {
+ IpSecConfig ipSecConfig = new IpSecConfig();
+ ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
+ addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+ addAuthAndCryptToIpSecConfig(ipSecConfig);
+
+ IpSecTransformResponse createTransformResp =
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+
+ int transformResourceId = createTransformResp.resourceId;
+ int tunnelResourceId = createTunnelResp.resourceId;
+ mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
+ transformResourceId, "blessedPackage");
+
+ for (int selAddrFamily : ADDRESS_FAMILIES) {
+ verify(mMockNetd)
+ .ipSecUpdateSecurityPolicy(
+ eq(mUid),
+ eq(selAddrFamily),
+ eq(IpSecManager.DIRECTION_OUT),
+ anyString(),
+ anyString(),
+ eq(TEST_SPI),
+ anyInt(), // iKey/oKey
+ anyInt(), // mask
+ eq(tunnelResourceId));
+ }
+
+ ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
+ verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
+ }
+
+ @Test
public void testAddRemoveAddressFromTunnelInterface() throws Exception {
for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
IpSecTunnelInterfaceResponse createTunnelResp =
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index af7123b..f2bd770 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -27,9 +27,17 @@
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.os.Process.SYSTEM_UID;
+import static com.android.server.connectivity.PermissionMonitor.NETWORK;
+import static com.android.server.connectivity.PermissionMonitor.SYSTEM;
+
+import static junit.framework.Assert.fail;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
@@ -40,6 +48,8 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
+import android.os.INetworkManagementService;
+import android.os.UserHandle;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -48,12 +58,19 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+
+import java.util.HashMap;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PermissionMonitorTest {
- private static final int MOCK_UID = 10001;
- private static final String[] MOCK_PACKAGE_NAMES = new String[] { "com.foo.bar" };
+ private static final int MOCK_USER1 = 0;
+ private static final int MOCK_USER2 = 1;
+ private static final int MOCK_UID1 = 10001;
+ private static final String MOCK_PACKAGE1 = "appName1";
+ private static final String SYSTEM_PACKAGE1 = "sysName1";
+ private static final String SYSTEM_PACKAGE2 = "sysName2";
private static final String PARTITION_SYSTEM = "system";
private static final String PARTITION_OEM = "oem";
private static final String PARTITION_PRODUCT = "product";
@@ -63,6 +80,7 @@
@Mock private Context mContext;
@Mock private PackageManager mPackageManager;
+ @Mock private INetworkManagementService mNMS;
private PermissionMonitor mPermissionMonitor;
@@ -70,8 +88,7 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(MOCK_PACKAGE_NAMES);
- mPermissionMonitor = spy(new PermissionMonitor(mContext, null));
+ mPermissionMonitor = spy(new PermissionMonitor(mContext, mNMS));
}
private boolean hasBgPermission(String partition, int targetSdkVersion, int uid,
@@ -80,7 +97,8 @@
packageInfo.applicationInfo.targetSdkVersion = targetSdkVersion;
packageInfo.applicationInfo.uid = uid;
when(mPackageManager.getPackageInfoAsUser(
- eq(MOCK_PACKAGE_NAMES[0]), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
+ eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
+ when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[] {MOCK_PACKAGE1});
return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
}
@@ -143,16 +161,16 @@
@Test
public void testHasUseBackgroundNetworksPermission() throws Exception {
- assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID));
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CHANGE_NETWORK_STATE));
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, NETWORK_STACK));
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CONNECTIVITY_INTERNAL));
- assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID,
+ assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1));
+ assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
+ assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
+ assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1,
CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID, CHANGE_WIFI_STATE));
+ assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
- assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID));
- assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID, CHANGE_WIFI_STATE));
+ assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
+ assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
}
@Test
@@ -172,15 +190,150 @@
@Test
public void testHasUseBackgroundNetworksPermissionVendorApp() throws Exception {
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID));
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CHANGE_NETWORK_STATE));
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, NETWORK_STACK));
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CONNECTIVITY_INTERNAL));
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID,
+ assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1));
+ assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
+ assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, NETWORK_STACK));
+ assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
+ assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1,
CONNECTIVITY_USE_RESTRICTED_NETWORKS));
- assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID, CHANGE_WIFI_STATE));
+ assertTrue(hasBgPermission(PARTITION_VENDOR, VERSION_P, MOCK_UID1, CHANGE_WIFI_STATE));
- assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID));
- assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID, CHANGE_WIFI_STATE));
+ assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
+ assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
+ }
+
+ private class NMSMonitor {
+ private final HashMap<Integer, Boolean> mApps = new HashMap<>();
+
+ NMSMonitor(INetworkManagementService mockNMS) throws Exception {
+ // Add hook to verify and track result of setPermission.
+ doAnswer((InvocationOnMock invocation) -> {
+ final Object[] args = invocation.getArguments();
+ final Boolean isSystem = args[0].equals("SYSTEM");
+ for (final int uid : (int[]) args[1]) {
+ // TODO: Currently, permission monitor will send duplicate commands for each uid
+ // corresponding to each user. Need to fix that and uncomment below test.
+ // if (mApps.containsKey(uid) && mApps.get(uid) == isSystem) {
+ // fail("uid " + uid + " is already set to " + isSystem);
+ // }
+ mApps.put(uid, isSystem);
+ }
+ return null;
+ }).when(mockNMS).setPermission(anyString(), any(int[].class));
+
+ // Add hook to verify and track result of clearPermission.
+ doAnswer((InvocationOnMock invocation) -> {
+ final Object[] args = invocation.getArguments();
+ for (final int uid : (int[]) args[0]) {
+ // TODO: Currently, permission monitor will send duplicate commands for each uid
+ // corresponding to each user. Need to fix that and uncomment below test.
+ // if (!mApps.containsKey(uid)) {
+ // fail("uid " + uid + " does not exist.");
+ // }
+ mApps.remove(uid);
+ }
+ return null;
+ }).when(mockNMS).clearPermission(any(int[].class));
+ }
+
+ public void expectPermission(Boolean permission, int[] users, int[] apps) {
+ for (final int user : users) {
+ for (final int app : apps) {
+ final int uid = UserHandle.getUid(user, app);
+ if (!mApps.containsKey(uid)) {
+ fail("uid " + uid + " does not exist.");
+ }
+ if (mApps.get(uid) != permission) {
+ fail("uid " + uid + " has wrong permission: " + permission);
+ }
+ }
+ }
+ }
+
+ public void expectNoPermission(int[] users, int[] apps) {
+ for (final int user : users) {
+ for (final int app : apps) {
+ final int uid = UserHandle.getUid(user, app);
+ if (mApps.containsKey(uid)) {
+ fail("uid " + uid + " has listed permissions, expected none.");
+ }
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testUserAndPackageAddRemove() throws Exception {
+ final NMSMonitor mNMSMonitor = new NMSMonitor(mNMS);
+
+ // MOCK_UID1: MOCK_PACKAGE1 only has network permission.
+ // SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
+ // SYSTEM_UID: SYSTEM_PACKAGE2 only has network permission.
+ doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(eq(SYSTEM), anyString());
+ doReturn(SYSTEM).when(mPermissionMonitor).highestPermissionForUid(any(),
+ eq(SYSTEM_PACKAGE1));
+ doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
+ eq(SYSTEM_PACKAGE2));
+ doReturn(NETWORK).when(mPermissionMonitor).highestPermissionForUid(any(),
+ eq(MOCK_PACKAGE1));
+
+ // Add SYSTEM_PACKAGE2, expect only have network permission.
+ mPermissionMonitor.onUserAdded(MOCK_USER1);
+ addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
+ mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
+
+ // Add SYSTEM_PACKAGE1, expect permission escalate.
+ addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
+ mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
+
+ mPermissionMonitor.onUserAdded(MOCK_USER2);
+ mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
+ new int[]{SYSTEM_UID});
+
+ addPackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
+ mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
+ new int[]{SYSTEM_UID});
+ mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
+ new int[]{MOCK_UID1});
+
+ // Remove MOCK_UID1, expect no permission left for all user.
+ mPermissionMonitor.onPackageRemoved(MOCK_UID1);
+ removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
+ mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1});
+
+ // Remove SYSTEM_PACKAGE1, expect permission downgrade.
+ when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
+ removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID);
+ mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
+ new int[]{SYSTEM_UID});
+
+ mPermissionMonitor.onUserRemoved(MOCK_USER1);
+ mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER2}, new int[]{SYSTEM_UID});
+
+ // Remove all packages, expect no permission left.
+ when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
+ removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_UID);
+ mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
+ new int[]{SYSTEM_UID, MOCK_UID1});
+
+ // Remove last user, expect no redundant clearPermission is invoked.
+ mPermissionMonitor.onUserRemoved(MOCK_USER2);
+ mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
+ new int[]{SYSTEM_UID, MOCK_UID1});
+ }
+
+ // Normal package add/remove operations will trigger multiple intent for uids corresponding to
+ // each user. To simulate generic package operations, the onPackageAdded/Removed will need to be
+ // called multiple times with the uid corresponding to each user.
+ private void addPackageForUsers(int[] users, String packageName, int uid) {
+ for (final int user : users) {
+ mPermissionMonitor.onPackageAdded(packageName, UserHandle.getUid(user, uid));
+ }
+ }
+
+ private void removePackageForUsers(int[] users, int uid) {
+ for (final int user : users) {
+ mPermissionMonitor.onPackageRemoved(UserHandle.getUid(user, uid));
+ }
}
}
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index a6ed9f2..8081812 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -23,15 +23,15 @@
import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
-import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
-import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
+import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
+import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
import static android.provider.Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER;
@@ -39,19 +39,18 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.notNull;
-import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-import static org.mockito.Mockito.mock;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -91,9 +90,9 @@
import android.os.Looper;
import android.os.PersistableBundle;
import android.os.RemoteException;
-import android.os.test.TestLooper;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.test.TestLooper;
import android.provider.Settings;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -126,7 +125,6 @@
public class TetheringTest {
private static final int IFINDEX_OFFSET = 100;
- private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
private static final String TEST_MOBILE_IFNAME = "test_rmnet_data0";
private static final String TEST_XLAT_MOBILE_IFNAME = "v4-test_rmnet_data0";
private static final String TEST_USB_IFNAME = "test_rndis0";
@@ -370,61 +368,6 @@
mServiceContext.unregisterReceiver(mBroadcastReceiver);
}
- private void setupForRequiredProvisioning() {
- // Produce some acceptable looking provision app setting if requested.
- when(mResources.getStringArray(
- com.android.internal.R.array.config_mobile_hotspot_provision_app))
- .thenReturn(PROVISIONING_APP_NAME);
- // Don't disable tethering provisioning unless requested.
- when(mSystemProperties.getBoolean(eq(Tethering.DISABLE_PROVISIONING_SYSPROP_KEY),
- anyBoolean())).thenReturn(false);
- // Act like the CarrierConfigManager is present and ready unless told otherwise.
- when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
- .thenReturn(mCarrierConfigManager);
- when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
- mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
- }
-
- @Test
- public void canRequireProvisioning() {
- setupForRequiredProvisioning();
- sendConfigurationChanged();
- assertTrue(mTethering.isTetherProvisioningRequired());
- }
-
- @Test
- public void toleratesCarrierConfigManagerMissing() {
- setupForRequiredProvisioning();
- when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
- .thenReturn(null);
- sendConfigurationChanged();
- // Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
- // We therefore still require provisioning.
- assertTrue(mTethering.isTetherProvisioningRequired());
- }
-
- @Test
- public void toleratesCarrierConfigMissing() {
- setupForRequiredProvisioning();
- when(mCarrierConfigManager.getConfig()).thenReturn(null);
- sendConfigurationChanged();
- // We still have a provisioning app configured, so still require provisioning.
- assertTrue(mTethering.isTetherProvisioningRequired());
- }
-
- @Test
- public void provisioningNotRequiredWhenAppNotFound() {
- setupForRequiredProvisioning();
- when(mResources.getStringArray(
- com.android.internal.R.array.config_mobile_hotspot_provision_app))
- .thenReturn(null);
- assertTrue(!mTethering.isTetherProvisioningRequired());
- when(mResources.getStringArray(
- com.android.internal.R.array.config_mobile_hotspot_provision_app))
- .thenReturn(new String[] {"malformedApp"});
- assertTrue(!mTethering.isTetherProvisioningRequired());
- }
-
private void sendWifiApStateChanged(int state) {
final Intent intent = new Intent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
intent.putExtra(EXTRA_WIFI_AP_STATE, state);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
new file mode 100644
index 0000000..0f72229
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.util.SharedLog;
+import android.os.PersistableBundle;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.CarrierConfigManager;
+
+import com.android.internal.R;
+import com.android.server.connectivity.MockableSystemProperties;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class EntitlementManagerTest {
+
+ private static final int EVENT_EM_UPDATE = 1;
+ private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
+
+ @Mock private CarrierConfigManager mCarrierConfigManager;
+ @Mock private Context mContext;
+ @Mock private ContentResolver mContent;
+ @Mock private MockableSystemProperties mSystemProperties;
+ @Mock private Resources mResources;
+ @Mock private SharedLog mLog;
+
+ // Like so many Android system APIs, these cannot be mocked because it is marked final.
+ // We have to use the real versions.
+ private final PersistableBundle mCarrierConfig = new PersistableBundle();
+
+ private EntitlementManager mEnMgr;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getContentResolver()).thenReturn(mContent);
+ when(mResources.getStringArray(R.array.config_tether_dhcp_range))
+ .thenReturn(new String[0]);
+ when(mResources.getStringArray(R.array.config_tether_usb_regexs))
+ .thenReturn(new String[0]);
+ when(mResources.getStringArray(R.array.config_tether_wifi_regexs))
+ .thenReturn(new String[0]);
+ when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs))
+ .thenReturn(new String[0]);
+ when(mResources.getIntArray(R.array.config_tether_upstream_types))
+ .thenReturn(new int[0]);
+ when(mLog.forSubComponent(anyString())).thenReturn(mLog);
+
+ mEnMgr = new EntitlementManager(mContext, mLog, mSystemProperties);
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ }
+
+ @After
+ public void tearDown() throws Exception {}
+
+ private void setupForRequiredProvisioning() {
+ // Produce some acceptable looking provision app setting if requested.
+ when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
+ .thenReturn(PROVISIONING_APP_NAME);
+ // Don't disable tethering provisioning unless requested.
+ when(mSystemProperties.getBoolean(eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY),
+ anyBoolean())).thenReturn(false);
+ // Act like the CarrierConfigManager is present and ready unless told otherwise.
+ when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
+ .thenReturn(mCarrierConfigManager);
+ when(mCarrierConfigManager.getConfig()).thenReturn(mCarrierConfig);
+ mCarrierConfig.putBoolean(CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
+ }
+
+ @Test
+ public void canRequireProvisioning() {
+ setupForRequiredProvisioning();
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ assertTrue(mEnMgr.isTetherProvisioningRequired());
+ }
+
+ @Test
+ public void toleratesCarrierConfigManagerMissing() {
+ setupForRequiredProvisioning();
+ when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE))
+ .thenReturn(null);
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ // Couldn't get the CarrierConfigManager, but still had a declared provisioning app.
+ // Therefore provisioning still be required.
+ assertTrue(mEnMgr.isTetherProvisioningRequired());
+ }
+
+ @Test
+ public void toleratesCarrierConfigMissing() {
+ setupForRequiredProvisioning();
+ when(mCarrierConfigManager.getConfig()).thenReturn(null);
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ // We still have a provisioning app configured, so still require provisioning.
+ assertTrue(mEnMgr.isTetherProvisioningRequired());
+ }
+
+ @Test
+ public void provisioningNotRequiredWhenAppNotFound() {
+ setupForRequiredProvisioning();
+ when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
+ .thenReturn(null);
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ assertFalse(mEnMgr.isTetherProvisioningRequired());
+ when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
+ .thenReturn(new String[] {"malformedApp"});
+ mEnMgr.updateConfiguration(new TetheringConfiguration(mContext, mLog));
+ assertFalse(mEnMgr.isTetherProvisioningRequired());
+ }
+
+}
diff --git a/tools/stringslint/stringslint.py b/tools/stringslint/stringslint.py
index 03c0b9a..afe91cd 100644
--- a/tools/stringslint/stringslint.py
+++ b/tools/stringslint/stringslint.py
@@ -145,6 +145,13 @@
if "translatable" in child.attrib and child.attrib["translatable"].lower() == "false":
continue
+ misspelled_attributes = [
+ ("translateable", "translatable"),
+ ]
+ for misspelling, expected in misspelled_attributes:
+ if misspelling in child.attrib:
+ error(child, "Misspelled <string> attribute.", misspelling, expected)
+
limit = re.search("CHAR[ _-]LIMIT=(\d+|NONE|none)", comment.text)
if limit is None:
info(child, "Missing CHAR LIMIT to aid translation",
diff --git a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
index aa8d325..87706b9 100644
--- a/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
+++ b/wifi/java/android/net/wifi/WifiNetworkConfigBuilder.java
@@ -60,14 +60,27 @@
*/
private @Nullable Pair<MacAddress, MacAddress> mBssidPatternMatcher;
/**
+ * Whether this is an OWE network or not.
+ */
+ private boolean mIsEnhancedOpen;
+ /**
* Pre-shared key for use with WPA-PSK networks.
*/
- private @Nullable String mPskPassphrase;
+ private @Nullable String mWpa2PskPassphrase;
+ /**
+ * Pre-shared key for use with WPA3-SAE networks.
+ */
+ private @Nullable String mWpa3SaePassphrase;
/**
* The enterprise configuration details specifying the EAP method,
- * certificates and other settings associated with the EAP.
+ * certificates and other settings associated with the WPA-EAP networks.
*/
- private @Nullable WifiEnterpriseConfig mEnterpriseConfig;
+ private @Nullable WifiEnterpriseConfig mWpa2EnterpriseConfig;
+ /**
+ * The enterprise configuration details specifying the EAP method,
+ * certificates and other settings associated with the SuiteB networks.
+ */
+ private @Nullable WifiEnterpriseConfig mWpa3EnterpriseConfig;
/**
* This is a network that does not broadcast its SSID, so an
* SSID-specific probe request must be used for scans.
@@ -94,8 +107,11 @@
public WifiNetworkConfigBuilder() {
mSsidPatternMatcher = null;
mBssidPatternMatcher = null;
- mPskPassphrase = null;
- mEnterpriseConfig = null;
+ mIsEnhancedOpen = false;
+ mWpa2PskPassphrase = null;
+ mWpa3SaePassphrase = null;
+ mWpa2EnterpriseConfig = null;
+ mWpa3EnterpriseConfig = null;
mIsHiddenSSID = false;
mIsAppInteractionRequired = false;
mIsUserInteractionRequired = false;
@@ -188,36 +204,81 @@
}
/**
- * Set the ASCII PSK passphrase for this network. Needed for authenticating to
- * WPA_PSK networks.
+ * Specifies whether this represents an Enhanced Open (OWE) network.
*
- * @param pskPassphrase PSK passphrase of the network.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setIsEnhancedOpen() {
+ mIsEnhancedOpen = true;
+ return this;
+ }
+
+ /**
+ * Set the ASCII WPA2 passphrase for this network. Needed for authenticating to
+ * WPA2-PSK networks.
+ *
+ * @param passphrase passphrase of the network.
* @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
* method.
* @throws IllegalArgumentException if the passphrase is not ASCII encodable.
*/
- public WifiNetworkConfigBuilder setPskPassphrase(@NonNull String pskPassphrase) {
- checkNotNull(pskPassphrase);
+ public WifiNetworkConfigBuilder setWpa2Passphrase(@NonNull String passphrase) {
+ checkNotNull(passphrase);
final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
- if (!asciiEncoder.canEncode(pskPassphrase)) {
+ if (!asciiEncoder.canEncode(passphrase)) {
throw new IllegalArgumentException("passphrase not ASCII encodable");
}
- mPskPassphrase = pskPassphrase;
+ mWpa2PskPassphrase = passphrase;
+ return this;
+ }
+
+ /**
+ * Set the ASCII WPA3 passphrase for this network. Needed for authenticating to
+ * WPA3-SAE networks.
+ *
+ * @param passphrase passphrase of the network.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ * @throws IllegalArgumentException if the passphrase is not ASCII encodable.
+ */
+ public WifiNetworkConfigBuilder setWpa3Passphrase(@NonNull String passphrase) {
+ checkNotNull(passphrase);
+ final CharsetEncoder asciiEncoder = StandardCharsets.US_ASCII.newEncoder();
+ if (!asciiEncoder.canEncode(passphrase)) {
+ throw new IllegalArgumentException("passphrase not ASCII encodable");
+ }
+ mWpa3SaePassphrase = passphrase;
return this;
}
/**
* Set the associated enterprise configuration for this network. Needed for authenticating to
- * WPA_EAP networks. See {@link WifiEnterpriseConfig} for description.
+ * WPA2-EAP networks. See {@link WifiEnterpriseConfig} for description.
*
* @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
* @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
* method.
*/
- public WifiNetworkConfigBuilder setEnterpriseConfig(
+ public WifiNetworkConfigBuilder setWpa2EnterpriseConfig(
@NonNull WifiEnterpriseConfig enterpriseConfig) {
checkNotNull(enterpriseConfig);
- mEnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+ mWpa2EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
+ return this;
+ }
+
+ /**
+ * Set the associated enterprise configuration for this network. Needed for authenticating to
+ * WPA3-SuiteB networks. See {@link WifiEnterpriseConfig} for description.
+ *
+ * @param enterpriseConfig Instance of {@link WifiEnterpriseConfig}.
+ * @return Instance of {@link WifiNetworkConfigBuilder} to enable chaining of the builder
+ * method.
+ */
+ public WifiNetworkConfigBuilder setWpa3EnterpriseConfig(
+ @NonNull WifiEnterpriseConfig enterpriseConfig) {
+ checkNotNull(enterpriseConfig);
+ mWpa3EnterpriseConfig = new WifiEnterpriseConfig(enterpriseConfig);
return this;
}
@@ -324,16 +385,38 @@
configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
}
- private void setKeyMgmtInWifiConfiguration(@NonNull WifiConfiguration configuration) {
- if (!TextUtils.isEmpty(mPskPassphrase)) {
- // WPA_PSK network.
+ private void setSecurityParamsInWifiConfiguration(@NonNull WifiConfiguration configuration) {
+ if (!TextUtils.isEmpty(mWpa2PskPassphrase)) { // WPA-PSK network.
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
- } else if (mEnterpriseConfig != null) {
- // WPA_EAP network
+ // WifiConfiguration.preSharedKey needs quotes around ASCII password.
+ configuration.preSharedKey = "\"" + mWpa2PskPassphrase + "\"";
+ } else if (!TextUtils.isEmpty(mWpa3SaePassphrase)) { // WPA3-SAE network.
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
+ // PMF mandatory for SAE.
+ configuration.requirePMF = true;
+ // WifiConfiguration.preSharedKey needs quotes around ASCII password.
+ configuration.preSharedKey = "\"" + mWpa3SaePassphrase + "\"";
+ } else if (mWpa2EnterpriseConfig != null) { // WPA-EAP network
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
- } else {
- // Open network
+ configuration.enterpriseConfig = mWpa2EnterpriseConfig;
+ } else if (mWpa3EnterpriseConfig != null) { // WPA3-SuiteB network
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SUITE_B_192);
+ configuration.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
+ // TODO (b/113878056): Verify these params once we verify SuiteB configuration.
+ configuration.allowedGroupMgmtCiphers.set(
+ WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256);
+ configuration.allowedSuiteBCiphers.set(
+ WifiConfiguration.SuiteBCipher.ECDHE_ECDSA);
+ configuration.allowedSuiteBCiphers.set(
+ WifiConfiguration.SuiteBCipher.ECDHE_RSA);
+ configuration.requirePMF = true;
+ configuration.enterpriseConfig = mWpa3EnterpriseConfig;
+ } else if (mIsEnhancedOpen) { // OWE network
+ configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
+ // PMF mandatory.
+ configuration.requirePMF = true;
+ } else { // Open network
configuration.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
}
}
@@ -349,12 +432,7 @@
if (mSsidPatternMatcher.getType() == PatternMatcher.PATTERN_LITERAL) {
wifiConfiguration.SSID = "\"" + mSsidPatternMatcher.getPath() + "\"";
}
- setKeyMgmtInWifiConfiguration(wifiConfiguration);
- // WifiConfiguration.preSharedKey needs quotes around ASCII password.
- if (mPskPassphrase != null) {
- wifiConfiguration.preSharedKey = "\"" + mPskPassphrase + "\"";
- }
- wifiConfiguration.enterpriseConfig = mEnterpriseConfig;
+ setSecurityParamsInWifiConfiguration(wifiConfiguration);
wifiConfiguration.hiddenSSID = mIsHiddenSSID;
wifiConfiguration.priority = mPriority;
wifiConfiguration.meteredOverride =
@@ -396,6 +474,20 @@
return false;
}
+ private void validateSecurityParams() {
+ int numSecurityTypes = 0;
+ numSecurityTypes += mIsEnhancedOpen ? 1 : 0;
+ numSecurityTypes += !TextUtils.isEmpty(mWpa2PskPassphrase) ? 1 : 0;
+ numSecurityTypes += !TextUtils.isEmpty(mWpa3SaePassphrase) ? 1 : 0;
+ numSecurityTypes += mWpa2EnterpriseConfig != null ? 1 : 0;
+ numSecurityTypes += mWpa3EnterpriseConfig != null ? 1 : 0;
+ if (numSecurityTypes > 1) {
+ throw new IllegalStateException("only one of setIsEnhancedOpen, setWpa2Passphrase,"
+ + "setWpa3Passphrase, setWpa2EnterpriseConfig or setWpa3EnterpriseConfig"
+ + " can be invoked for network specifier");
+ }
+ }
+
/**
* Create a specifier object used to request a Wi-Fi network. The generated
* {@link NetworkSpecifier} should be used in
@@ -464,10 +556,7 @@
+ "setIsUserInteractionRequired/setPriority/setIsMetered are allowed for "
+ "specifier");
}
- if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) {
- throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can"
- + " be invoked for network specifier");
- }
+ validateSecurityParams();
return new WifiNetworkSpecifier(
mSsidPatternMatcher,
@@ -493,10 +582,7 @@
throw new IllegalStateException("none of setSsidPattern/setBssidPattern/setBssid are"
+ " allowed for suggestion");
}
- if (!TextUtils.isEmpty(mPskPassphrase) && mEnterpriseConfig != null) {
- throw new IllegalStateException("only one of setPreSharedKey or setEnterpriseConfig can"
- + "be invoked for suggestion");
- }
+ validateSecurityParams();
return new WifiNetworkSuggestion(
buildWifiConfiguration(),
diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
index 25dcdd8..893b19c 100644
--- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
+++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
@@ -49,7 +49,7 @@
/**
* SSID of the network to connect for service sign-up.
*/
- private final WifiSsid mOsuSsid;
+ private WifiSsid mOsuSsid;
/**
* Friendly name of the OSU provider.
@@ -130,6 +130,10 @@
return mOsuSsid;
}
+ public void setOsuSsid(WifiSsid osuSsid) {
+ mOsuSsid = osuSsid;
+ }
+
public String getFriendlyName() {
return mFriendlyName;
}
diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
index 5c9db53..a62d63c 100644
--- a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
+++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
@@ -150,6 +150,12 @@
public static final int OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION = 22;
/**
+ * The reason code for provisioning failure when an {@link OsuProvider} is not found for
+ * provisioning.
+ */
+ public static final int OSU_FAILURE_OSU_PROVIDER_NOT_FOUND = 23;
+
+ /**
* The status code for provisioning flow to indicate connecting to OSU AP
*/
public static final int OSU_STATUS_AP_CONNECTING = 1;
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
index 8980ddb..c455c6f 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkConfigBuilderTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.net.MacAddress;
@@ -81,11 +82,11 @@
* pattern.
*/
@Test
- public void testWifiNetworkSpecifierBuilderForWpaPskNetworkWithBssidPattern() {
+ public void testWifiNetworkSpecifierBuilderForWpa2PskNetworkWithBssidPattern() {
NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
.setBssidPattern(MacAddress.fromString(TEST_BSSID_OUI_BASE_ADDRESS),
MacAddress.fromString(TEST_BSSID_OUI_MASK))
- .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
.buildNetworkSpecifier();
assertTrue(specifier instanceof WifiNetworkSpecifier);
@@ -119,7 +120,7 @@
* SSID and BSSID pattern.
*/
@Test
- public void testWifiNetworkSpecifierBuilderForEnterpriseHiddenNetworkWithSsidAndBssid() {
+ public void testWifiNetworkSpecifierBuilderForWpa2EapHiddenNetworkWithSsidAndBssid() {
WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
@@ -127,7 +128,7 @@
NetworkSpecifier specifier = new WifiNetworkConfigBuilder()
.setSsid(TEST_SSID)
.setBssid(MacAddress.fromString(TEST_BSSID))
- .setEnterpriseConfig(enterpriseConfig)
+ .setWpa2EnterpriseConfig(enterpriseConfig)
.setIsHiddenSsid()
.buildNetworkSpecifier();
@@ -174,14 +175,14 @@
}
/**
- * Ensure {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} throws an exception
+ * Ensure {@link WifiNetworkConfigBuilder#setWpa2Passphrase(String)} throws an exception
* when the string is not ASCII encodable.
*/
@Test(expected = IllegalArgumentException.class)
- public void testSetPskPassphraseWithNonAsciiString() {
+ public void testSetWpa2PasphraseWithNonAsciiString() {
new WifiNetworkConfigBuilder()
.setSsid(TEST_SSID)
- .setPskPassphrase("salvē")
+ .setWpa2Passphrase("salvē")
.buildNetworkSpecifier();
}
@@ -275,15 +276,15 @@
/**
* Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
- * when both {@link WifiNetworkConfigBuilder#setPskPassphrase(String)} and
- * {@link WifiNetworkConfigBuilder#setEnterpriseConfig(WifiEnterpriseConfig)} are invoked.
+ * when both {@link WifiNetworkConfigBuilder#setWpa2Passphrase(String)} and
+ * {@link WifiNetworkConfigBuilder#setWpa2EnterpriseConfig(WifiEnterpriseConfig)} are invoked.
*/
@Test(expected = IllegalStateException.class)
- public void testWifiNetworkSpecifierBuilderWithBothPskPassphraseAndEnterpriseConfig() {
+ public void testWifiNetworkSpecifierBuilderWithBothWpa2PasphraseAndEnterpriseConfig() {
new WifiNetworkConfigBuilder()
.setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
- .setPskPassphrase(TEST_PRESHARED_KEY)
- .setEnterpriseConfig(new WifiEnterpriseConfig())
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
+ .setWpa2EnterpriseConfig(new WifiEnterpriseConfig())
.buildNetworkSpecifier();
}
@@ -375,10 +376,11 @@
* app interaction and has a priority of zero set.
*/
@Test
- public void testWifiNetworkSuggestionBuilderForWpaEapNetworkWithPriorityAndReqAppInteraction() {
+ public void
+ testWifiNetworkSuggestionBuilderForWpa2EapNetworkWithPriorityAndReqAppInteraction() {
WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
.setSsid(TEST_SSID)
- .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
.setIsAppInteractionRequired()
.setPriority(0)
.buildNetworkSuggestion();
@@ -401,10 +403,11 @@
* user interaction and is metered.
*/
@Test
- public void testWifiNetworkSuggestionBuilderForWpaPskNetworkWithMeteredAndReqUserInteraction() {
+ public void
+ testWifiNetworkSuggestionBuilderForWpa2PskNetworkWithMeteredAndReqUserInteraction() {
WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
.setSsid(TEST_SSID)
- .setPskPassphrase(TEST_PRESHARED_KEY)
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
.setIsUserInteractionRequired()
.setIsMetered()
.buildNetworkSuggestion();
@@ -422,6 +425,74 @@
}
/**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for OWE network.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForEnhancedOpenNetwork() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setIsEnhancedOpen()
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.OWE));
+ assertNull(suggestion.wifiConfiguration.preSharedKey);
+ assertTrue(suggestion.wifiConfiguration.requirePMF);
+ }
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for SAE network.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForWpa3PskNetwork() {
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setWpa3Passphrase(TEST_PRESHARED_KEY)
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.SAE));
+ assertEquals("\"" + TEST_PRESHARED_KEY + "\"",
+ suggestion.wifiConfiguration.preSharedKey);
+ assertTrue(suggestion.wifiConfiguration.requirePMF);
+ }
+
+
+ /**
+ * Validate correctness of WifiNetworkSuggestion object created by
+ * {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} for SuiteB network.
+ */
+ @Test
+ public void testWifiNetworkSuggestionBuilderForWpa3EapNetwork() {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.TLS);
+ enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.GTC);
+
+ WifiNetworkSuggestion suggestion = new WifiNetworkConfigBuilder()
+ .setSsid(TEST_SSID)
+ .setWpa3EnterpriseConfig(enterpriseConfig)
+ .buildNetworkSuggestion();
+
+ assertEquals("\"" + TEST_SSID + "\"", suggestion.wifiConfiguration.SSID);
+ assertTrue(suggestion.wifiConfiguration.allowedKeyManagement
+ .get(WifiConfiguration.KeyMgmt.SUITE_B_192));
+ assertTrue(suggestion.wifiConfiguration.allowedGroupCiphers
+ .get(WifiConfiguration.GroupCipher.GCMP_256));
+ assertTrue(suggestion.wifiConfiguration.allowedGroupMgmtCiphers
+ .get(WifiConfiguration.GroupMgmtCipher.BIP_GMAC_256));
+ assertTrue(suggestion.wifiConfiguration.allowedSuiteBCiphers
+ .get(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA));
+ assertTrue(suggestion.wifiConfiguration.allowedSuiteBCiphers
+ .get(WifiConfiguration.SuiteBCipher.ECDHE_RSA));
+ assertTrue(suggestion.wifiConfiguration.requirePMF);
+ assertNull(suggestion.wifiConfiguration.preSharedKey);
+ }
+
+ /**
* Ensure {@link WifiNetworkConfigBuilder#buildNetworkSuggestion()} throws an exception
* when {@link WifiNetworkConfigBuilder#setSsidPattern(PatternMatcher)} is set.
*/
@@ -478,4 +549,46 @@
.setPriority(-1)
.buildNetworkSuggestion();
}
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when both {@link WifiNetworkConfigBuilder#setWpa2Passphrase(String)} and
+ * {@link WifiNetworkConfigBuilder#setWpa3Passphrase(String)} are invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithBothWpa2PasphraseAndWpa3Passphrase() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setWpa2Passphrase(TEST_PRESHARED_KEY)
+ .setWpa3Passphrase(TEST_PRESHARED_KEY)
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when both {@link WifiNetworkConfigBuilder#setWpa3Passphrase(String)} and
+ * {@link WifiNetworkConfigBuilder#setWpa3EnterpriseConfig(WifiEnterpriseConfig)} are invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithBothWpa3PasphraseAndEnterprise() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setWpa3Passphrase(TEST_PRESHARED_KEY)
+ .setWpa3EnterpriseConfig(new WifiEnterpriseConfig())
+ .buildNetworkSpecifier();
+ }
+
+ /**
+ * Ensure {@link WifiNetworkConfigBuilder#buildNetworkSpecifier()} throws an exception
+ * when both {@link WifiNetworkConfigBuilder#setWpa3Passphrase(String)} and
+ * {@link WifiNetworkConfigBuilder#setIsEnhancedOpen(} are invoked.
+ */
+ @Test(expected = IllegalStateException.class)
+ public void testWifiNetworkSpecifierBuilderWithBothWpa3PasphraseAndEnhancedOpen() {
+ new WifiNetworkConfigBuilder()
+ .setSsidPattern(new PatternMatcher(TEST_SSID, PATTERN_LITERAL))
+ .setWpa3Passphrase(TEST_PRESHARED_KEY)
+ .setIsEnhancedOpen()
+ .buildNetworkSpecifier();
+ }
}