Merge "settings command list by user"
diff --git a/Android.bp b/Android.bp
index 1012bb81..7e038ce8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -254,6 +254,7 @@
":statsd_aidl",
"core/java/android/os/ISystemUpdateManager.aidl",
"core/java/android/os/IThermalEventListener.aidl",
+ "core/java/android/os/IThermalStatusListener.aidl",
"core/java/android/os/IThermalService.aidl",
"core/java/android/os/IUpdateLock.aidl",
"core/java/android/os/IUserManager.aidl",
@@ -334,8 +335,10 @@
"core/java/android/service/chooser/IChooserTargetResult.aidl",
"core/java/android/service/resolver/IResolverRankerService.aidl",
"core/java/android/service/resolver/IResolverRankerResult.aidl",
+ "core/java/android/service/textclassifier/IConversationActionsCallback.aidl",
"core/java/android/service/textclassifier/ITextClassificationCallback.aidl",
"core/java/android/service/textclassifier/ITextClassifierService.aidl",
+ "core/java/android/service/textclassifier/ITextLanguageCallback.aidl",
"core/java/android/service/textclassifier/ITextLinksCallback.aidl",
"core/java/android/service/textclassifier/ITextSelectionCallback.aidl",
"core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl",
@@ -455,7 +458,6 @@
"media/java/android/media/IMediaScannerListener.aidl",
"media/java/android/media/IMediaScannerService.aidl",
"media/java/android/media/IPlaybackConfigDispatcher.aidl",
- "media/java/android/media/ISessionTokensListener.aidl",
":libaudioclient_aidl",
"media/java/android/media/IRecordingConfigDispatcher.aidl",
"media/java/android/media/IRemoteDisplayCallback.aidl",
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index ec3366c..5936ee4 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -10,3 +10,5 @@
ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES}
owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$"
+
+shell_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^packages/Shell/"
diff --git a/api/current.txt b/api/current.txt
index aa400cd..e84bc8d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9601,6 +9601,7 @@
method public abstract void unbindService(android.content.ServiceConnection);
method public void unregisterComponentCallbacks(android.content.ComponentCallbacks);
method public abstract void unregisterReceiver(android.content.BroadcastReceiver);
+ method public abstract void updateServiceGroup(android.content.ServiceConnection, int, int);
field public static final java.lang.String ACCESSIBILITY_SERVICE = "accessibility";
field public static final java.lang.String ACCOUNT_SERVICE = "account";
field public static final java.lang.String ACTIVITY_SERVICE = "activity";
@@ -9799,6 +9800,7 @@
method public boolean stopService(android.content.Intent);
method public void unbindService(android.content.ServiceConnection);
method public void unregisterReceiver(android.content.BroadcastReceiver);
+ method public void updateServiceGroup(android.content.ServiceConnection, int, int);
}
public deprecated class CursorLoader extends android.content.AsyncTaskLoader {
@@ -42859,6 +42861,7 @@
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
+ field public static final java.lang.String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
field public static final java.lang.String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array";
@@ -56237,6 +56240,7 @@
}
public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
+ ctor public InMemoryDexClassLoader(java.nio.ByteBuffer[], java.lang.String, java.lang.ClassLoader);
ctor public InMemoryDexClassLoader(java.nio.ByteBuffer[], java.lang.ClassLoader);
ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 8d800bc..bf2c357 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5191,8 +5191,10 @@
method public abstract void onClassifyText(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextClassification.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextClassification>);
method public void onCreateTextClassificationSession(android.view.textclassifier.TextClassificationContext, android.view.textclassifier.TextClassificationSessionId);
method public void onDestroyTextClassificationSession(android.view.textclassifier.TextClassificationSessionId);
+ method public void onDetectLanguage(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextLanguage.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLanguage>);
method public abstract void onGenerateLinks(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextLinks.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextLinks>);
method public void onSelectionEvent(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.SelectionEvent);
+ method public void onSuggestConversationActions(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.ConversationActions.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.ConversationActions>);
method public abstract void onSuggestSelection(android.view.textclassifier.TextClassificationSessionId, android.view.textclassifier.TextSelection.Request, android.os.CancellationSignal, android.service.textclassifier.TextClassifierService.Callback<android.view.textclassifier.TextSelection>);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.textclassifier.TextClassifierService";
}
@@ -6254,6 +6256,45 @@
field public static final android.os.Parcelable.Creator<android.telephony.ims.ImsExternalCallState> CREATOR;
}
+ public class ImsMmTelManager {
+ method public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(android.content.Context, int);
+ method public int getVoWiFiModeSetting();
+ method public boolean isAdvancedCallingSettingEnabled();
+ method public boolean isAvailable(int, int);
+ method public boolean isCapable(int, int);
+ method public boolean isVoWiFiRoamingSettingEnabled();
+ method public boolean isVoWiFiSettingEnabled();
+ method public boolean isVtSettingEnabled();
+ method public void registerImsRegistrationCallback(java.util.concurrent.Executor, android.telephony.ims.ImsMmTelManager.RegistrationCallback);
+ method public void registerMmTelCapabilityCallback(java.util.concurrent.Executor, android.telephony.ims.ImsMmTelManager.CapabilityCallback);
+ method public void setAdvancedCallingSetting(boolean);
+ method public void setRttCapabilitySetting(boolean);
+ method public void setVoWiFiModeSetting(int);
+ method public void setVoWiFiNonPersistent(boolean, int);
+ method public void setVoWiFiRoamingModeSetting(int);
+ method public void setVoWiFiRoamingSetting(boolean);
+ method public void setVoWiFiSetting(boolean);
+ method public void setVtSetting(boolean);
+ method public void unregisterImsRegistrationCallback(android.telephony.ims.ImsMmTelManager.RegistrationCallback);
+ method public void unregisterMmTelCapabilityCallback(android.telephony.ims.ImsMmTelManager.CapabilityCallback);
+ field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1
+ field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0
+ field public static final int WIFI_MODE_WIFI_PREFERRED = 2; // 0x2
+ }
+
+ public static class ImsMmTelManager.CapabilityCallback {
+ ctor public ImsMmTelManager.CapabilityCallback();
+ method public void onCapabilitiesStatusChanged(android.telephony.ims.feature.MmTelFeature.MmTelCapabilities);
+ }
+
+ public static class ImsMmTelManager.RegistrationCallback {
+ ctor public ImsMmTelManager.RegistrationCallback();
+ method public void onDeregistered(android.telephony.ims.ImsReasonInfo);
+ method public void onRegistered(int);
+ method public void onRegistering(int);
+ method public void onTechnologyChangeFailed(int, android.telephony.ims.ImsReasonInfo);
+ }
+
public final class ImsReasonInfo implements android.os.Parcelable {
ctor public ImsReasonInfo(int, int, java.lang.String);
method public int describeContents();
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index 1191e6a..020c443 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -48,8 +48,6 @@
using android::Res_value;
using android::ResStringPool;
using android::ResTable_config;
-using android::String16;
-using android::String8;
using android::StringPiece16;
using android::base::StringPrintf;
using android::idmap2::CommandLineOptions;
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index e5764f04..2dcf50f 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -12274,7 +12274,7 @@
HPLorg/ccil/cowan/tagsoup/AttributesImpl;->setAttribute(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
HPLorg/ccil/cowan/tagsoup/Element;->anonymize()V
HPLorg/ccil/cowan/tagsoup/Element;->preclose()V
-HPLorg/ccil/cowan/tagsoup/HTMLSchema;-><init>()V
+# HPLorg/ccil/cowan/tagsoup/HTMLSchema;-><init>()V b/76145463
HPLorg/json/JSONArray;->optDouble(I)D
HPLorg/json/JSONArray;->optDouble(ID)D
HPLorg/json/JSONStringer;->value(J)Lorg/json/JSONStringer;
@@ -15623,7 +15623,7 @@
HSPLandroid/app/admin/IDevicePolicyManager$Stub$Proxy;->isLockTaskPermitted(Ljava/lang/String;)Z
HSPLandroid/app/admin/IDevicePolicyManager$Stub$Proxy;->isProvisioningAllowed(Ljava/lang/String;Ljava/lang/String;)Z
HSPLandroid/app/admin/IDevicePolicyManager$Stub;-><init>()V
-HSPLandroid/app/admin/IDevicePolicyManager$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
+# HSPLandroid/app/admin/IDevicePolicyManager$Stub;->onTransact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z b/76145463
HSPLandroid/app/admin/IDevicePolicyManager;->addCrossProfileIntentFilter(Landroid/content/ComponentName;Landroid/content/IntentFilter;I)V
HSPLandroid/app/admin/IDevicePolicyManager;->addCrossProfileWidgetProvider(Landroid/content/ComponentName;Ljava/lang/String;)Z
HSPLandroid/app/admin/IDevicePolicyManager;->addOverrideApn(Landroid/content/ComponentName;Landroid/telephony/data/ApnSetting;)I
@@ -25254,7 +25254,7 @@
HSPLandroid/media/MediaCodecInfo$VideoCapabilities;->parseFromInfo(Landroid/media/MediaFormat;)V
HSPLandroid/media/MediaCodecInfo$VideoCapabilities;->parseWidthHeightRanges(Ljava/lang/Object;)Landroid/util/Pair;
HSPLandroid/media/MediaCodecInfo$VideoCapabilities;->supports(Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Number;)Z
-HSPLandroid/media/MediaCodecInfo$VideoCapabilities;->updateLimits()V
+# HSPLandroid/media/MediaCodecInfo$VideoCapabilities;->updateLimits()V b/76145463
HSPLandroid/media/MediaCodecInfo;-><init>(Ljava/lang/String;Z[Landroid/media/MediaCodecInfo$CodecCapabilities;)V
HSPLandroid/media/MediaCodecInfo;->access$200()Landroid/util/Range;
HSPLandroid/media/MediaCodecInfo;->access$300()Landroid/util/Range;
@@ -37845,7 +37845,7 @@
HSPLandroid/widget/ViewSwitcher;->getNextView()Landroid/view/View;
HSPLandroid/widget/WrapperListAdapter;->getWrappedAdapter()Landroid/widget/ListAdapter;
HSPLcom/android/i18n/phonenumbers/AlternateFormatsCountryCodeSet;->getCountryCodeSet()Ljava/util/Set;
-HSPLcom/android/i18n/phonenumbers/CountryCodeToRegionCodeMap;->getCountryCodeToRegionCodeMap()Ljava/util/Map;
+# HSPLcom/android/i18n/phonenumbers/CountryCodeToRegionCodeMap;->getCountryCodeToRegionCodeMap()Ljava/util/Map; b/76145463
HSPLcom/android/i18n/phonenumbers/MetadataLoader;->loadMetadata(Ljava/lang/String;)Ljava/io/InputStream;
HSPLcom/android/i18n/phonenumbers/MetadataManager$1;-><init>()V
HSPLcom/android/i18n/phonenumbers/MetadataManager$1;->loadMetadata(Ljava/lang/String;)Ljava/io/InputStream;
@@ -37999,7 +37999,7 @@
HSPLcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->setCountryCodeSource(Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber$CountryCodeSource;)Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;
HSPLcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->setNationalNumber(J)Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;
HSPLcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;->setRawInput(Ljava/lang/String;)Lcom/android/i18n/phonenumbers/Phonenumber$PhoneNumber;
-HSPLcom/android/i18n/phonenumbers/ShortNumbersRegionCodeSet;->getRegionCodeSet()Ljava/util/Set;
+# HSPLcom/android/i18n/phonenumbers/ShortNumbersRegionCodeSet;->getRegionCodeSet()Ljava/util/Set; b/76145463
HSPLcom/android/i18n/phonenumbers/internal/MatcherApi;->matchNationalNumber(Ljava/lang/CharSequence;Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;Z)Z
HSPLcom/android/i18n/phonenumbers/internal/RegexBasedMatcher;->matchNationalNumber(Ljava/lang/CharSequence;Lcom/android/i18n/phonenumbers/Phonemetadata$PhoneNumberDesc;Z)Z
HSPLcom/android/i18n/phonenumbers/internal/RegexCache$LRUCache$1;->removeEldestEntry(Ljava/util/Map$Entry;)Z
@@ -38978,7 +38978,7 @@
HSPLcom/android/internal/os/BatteryStatsImpl$Uid;->updateUidProcessStateLocked(I)V
HSPLcom/android/internal/os/BatteryStatsImpl$Uid;->writeJobCompletionsToParcelLocked(Landroid/os/Parcel;)V
HSPLcom/android/internal/os/BatteryStatsImpl$UserInfoProvider;->getUserIds()[I
-HSPLcom/android/internal/os/BatteryStatsImpl;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Landroid/os/Parcel;)V
+# HSPLcom/android/internal/os/BatteryStatsImpl;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Landroid/os/Parcel;)V b/76145463
HSPLcom/android/internal/os/BatteryStatsImpl;-><init>(Lcom/android/internal/os/BatteryStatsImpl$Clocks;Ljava/io/File;Landroid/os/Handler;Lcom/android/internal/os/BatteryStatsImpl$PlatformIdleStateCallback;Lcom/android/internal/os/BatteryStatsImpl$UserInfoProvider;)V
HSPLcom/android/internal/os/BatteryStatsImpl;-><init>(Ljava/io/File;Landroid/os/Handler;Lcom/android/internal/os/BatteryStatsImpl$PlatformIdleStateCallback;Lcom/android/internal/os/BatteryStatsImpl$UserInfoProvider;)V
HSPLcom/android/internal/os/BatteryStatsImpl;->addHistoryBufferLocked(JBLandroid/os/BatteryStats$HistoryItem;)V
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 553acc8..83fab7e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1432,7 +1432,15 @@
if (mAutoFillResetNeeded) {
if (!mAutoFillIgnoreFirstResumePause) {
View focus = getCurrentFocus();
- if (focus != null && focus.canNotifyAutofillEnterExitEvent()) {
+ // On Activity rotation situation (mRestoredFromBundle is true),
+ // we should not call on AutofillManager in onResume()
+ // since the next Layout pass will do that.
+ // However, there are both cases where Activity#getCurrentFocus()
+ // will return null (window not preserved) and not null (window IS
+ // preserved), so we need to explicitly check for mRestoredFromBundle
+ // here.
+ if (!mRestoredFromBundle && focus != null
+ && focus.canNotifyAutofillEnterExitEvent()) {
// TODO: in Activity killed/recreated case, i.e. SessionLifecycleTest#
// testDatasetVisibleWhileAutofilledAppIsLifecycled: the View's initial
// window visibility after recreation is INVISIBLE in onResume() and next frame
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index 30d6bee..9ef24c6 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -27,6 +27,7 @@
import dalvik.system.PathClassLoader;
import java.util.Collection;
+import java.util.List;
/** @hide */
public class ApplicationLoaders {
@@ -38,15 +39,25 @@
ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
String librarySearchPath, String libraryPermittedPath,
ClassLoader parent, String classLoaderName) {
+ return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
+ librarySearchPath, libraryPermittedPath, parent, classLoaderName,
+ null);
+ }
+
+ ClassLoader getClassLoaderWithSharedLibraries(
+ String zip, int targetSdkVersion, boolean isBundled,
+ String librarySearchPath, String libraryPermittedPath,
+ ClassLoader parent, String classLoaderName,
+ List<ClassLoader> sharedLibraries) {
// For normal usage the cache key used is the same as the zip path.
return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
- libraryPermittedPath, parent, zip, classLoaderName);
+ libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries);
}
private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
String librarySearchPath, String libraryPermittedPath,
ClassLoader parent, String cacheKey,
- String classLoaderName) {
+ String classLoaderName, List<ClassLoader> sharedLibraries) {
/*
* This is the parent we use if they pass "null" in. In theory
* this should be the "system" class loader; in practice we
@@ -75,7 +86,7 @@
ClassLoader classloader = ClassLoaderFactory.createClassLoader(
zip, librarySearchPath, libraryPermittedPath, parent,
- targetSdkVersion, isBundled, classLoaderName);
+ targetSdkVersion, isBundled, classLoaderName, sharedLibraries);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
@@ -90,7 +101,7 @@
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
ClassLoader loader = ClassLoaderFactory.createClassLoader(
- zip, null, parent, classLoaderName);
+ zip, null, parent, classLoaderName, sharedLibraries);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
return loader;
}
@@ -110,7 +121,7 @@
// The cache key is passed separately to enable the stub WebView to be cached under the
// stub's APK path, when the actual package path is the donor APK.
return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null,
- cacheKey, null /* classLoaderName */);
+ cacheKey, null /* classLoaderName */, null /* sharedLibraries */);
}
/**
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 9837deb..28ecb27 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1724,6 +1724,24 @@
}
@Override
+ public void updateServiceGroup(@NonNull ServiceConnection conn, int group, int importance) {
+ if (conn == null) {
+ throw new IllegalArgumentException("connection is null");
+ }
+ if (mPackageInfo != null) {
+ IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
+ getOuterContext(), conn);
+ try {
+ ActivityManager.getService().updateServiceGroup(sd, group, importance);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ } else {
+ throw new RuntimeException("Not supported in system context");
+ }
+ }
+
+ @Override
public void unbindService(ServiceConnection conn) {
if (conn == null) {
throw new IllegalArgumentException("connection is null");
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index f27c667..e83bcd0 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -140,6 +140,7 @@
int bindIsolatedService(in IApplicationThread caller, in IBinder token, in Intent service,
in String resolvedType, in IServiceConnection connection, int flags,
in String instanceName, in String callingPackage, int userId);
+ void updateServiceGroup(in IServiceConnection connection, int group, int importance);
boolean unbindService(in IServiceConnection connection);
void publishService(in IBinder token, in Intent intent, in IBinder service);
void setDebugApp(in String packageName, boolean waitForDebugger, boolean persistent);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index da4f77b..3f10754 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -29,6 +29,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.SharedLibraryInfo;
import android.content.pm.dex.ArtManager;
import android.content.pm.split.SplitDependencyLoader;
import android.content.res.AssetManager;
@@ -70,8 +71,10 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
final class IntentReceiverLeaked extends AndroidRuntimeException {
@UnsupportedAppUsage
@@ -397,6 +400,24 @@
makePaths(activityThread, false, aInfo, outZipPaths, null);
}
+ private static void appendSharedLibrariesLibPathsIfNeeded(
+ List<SharedLibraryInfo> sharedLibraries, ApplicationInfo aInfo,
+ Set<String> outSeenPaths,
+ List<String> outLibPaths) {
+ if (sharedLibraries == null) {
+ return;
+ }
+ for (SharedLibraryInfo lib : sharedLibraries) {
+ List<String> paths = lib.getAllCodePaths();
+ outSeenPaths.addAll(paths);
+ for (String path : paths) {
+ appendApkLibPathIfNeeded(path, aInfo, outLibPaths);
+ }
+ appendSharedLibrariesLibPathsIfNeeded(
+ lib.getDependencies(), aInfo, outSeenPaths, outLibPaths);
+ }
+ }
+
public static void makePaths(ActivityThread activityThread,
boolean isBundledApp,
ApplicationInfo aInfo,
@@ -404,7 +425,6 @@
List<String> outLibPaths) {
final String appDir = aInfo.sourceDir;
final String libDir = aInfo.nativeLibraryDir;
- final String[] sharedLibraries = aInfo.sharedLibraryFiles;
outZipPaths.clear();
outZipPaths.add(appDir);
@@ -499,11 +519,19 @@
}
}
- // Prepend the shared libraries, maintaining their original order where possible.
- if (sharedLibraries != null) {
+ // Add the shared libraries native paths. The dex files in shared libraries will
+ // be resolved through shared library loaders, which are setup later.
+ Set<String> outSeenPaths = new LinkedHashSet<>();
+ appendSharedLibrariesLibPathsIfNeeded(
+ aInfo.sharedLibraryInfos, aInfo, outSeenPaths, outLibPaths);
+
+ // ApplicationInfo.sharedLibraryFiles is a public API, so anyone can change it.
+ // We prepend shared libraries that the package manager hasn't seen, maintaining their
+ // original order where possible.
+ if (aInfo.sharedLibraryFiles != null) {
int index = 0;
- for (String lib : sharedLibraries) {
- if (!outZipPaths.contains(lib)) {
+ for (String lib : aInfo.sharedLibraryFiles) {
+ if (!outSeenPaths.contains(lib) && !outZipPaths.contains(lib)) {
outZipPaths.add(index, lib);
index++;
appendApkLibPathIfNeeded(lib, aInfo, outLibPaths);
@@ -631,6 +659,43 @@
return mSplitLoader.getSplitPathsForSplit(splitName);
}
+ /**
+ * Create a class loader for the {@code sharedLibrary}. Shared libraries are canonicalized,
+ * so if we already created a class loader with that shared library, we return it.
+ *
+ * Implementation notes: the canonicalization of shared libraries is something dex2oat
+ * also does.
+ */
+ ClassLoader createSharedLibraryLoader(SharedLibraryInfo sharedLibrary,
+ boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) {
+ List<String> paths = sharedLibrary.getAllCodePaths();
+ List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders(
+ sharedLibrary.getDependencies(), isBundledApp, librarySearchPath,
+ libraryPermittedPath);
+ final String jars = (paths.size() == 1) ? paths.get(0) :
+ TextUtils.join(File.pathSeparator, paths);
+
+ // Shared libraries get a null parent: this has the side effect of having canonicalized
+ // shared libraries using ApplicationLoaders cache, which is the behavior we want.
+ return ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(jars,
+ mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
+ libraryPermittedPath, /* parent */ null,
+ /* classLoaderName */ null, sharedLibraries);
+ }
+
+ private List<ClassLoader> createSharedLibrariesLoaders(List<SharedLibraryInfo> sharedLibraries,
+ boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) {
+ if (sharedLibraries == null) {
+ return null;
+ }
+ List<ClassLoader> loaders = new ArrayList<>();
+ for (SharedLibraryInfo info : sharedLibraries) {
+ loaders.add(createSharedLibraryLoader(
+ info, isBundledApp, librarySearchPath, libraryPermittedPath));
+ }
+ return loaders;
+ }
+
private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
if (mPackageName.equals("android")) {
// Note: This branch is taken for system server and we don't need to setup
@@ -759,10 +824,14 @@
// as this is early and necessary.
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
- mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
- mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
+ List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders(
+ mApplicationInfo.sharedLibraryInfos, isBundledApp, librarySearchPath,
+ libraryPermittedPath);
+
+ mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(
+ zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
libraryPermittedPath, mBaseClassLoader,
- mApplicationInfo.classLoaderName);
+ mApplicationInfo.classLoaderName, sharedLibraries);
mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
StrictMode.setThreadPolicy(oldPolicy);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 450efdf..f2a3e44 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3193,6 +3193,25 @@
}
/**
+ * Returns the actions that are contextual (marked as SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) out
+ * of the actions in this notification.
+ *
+ * @hide
+ */
+ public List<Notification.Action> getContextualActions() {
+ if (actions == null) return Collections.emptyList();
+
+ List<Notification.Action> contextualActions = new ArrayList<>();
+ for (Notification.Action action : actions) {
+ if (action.getSemanticAction()
+ == Notification.Action.SEMANTIC_ACTION_CONTEXTUAL_SUGGESTION) {
+ contextualActions.add(action);
+ }
+ }
+ return contextualActions;
+ }
+
+ /**
* Builder class for {@link Notification} objects.
*
* Provides a convenient way to set the various fields of a {@link Notification} and generate
@@ -7461,7 +7480,11 @@
return mRemoteInputHistory;
}
- private Bundle toBundle() {
+ /**
+ * @hide
+ */
+ @VisibleForTesting
+ public Bundle toBundle() {
Bundle bundle = new Bundle();
if (mText != null) {
bundle.putCharSequence(KEY_TEXT, mText);
diff --git a/core/java/android/app/Person.java b/core/java/android/app/Person.java
index 3884a8d..a2dae3b 100644
--- a/core/java/android/app/Person.java
+++ b/core/java/android/app/Person.java
@@ -22,6 +22,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Objects;
+
/**
* Provides an immutable reference to an entity that appears repeatedly on different surfaces of the
* platform. For example, this could represent the sender of a message.
@@ -121,6 +123,26 @@
}
@Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Person) {
+ final Person other = (Person) obj;
+ return Objects.equals(mName, other.mName)
+ && mIcon == null ? other.mIcon == null :
+ (other.mIcon != null && mIcon.sameAs(other.mIcon))
+ && Objects.equals(mUri, other.mUri)
+ && Objects.equals(mKey, other.mKey)
+ && mIsBot == other.mIsBot
+ && mIsImportant == other.mIsImportant;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mIcon, mUri, mKey, mIsBot, mIsImportant);
+ }
+
+ @Override
public int describeContents() {
return 0;
}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 636b1b9..8d9d340 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -973,11 +973,11 @@
*/
@UnsupportedAppUsage
public void phoneStateChanged(int numActive, int numHeld, int callState, String number,
- int type) {
+ int type, String name) {
final IBluetoothHeadset service = mService;
if (service != null && isEnabled()) {
try {
- service.phoneStateChanged(numActive, numHeld, callState, number, type);
+ service.phoneStateChanged(numActive, numHeld, callState, number, type, name);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 004417b..cec8ef5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -425,6 +425,15 @@
*/
public static final int BIND_EXTERNAL_SERVICE = 0x80000000;
+ /**
+ * These bind flags reduce the strength of the binding such that we shouldn't
+ * consider it as pulling the process up to the level of the one that is bound to it.
+ * @hide
+ */
+ public static final int BIND_REDUCTION_FLAGS =
+ Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_WAIVE_PRIORITY
+ | Context.BIND_ADJUST_BELOW_PERCEPTIBLE | Context.BIND_NOT_VISIBLE;
+
/** @hide */
@IntDef(flag = true, prefix = { "RECEIVER_VISIBLE_" }, value = {
RECEIVER_VISIBLE_TO_INSTANT_APPS
@@ -2982,6 +2991,31 @@
}
/**
+ * For a service previously bound with {@link #bindService} or a related method, change
+ * how the system manages that service's process in relation to other processes. This
+ * doesn't modify the original bind flags that were passed in when binding, but adjusts
+ * how the process will be managed in some cases based on those flags. Currently only
+ * works on isolated processes (will be ignored for non-isolated processes).
+ *
+ * @param conn The connection interface previously supplied to bindService(). This
+ * parameter must not be null.
+ * @param group A group to put this connection's process in. Upon calling here, this
+ * will override any previous group that was set for that process. The group
+ * tells the system about processes that are logically grouped together, so
+ * should be managed as one unit of importance (such as when being considered
+ * a recently used app). All processes in the same app with the same group
+ * are considered to be related. Supplying 0 reverts to the default behavior
+ * of not grouping.
+ * @param importance Additional importance of the processes within a group. Upon calling
+ * here, this will override any previous group that was set for that
+ * process. This fine-tunes process killing of all processes within
+ * a related groups -- higher importance values will be killed before
+ * lower ones.
+ */
+ public abstract void updateServiceGroup(@NonNull ServiceConnection conn, int group,
+ int importance);
+
+ /**
* Disconnect from an application service. You will no longer receive
* calls as the service is restarted, and the service is now allowed to
* stop at any time.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 88696b0e..2db44b4 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -726,6 +726,11 @@
}
@Override
+ public void updateServiceGroup(ServiceConnection conn, int group, int importance) {
+ mBase.updateServiceGroup(conn, group, importance);
+ }
+
+ @Override
public void unbindService(ServiceConnection conn) {
mBase.unbindService(conn);
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 48240db..4e110da 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -45,6 +45,7 @@
import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.List;
import java.util.Objects;
import java.util.UUID;
@@ -830,7 +831,17 @@
* the structure.
*/
public String[] sharedLibraryFiles;
-
+
+ /**
+ * List of all shared libraries this application is linked against. This
+ * field is only set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
+ * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving
+ * the structure.
+ *
+ * {@hide}
+ */
+ public List<SharedLibraryInfo> sharedLibraryInfos;
+
/**
* Full path to the default directory assigned to the package for its
* persistent data.
@@ -1474,6 +1485,7 @@
seInfo = orig.seInfo;
seInfoUser = orig.seInfoUser;
sharedLibraryFiles = orig.sharedLibraryFiles;
+ sharedLibraryInfos = orig.sharedLibraryInfos;
dataDir = orig.dataDir;
deviceProtectedDataDir = orig.deviceProtectedDataDir;
credentialProtectedDataDir = orig.credentialProtectedDataDir;
@@ -1549,6 +1561,7 @@
dest.writeString(seInfo);
dest.writeString(seInfoUser);
dest.writeStringArray(sharedLibraryFiles);
+ dest.writeTypedList(sharedLibraryInfos);
dest.writeString(dataDir);
dest.writeString(deviceProtectedDataDir);
dest.writeString(credentialProtectedDataDir);
@@ -1621,6 +1634,7 @@
seInfo = source.readString();
seInfoUser = source.readString();
sharedLibraryFiles = source.readStringArray();
+ sharedLibraryInfos = source.createTypedArrayList(SharedLibraryInfo.CREATOR);
dataDir = source.readString();
deviceProtectedDataDir = source.readString();
credentialProtectedDataDir = source.readString();
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 7ef5264..2fcf1dd 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -7669,6 +7669,7 @@
}
if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
ai.sharedLibraryFiles = p.usesLibraryFiles;
+ ai.sharedLibraryInfos = p.usesLibraryInfos;
}
if (state.stopped) {
ai.flags |= ApplicationInfo.FLAG_STOPPED;
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 096301c..ad82626d 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -74,6 +74,7 @@
private final String mPath;
private final String mPackageName;
private final String mName;
+ private final List<String> mCodePaths;
private final long mVersion;
private final @Type int mType;
@@ -84,6 +85,8 @@
/**
* Creates a new instance.
*
+ * @param codePaths For a non {@link #TYPE_BUILTIN builtin} library, the locations of jars of
+ * this shared library. Null for builtin library.
* @param name The lib name.
* @param version The lib version if not builtin.
* @param type The lib type.
@@ -92,11 +95,13 @@
*
* @hide
*/
- public SharedLibraryInfo(String path, String packageName, String name, long version, int type,
+ public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
+ String name, long version, int type,
VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
List<SharedLibraryInfo> dependencies) {
mPath = path;
mPackageName = packageName;
+ mCodePaths = codePaths;
mName = name;
mVersion = version;
mType = type;
@@ -106,7 +111,8 @@
}
private SharedLibraryInfo(Parcel parcel) {
- this(parcel.readString(), parcel.readString(), parcel.readString(), parcel.readLong(),
+ this(parcel.readString(), parcel.readString(), parcel.readArrayList(null),
+ parcel.readString(), parcel.readLong(),
parcel.readInt(), parcel.readParcelable(null), parcel.readArrayList(null),
parcel.createTypedArrayList(SharedLibraryInfo.CREATOR));
}
@@ -155,6 +161,25 @@
}
/**
+ * Get all code paths for that library.
+ *
+ * @return All code paths.
+ *
+ * @hide
+ */
+ public List<String> getAllCodePaths() {
+ if (getPath() != null) {
+ // Builtin library.
+ ArrayList<String> list = new ArrayList<>();
+ list.add(getPath());
+ return list;
+ } else {
+ // Static or dynamic library.
+ return mCodePaths;
+ }
+ }
+
+ /**
* Add a library dependency to that library. Note that this
* should be called under the package manager lock.
*
@@ -273,6 +298,7 @@
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mPath);
parcel.writeString(mPackageName);
+ parcel.writeList(mCodePaths);
parcel.writeString(mName);
parcel.writeLong(mVersion);
parcel.writeInt(mType);
diff --git a/core/java/android/os/IThermalService.aidl b/core/java/android/os/IThermalService.aidl
index 287a5ed..8160338 100644
--- a/core/java/android/os/IThermalService.aidl
+++ b/core/java/android/os/IThermalService.aidl
@@ -17,6 +17,7 @@
package android.os;
import android.os.IThermalEventListener;
+import android.os.IThermalStatusListener;
import android.os.Temperature;
import java.util.List;
@@ -30,31 +31,60 @@
* @param listener the IThermalEventListener to be notified.
* {@hide}
*/
- void registerThermalEventListener(in IThermalEventListener listener);
+ boolean registerThermalEventListener(in IThermalEventListener listener);
+
/**
* Register a listener for thermal events on given temperature type.
* @param listener the IThermalEventListener to be notified.
* @param type the temperature type IThermalEventListener to be notified.
+ * @return true if registered successfully.
* {@hide}
*/
- void registerThermalEventListenerWithType(in IThermalEventListener listener, in int type);
+ boolean registerThermalEventListenerWithType(in IThermalEventListener listener, in int type);
+
/**
* Unregister a previously-registered listener for thermal events.
* @param listener the IThermalEventListener to no longer be notified.
+ * @return true if unregistered successfully.
* {@hide}
*/
- void unregisterThermalEventListener(in IThermalEventListener listener);
+ boolean unregisterThermalEventListener(in IThermalEventListener listener);
+
/**
* Get current temperature with its throttling status.
* @return list of android.os.Temperature
* {@hide}
*/
List<Temperature> getCurrentTemperatures();
+
/**
* Get current temperature with its throttling status on given temperature type.
* @param type the temperature type to query.
- * @return list of android.os.Temperature
+ * @return list of {@link android.os.Temperature}.
* {@hide}
*/
List<Temperature> getCurrentTemperaturesWithType(in int type);
+
+ /**
+ * Register a listener for thermal status change.
+ * @param listener the IThermalStatusListener to be notified.
+ * @return true if registered successfully.
+ * {@hide}
+ */
+ boolean registerThermalStatusListener(in IThermalStatusListener listener);
+
+ /**
+ * Unregister a previously-registered listener for thermal status.
+ * @param listener the IThermalStatusListener to no longer be notified.
+ * @return true if unregistered successfully.
+ * {@hide}
+ */
+ boolean unregisterThermalStatusListener(in IThermalStatusListener listener);
+
+ /**
+ * Get current thermal status.
+ * @return status defined in {@link android.os.Temperature}.
+ * {@hide}
+ */
+ int getCurrentStatus();
}
diff --git a/core/java/android/os/IThermalStatusListener.aidl b/core/java/android/os/IThermalStatusListener.aidl
new file mode 100644
index 0000000..a6da7d0
--- /dev/null
+++ b/core/java/android/os/IThermalStatusListener.aidl
@@ -0,0 +1,29 @@
+/*
+** 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.os;
+
+/**
+ * Listener for thermal status.
+ * {@hide}
+ */
+oneway interface IThermalStatusListener {
+ /**
+ * Called when overall thermal throttling status changed.
+ * @param status defined in {@link android.os.Temperature#ThrottlingStatus}.
+ */
+ void onStatusChange(int status);
+}
diff --git a/core/java/android/os/Temperature.java b/core/java/android/os/Temperature.java
index 37ed52c..bf85fbd 100644
--- a/core/java/android/os/Temperature.java
+++ b/core/java/android/os/Temperature.java
@@ -25,9 +25,7 @@
/**
* Temperature values used by IThermalService.
- */
-
-/**
+ *
* @hide
*/
public class Temperature implements Parcelable {
@@ -40,7 +38,6 @@
/** The level of the sensor is currently in throttling */
private int mStatus;
- /** @hide */
@IntDef(prefix = { "THROTTLING_" }, value = {
THROTTLING_NONE,
THROTTLING_LIGHT,
@@ -62,7 +59,6 @@
public static final int THROTTLING_WARNING = ThrottlingSeverity.WARNING;
public static final int THROTTLING_SHUTDOWN = ThrottlingSeverity.SHUTDOWN;
- /** @hide */
@IntDef(prefix = { "TYPE_" }, value = {
TYPE_UNKNOWN,
TYPE_CPU,
@@ -95,19 +91,28 @@
*
* @return true if a temperature type is valid otherwise false.
*/
- public static boolean isValidType(int type) {
+ public static boolean isValidType(@Type int type) {
return type >= TYPE_UNKNOWN && type <= TYPE_BCL_PERCENTAGE;
}
+ /**
+ * Verify a valid throttling status.
+ *
+ * @return true if a status is valid otherwise false.
+ */
+ public static boolean isValidStatus(@ThrottlingStatus int status) {
+ return status >= THROTTLING_NONE && status <= THROTTLING_SHUTDOWN;
+ }
+
public Temperature() {
this(Float.NaN, TYPE_UNKNOWN, "", THROTTLING_NONE);
}
- public Temperature(float value, @Type int type, String name, int status) {
+ public Temperature(float value, @Type int type, String name, @ThrottlingStatus int status) {
mValue = value;
mType = isValidType(type) ? type : TYPE_UNKNOWN;
mName = name;
- mStatus = status;
+ mStatus = isValidStatus(status) ? status : THROTTLING_NONE;
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index be3dd5d..943888b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12171,7 +12171,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
*/
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index 09bba4b..e930f40 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.TelephonyManager;
import com.android.internal.telephony.uicc.IccUtils;
@@ -26,7 +27,10 @@
/**
* Used to pass info to CarrierConfigService implementations so they can decide what values to
- * return.
+ * return. Instead of passing mcc, mnc, gid1, gid2, spn, imsi to locate carrier information,
+ * CarrierIdentifier also include carrier id {@link TelephonyManager#getSimCarrierId()},
+ * a platform-wide unique identifier for each carrier. CarrierConfigService can directly use
+ * carrier id as the key to look up the carrier info.
*/
public class CarrierIdentifier implements Parcelable {
@@ -49,15 +53,40 @@
private @Nullable String mImsi;
private @Nullable String mGid1;
private @Nullable String mGid2;
+ private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
+ private int mPreciseCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
public CarrierIdentifier(String mcc, String mnc, @Nullable String spn, @Nullable String imsi,
@Nullable String gid1, @Nullable String gid2) {
+ this(mcc, mnc, spn, imsi, gid1, gid2, TelephonyManager.UNKNOWN_CARRIER_ID,
+ TelephonyManager.UNKNOWN_CARRIER_ID);
+ }
+
+ /**
+ * @param mcc mobile country code
+ * @param mnc mobile network code
+ * @param spn service provider name
+ * @param imsi International Mobile Subscriber Identity {@link TelephonyManager#getSubscriberId()}
+ * @param gid1 group id level 1 {@link TelephonyManager#getGroupIdLevel1()}
+ * @param gid2 group id level 2
+ * @param carrierid carrier unique identifier {@link TelephonyManager#getSimCarrierId()}, used
+ * to uniquely identify the carrier and look up the carrier configurations.
+ * @param preciseCarrierId precise carrier identifier {@link TelephonyManager#getSimPreciseCarrierId()}
+ * @hide
+ *
+ * TODO: expose this to public API
+ */
+ public CarrierIdentifier(String mcc, String mnc, @Nullable String spn,
+ @Nullable String imsi, @Nullable String gid1, @Nullable String gid2,
+ int carrierid, int preciseCarrierId) {
mMcc = mcc;
mMnc = mnc;
mSpn = spn;
mImsi = imsi;
mGid1 = gid1;
mGid2 = gid2;
+ mCarrierId = carrierid;
+ mPreciseCarrierId = preciseCarrierId;
}
/**
@@ -125,6 +154,22 @@
return mGid2;
}
+ /**
+ * Get the carrier id {@link TelephonyManager#getSimCarrierId() }
+ * @hide
+ */
+ public int getCarrierId() {
+ return mCarrierId;
+ }
+
+ /**
+ * Get the precise carrier id {@link TelephonyManager#getSimPreciseCarrierId()}
+ * @hide
+ */
+ public int getPreciseCarrierId() {
+ return mPreciseCarrierId;
+ }
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -140,19 +185,14 @@
&& Objects.equals(mSpn, that.mSpn)
&& Objects.equals(mImsi, that.mImsi)
&& Objects.equals(mGid1, that.mGid1)
- && Objects.equals(mGid2, that.mGid2);
+ && Objects.equals(mGid2, that.mGid2)
+ && Objects.equals(mCarrierId, that.mCarrierId)
+ && Objects.equals(mPreciseCarrierId, that.mPreciseCarrierId);
}
@Override
- public int hashCode() {
- int result = 1;
- result = 31 * result + Objects.hashCode(mMcc);
- result = 31 * result + Objects.hashCode(mMnc);
- result = 31 * result + Objects.hashCode(mSpn);
- result = 31 * result + Objects.hashCode(mImsi);
- result = 31 * result + Objects.hashCode(mGid1);
- result = 31 * result + Objects.hashCode(mGid2);
- return result;
+ public int hashCode(){
+ return Objects.hash(mMcc, mMnc, mSpn, mImsi, mGid1, mGid2, mCarrierId, mPreciseCarrierId);
}
@Override
@@ -168,18 +208,22 @@
out.writeString(mImsi);
out.writeString(mGid1);
out.writeString(mGid2);
+ out.writeInt(mCarrierId);
+ out.writeInt(mPreciseCarrierId);
}
@Override
public String toString() {
return "CarrierIdentifier{"
- + "mcc=" + mMcc
- + ",mnc=" + mMnc
- + ",spn=" + mSpn
- + ",imsi=" + mImsi
- + ",gid1=" + mGid1
- + ",gid2=" + mGid2
- + "}";
+ + "mcc=" + mMcc
+ + ",mnc=" + mMnc
+ + ",spn=" + mSpn
+ + ",imsi=" + mImsi
+ + ",gid1=" + mGid1
+ + ",gid2=" + mGid2
+ + ",carrierid=" + mCarrierId
+ + ",mPreciseCarrierId=" + mPreciseCarrierId
+ + "}";
}
/** @hide */
@@ -190,6 +234,8 @@
mImsi = in.readString();
mGid1 = in.readString();
mGid2 = in.readString();
+ mCarrierId = in.readInt();
+ mPreciseCarrierId = in.readInt();
}
/** @hide */
diff --git a/core/java/android/service/carrier/CarrierService.java b/core/java/android/service/carrier/CarrierService.java
index b94ccf9..c351d89 100644
--- a/core/java/android/service/carrier/CarrierService.java
+++ b/core/java/android/service/carrier/CarrierService.java
@@ -93,7 +93,11 @@
* </p>
*
* @param id contains details about the current carrier that can be used do decide what
- * configuration values to return.
+ * configuration values to return. Instead of using details like MCCMNC to decide
+ * current carrier, it also contains subscription carrier id
+ * {@link android.telephony.TelephonyManager#getSimCarrierId()}, a platform-wide
+ * unique identifier for each carrier, CarrierConfigService can directly use carrier
+ * id as the key to look up the carrier info.
* @return a {@link PersistableBundle} object containing the configuration or null if default
* values should be used.
*/
diff --git a/media/java/android/media/ISessionTokensListener.aidl b/core/java/android/service/textclassifier/IConversationActionsCallback.aidl
similarity index 63%
copy from media/java/android/media/ISessionTokensListener.aidl
copy to core/java/android/service/textclassifier/IConversationActionsCallback.aidl
index c83a19e..c35d424 100644
--- a/media/java/android/media/ISessionTokensListener.aidl
+++ b/core/java/android/service/textclassifier/IConversationActionsCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 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,14 +14,15 @@
* limitations under the License.
*/
-package android.media;
+package android.service.textclassifier;
-import android.os.Bundle;
+import android.view.textclassifier.ConversationActions;
/**
- * Listens for changes to the list of session tokens.
+ * Callback for a ConversationActions request.
* @hide
*/
-oneway interface ISessionTokensListener {
- void onSessionTokensChanged(in List<Bundle> tokens);
-}
+oneway interface IConversationActionsCallback {
+ void onSuccess(in ConversationActions conversationActions);
+ void onFailure();
+}
\ No newline at end of file
diff --git a/core/java/android/service/textclassifier/ITextClassifierService.aidl b/core/java/android/service/textclassifier/ITextClassifierService.aidl
index 7ac72c7..254a710 100644
--- a/core/java/android/service/textclassifier/ITextClassifierService.aidl
+++ b/core/java/android/service/textclassifier/ITextClassifierService.aidl
@@ -16,14 +16,18 @@
package android.service.textclassifier;
+import android.service.textclassifier.IConversationActionsCallback;
import android.service.textclassifier.ITextClassificationCallback;
+import android.service.textclassifier.ITextLanguageCallback;
import android.service.textclassifier.ITextLinksCallback;
import android.service.textclassifier.ITextSelectionCallback;
+import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationSessionId;
import android.view.textclassifier.TextLinks;
+import android.view.textclassifier.TextLanguage;
import android.view.textclassifier.TextSelection;
/**
@@ -58,4 +62,14 @@
void onDestroyTextClassificationSession(
in TextClassificationSessionId sessionId);
+
+ void onDetectLanguage(
+ in TextClassificationSessionId sessionId,
+ in TextLanguage.Request request,
+ in ITextLanguageCallback callback);
+
+ void onSuggestConversationActions(
+ in TextClassificationSessionId sessionId,
+ in ConversationActions.Request request,
+ in IConversationActionsCallback callback);
}
diff --git a/media/java/android/media/ISessionTokensListener.aidl b/core/java/android/service/textclassifier/ITextLanguageCallback.aidl
similarity index 65%
rename from media/java/android/media/ISessionTokensListener.aidl
rename to core/java/android/service/textclassifier/ITextLanguageCallback.aidl
index c83a19e..263d99af 100644
--- a/media/java/android/media/ISessionTokensListener.aidl
+++ b/core/java/android/service/textclassifier/ITextLanguageCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 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,14 +14,15 @@
* limitations under the License.
*/
-package android.media;
+package android.service.textclassifier;
-import android.os.Bundle;
+import android.view.textclassifier.TextLanguage;
/**
- * Listens for changes to the list of session tokens.
+ * Callback for a TextLanguage request.
* @hide
*/
-oneway interface ISessionTokensListener {
- void onSessionTokensChanged(in List<Bundle> tokens);
-}
+oneway interface ITextLanguageCallback {
+ void onSuccess(in TextLanguage textLanguage);
+ void onFailure();
+}
\ No newline at end of file
diff --git a/core/java/android/service/textclassifier/TextClassifierService.java b/core/java/android/service/textclassifier/TextClassifierService.java
index 7f1082d..d7359f1 100644
--- a/core/java/android/service/textclassifier/TextClassifierService.java
+++ b/core/java/android/service/textclassifier/TextClassifierService.java
@@ -32,12 +32,14 @@
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Slog;
+import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassificationSessionId;
import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextLanguage;
import android.view.textclassifier.TextLinks;
import android.view.textclassifier.TextSelection;
@@ -92,8 +94,7 @@
@Override
public void onSuggestSelection(
TextClassificationSessionId sessionId,
- TextSelection.Request request, ITextSelectionCallback callback)
- throws RemoteException {
+ TextSelection.Request request, ITextSelectionCallback callback) {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
TextClassifierService.this.onSuggestSelection(
@@ -125,8 +126,7 @@
@Override
public void onClassifyText(
TextClassificationSessionId sessionId,
- TextClassification.Request request, ITextClassificationCallback callback)
- throws RemoteException {
+ TextClassification.Request request, ITextClassificationCallback callback) {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
TextClassifierService.this.onClassifyText(
@@ -156,8 +156,7 @@
@Override
public void onGenerateLinks(
TextClassificationSessionId sessionId,
- TextLinks.Request request, ITextLinksCallback callback)
- throws RemoteException {
+ TextLinks.Request request, ITextLinksCallback callback) {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
TextClassifierService.this.onGenerateLinks(
@@ -188,16 +187,81 @@
@Override
public void onSelectionEvent(
TextClassificationSessionId sessionId,
- SelectionEvent event) throws RemoteException {
+ SelectionEvent event) {
Preconditions.checkNotNull(event);
TextClassifierService.this.onSelectionEvent(sessionId, event);
}
/** {@inheritDoc} */
@Override
+ public void onDetectLanguage(
+ TextClassificationSessionId sessionId,
+ TextLanguage.Request request,
+ ITextLanguageCallback callback) {
+ Preconditions.checkNotNull(request);
+ Preconditions.checkNotNull(callback);
+ TextClassifierService.this.onDetectLanguage(
+ sessionId,
+ request,
+ mCancellationSignal,
+ new Callback<TextLanguage>() {
+ @Override
+ public void onSuccess(TextLanguage result) {
+ try {
+ callback.onSuccess(result);
+ } catch (RemoteException e) {
+ Slog.d(LOG_TAG, "Error calling callback");
+ }
+ }
+
+ @Override
+ public void onFailure(CharSequence error) {
+ try {
+ callback.onFailure();
+ } catch (RemoteException e) {
+ Slog.d(LOG_TAG, "Error calling callback");
+ }
+ };
+ });
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onSuggestConversationActions(
+ TextClassificationSessionId sessionId,
+ ConversationActions.Request request,
+ IConversationActionsCallback callback) {
+ Preconditions.checkNotNull(request);
+ Preconditions.checkNotNull(callback);
+ TextClassifierService.this.onSuggestConversationActions(
+ sessionId,
+ request,
+ mCancellationSignal,
+ new Callback<ConversationActions>() {
+ @Override
+ public void onSuccess(ConversationActions result) {
+ try {
+ callback.onSuccess(result);
+ } catch (RemoteException e) {
+ Slog.d(LOG_TAG, "Error calling callback");
+ }
+ }
+
+ @Override
+ public void onFailure(CharSequence error) {
+ try {
+ callback.onFailure();
+ } catch (RemoteException e) {
+ Slog.d(LOG_TAG, "Error calling callback");
+ }
+ }
+ });
+ }
+
+ /** {@inheritDoc} */
+ @Override
public void onCreateTextClassificationSession(
- TextClassificationContext context, TextClassificationSessionId sessionId)
- throws RemoteException {
+ TextClassificationContext context, TextClassificationSessionId sessionId) {
Preconditions.checkNotNull(context);
Preconditions.checkNotNull(sessionId);
TextClassifierService.this.onCreateTextClassificationSession(context, sessionId);
@@ -205,8 +269,7 @@
/** {@inheritDoc} */
@Override
- public void onDestroyTextClassificationSession(TextClassificationSessionId sessionId)
- throws RemoteException {
+ public void onDestroyTextClassificationSession(TextClassificationSessionId sessionId) {
TextClassifierService.this.onDestroyTextClassificationSession(sessionId);
}
};
@@ -266,6 +329,38 @@
@NonNull Callback<TextLinks> callback);
/**
+ * Detects and returns the language of the give text.
+ *
+ * @param sessionId the session id
+ * @param request the language detection request
+ * @param cancellationSignal object to watch for canceling the current operation
+ * @param callback the callback to return the result to
+ */
+ public void onDetectLanguage(
+ @Nullable TextClassificationSessionId sessionId,
+ @NonNull TextLanguage.Request request,
+ @NonNull CancellationSignal cancellationSignal,
+ @NonNull Callback<TextLanguage> callback) {
+ callback.onSuccess(getLocalTextClassifier().detectLanguage(request));
+ }
+
+ /**
+ * Suggests and returns a list of actions according to the given conversation.
+ *
+ * @param sessionId the session id
+ * @param request the conversation actions request
+ * @param cancellationSignal object to watch for canceling the current operation
+ * @param callback the callback to return the result to
+ */
+ public void onSuggestConversationActions(
+ @Nullable TextClassificationSessionId sessionId,
+ @NonNull ConversationActions.Request request,
+ @NonNull CancellationSignal cancellationSignal,
+ @NonNull Callback<ConversationActions> callback) {
+ callback.onSuccess(getLocalTextClassifier().suggestConversationActions(request));
+ }
+
+ /**
* Writes the selection event.
* This is called when a selection event occurs. e.g. user changed selection; or smart selection
* happened.
diff --git a/core/java/android/service/wallpaper/IWallpaperConnection.aidl b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
index 3c3ef0c..a976d0e 100644
--- a/core/java/android/service/wallpaper/IWallpaperConnection.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperConnection.aidl
@@ -24,8 +24,8 @@
* @hide
*/
interface IWallpaperConnection {
- void attachEngine(IWallpaperEngine engine);
- void engineShown(IWallpaperEngine engine);
+ void attachEngine(IWallpaperEngine engine, int displayId);
+ void engineShown(IWallpaperEngine engine);
ParcelFileDescriptor setWallpaper(String name);
void onWallpaperColorsChanged(in WallpaperColors colors);
}
diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl
index 5fd0157..99a81f5 100644
--- a/core/java/android/service/wallpaper/IWallpaperService.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperService.aidl
@@ -24,6 +24,6 @@
*/
oneway interface IWallpaperService {
void attach(IWallpaperConnection connection,
- IBinder windowToken, int windowType, boolean isPreview,
- int reqWidth, int reqHeight, in Rect padding);
+ IBinder windowToken, int windowType, boolean isPreview,
+ int reqWidth, int reqHeight, in Rect padding, int displayId);
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 4bd86a4..6f51bec 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -24,7 +24,6 @@
import android.app.WallpaperColors;
import android.app.WallpaperInfo;
import android.app.WallpaperManager;
-import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -806,7 +805,7 @@
com.android.internal.R.style.Animation_Wallpaper;
mInputChannel = new InputChannel();
if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,
- Display.DEFAULT_DISPLAY, mWinFrame, mContentInsets, mStableInsets,
+ mDisplay.getDisplayId(), mWinFrame, mContentInsets, mStableInsets,
mOutsets, mDisplayCutout, mInputChannel) < 0) {
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
@@ -1015,7 +1014,15 @@
if (mDestroyed) {
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;
@@ -1027,10 +1034,7 @@
mWindow.setSession(mSession);
mLayout.packageName = getPackageName();
-
- mDisplayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE);
mDisplayManager.registerDisplayListener(mDisplayListener, mCaller.getHandler());
- mDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
mDisplayState = mDisplay.getState();
if (DEBUG) Log.v(TAG, "onCreate(): " + this);
@@ -1268,12 +1272,14 @@
int mReqWidth;
int mReqHeight;
final Rect mDisplayPadding = new Rect();
+ int mDisplayId;
Engine mEngine;
IWallpaperEngineWrapper(WallpaperService context,
IWallpaperConnection conn, IBinder windowToken,
- int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding) {
+ int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding,
+ int displayId) {
mCaller = new HandlerCaller(context, context.getMainLooper(), this, true);
mConnection = conn;
mWindowToken = windowToken;
@@ -1282,6 +1288,7 @@
mReqWidth = reqWidth;
mReqHeight = reqHeight;
mDisplayPadding.set(padding);
+ mDisplayId = displayId;
Message msg = mCaller.obtainMessage(DO_ATTACH);
mCaller.sendMessage(msg);
@@ -1353,7 +1360,7 @@
switch (message.what) {
case DO_ATTACH: {
try {
- mConnection.attachEngine(this);
+ mConnection.attachEngine(this, mDisplayId);
} catch (RemoteException e) {
Log.w(TAG, "Wallpaper host disappeared", e);
return;
@@ -1453,9 +1460,10 @@
@Override
public void attach(IWallpaperConnection conn, IBinder windowToken,
- int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding) {
+ int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding,
+ int displayId) {
new IWallpaperEngineWrapper(mTarget, conn, windowToken,
- windowType, isPreview, reqWidth, reqHeight, padding);
+ windowType, isPreview, reqWidth, reqHeight, padding, displayId);
}
}
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 717a858..21c4252 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -21,9 +21,9 @@
import android.annotation.UnsupportedAppUsage;
import android.os.SystemClock;
-import libcore.util.CountryTimeZones;
-import libcore.util.CountryTimeZones.TimeZoneMapping;
-import libcore.util.TimeZoneFinder;
+import libcore.timezone.CountryTimeZones;
+import libcore.timezone.CountryTimeZones.TimeZoneMapping;
+import libcore.timezone.TimeZoneFinder;
import libcore.util.ZoneInfoDB;
import java.io.PrintWriter;
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/media/java/android/media/update/ProviderCreator.java b/core/java/android/view/textclassifier/ConversationActions.aidl
similarity index 74%
rename from media/java/android/media/update/ProviderCreator.java
rename to core/java/android/view/textclassifier/ConversationActions.aidl
index f5f3e47..fece939 100644
--- a/media/java/android/media/update/ProviderCreator.java
+++ b/core/java/android/view/textclassifier/ConversationActions.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 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,7 @@
* limitations under the License.
*/
-package android.media.update;
+package android.view.textclassifier;
-/** @hide */
-@FunctionalInterface
-public interface ProviderCreator<T, U> {
- U createProvider(T instance);
-}
+parcelable ConversationActions;
+parcelable ConversationActions.Request;
\ No newline at end of file
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index 16eb5af..f8fce62 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -23,8 +23,10 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.service.textclassifier.IConversationActionsCallback;
import android.service.textclassifier.ITextClassificationCallback;
import android.service.textclassifier.ITextClassifierService;
+import android.service.textclassifier.ITextLanguageCallback;
import android.service.textclassifier.ITextLinksCallback;
import android.service.textclassifier.ITextSelectionCallback;
@@ -76,7 +78,7 @@
if (selection != null) {
return selection;
}
- } catch (RemoteException | InterruptedException e) {
+ } catch (RemoteException e) {
Log.e(LOG_TAG, "Error suggesting selection for text. Using fallback.", e);
}
return mFallback.suggestSelection(request);
@@ -97,7 +99,7 @@
if (classification != null) {
return classification;
}
- } catch (RemoteException | InterruptedException e) {
+ } catch (RemoteException e) {
Log.e(LOG_TAG, "Error classifying text. Using fallback.", e);
}
return mFallback.classifyText(request);
@@ -124,7 +126,7 @@
if (links != null) {
return links;
}
- } catch (RemoteException | InterruptedException e) {
+ } catch (RemoteException e) {
Log.e(LOG_TAG, "Error generating links. Using fallback.", e);
}
return mFallback.generateLinks(request);
@@ -142,6 +144,42 @@
}
}
+ @Override
+ public TextLanguage detectLanguage(TextLanguage.Request request) {
+ Preconditions.checkNotNull(request);
+ Utils.checkMainThread();
+
+ try {
+ final TextLanguageCallback callback = new TextLanguageCallback();
+ mManagerService.onDetectLanguage(mSessionId, request, callback);
+ final TextLanguage textLanguage = callback.mReceiver.get();
+ if (textLanguage != null) {
+ return textLanguage;
+ }
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Error detecting language.", e);
+ }
+ return mFallback.detectLanguage(request);
+ }
+
+ @Override
+ public ConversationActions suggestConversationActions(ConversationActions.Request request) {
+ Preconditions.checkNotNull(request);
+ Utils.checkMainThread();
+
+ try {
+ final ConversationActionsCallback callback = new ConversationActionsCallback();
+ mManagerService.onSuggestConversationActions(mSessionId, request, callback);
+ final ConversationActions conversationActions = callback.mReceiver.get();
+ if (conversationActions != null) {
+ return conversationActions;
+ }
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Error reporting selection event.", e);
+ }
+ return mFallback.suggestConversationActions(request);
+ }
+
/**
* @inheritDoc
*/
@@ -193,7 +231,7 @@
private static final class TextSelectionCallback extends ITextSelectionCallback.Stub {
- final ResponseReceiver<TextSelection> mReceiver = new ResponseReceiver<>();
+ final ResponseReceiver<TextSelection> mReceiver = new ResponseReceiver<>("textselection");
@Override
public void onSuccess(TextSelection selection) {
@@ -208,7 +246,8 @@
private static final class TextClassificationCallback extends ITextClassificationCallback.Stub {
- final ResponseReceiver<TextClassification> mReceiver = new ResponseReceiver<>();
+ final ResponseReceiver<TextClassification> mReceiver =
+ new ResponseReceiver<>("textclassification");
@Override
public void onSuccess(TextClassification classification) {
@@ -223,7 +262,7 @@
private static final class TextLinksCallback extends ITextLinksCallback.Stub {
- final ResponseReceiver<TextLinks> mReceiver = new ResponseReceiver<>();
+ final ResponseReceiver<TextLinks> mReceiver = new ResponseReceiver<>("textlinks");
@Override
public void onSuccess(TextLinks links) {
@@ -236,12 +275,48 @@
}
}
+ private static final class TextLanguageCallback extends ITextLanguageCallback.Stub {
+
+ final ResponseReceiver<TextLanguage> mReceiver = new ResponseReceiver<>("textlanguage");
+
+ @Override
+ public void onSuccess(TextLanguage textLanguage) {
+ mReceiver.onSuccess(textLanguage);
+ }
+
+ @Override
+ public void onFailure() {
+ mReceiver.onFailure();
+ }
+ }
+
+ private static final class ConversationActionsCallback
+ extends IConversationActionsCallback.Stub {
+
+ final ResponseReceiver<ConversationActions> mReceiver =
+ new ResponseReceiver<>("conversationaction");
+
+ @Override
+ public void onSuccess(ConversationActions conversationActions) {
+ mReceiver.onSuccess(conversationActions);
+ }
+
+ @Override
+ public void onFailure() {
+ mReceiver.onFailure();
+ }
+ }
+
private static final class ResponseReceiver<T> {
private final CountDownLatch mLatch = new CountDownLatch(1);
-
+ private final String mName;
private T mResponse;
+ private ResponseReceiver(String name) {
+ mName = name;
+ }
+
public void onSuccess(T response) {
mResponse = response;
mLatch.countDown();
@@ -253,13 +328,21 @@
}
@Nullable
- public T get() throws InterruptedException {
+ public T get() {
// If this is running on the main thread, do not block for a response.
// The response will unfortunately be null and the TextClassifier should depend on its
// fallback.
// NOTE that TextClassifier calls should preferably always be called on a worker thread.
if (Looper.myLooper() != Looper.getMainLooper()) {
- mLatch.await(2, TimeUnit.SECONDS);
+ try {
+ boolean success = mLatch.await(2, TimeUnit.SECONDS);
+ if (!success) {
+ Log.w(LOG_TAG, "Timeout in ResponseReceiver.get(): " + mName);
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ Log.e(LOG_TAG, "Interrupted during ResponseReceiver.get(): " + mName, e);
+ }
}
return mResponse;
}
diff --git a/media/java/android/media/update/ProviderCreator.java b/core/java/android/view/textclassifier/TextLanguage.aidl
similarity index 74%
copy from media/java/android/media/update/ProviderCreator.java
copy to core/java/android/view/textclassifier/TextLanguage.aidl
index f5f3e47..54e3cf9f 100644
--- a/media/java/android/media/update/ProviderCreator.java
+++ b/core/java/android/view/textclassifier/TextLanguage.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright 2018 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,7 @@
* limitations under the License.
*/
-package android.media.update;
+package android.view.textclassifier;
-/** @hide */
-@FunctionalInterface
-public interface ProviderCreator<T, U> {
- U createProvider(T instance);
-}
+parcelable TextLanguage;
+parcelable TextLanguage.Request;
\ No newline at end of file
diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java
index 387857f..c5bc45a 100644
--- a/core/java/com/android/internal/os/ClassLoaderFactory.java
+++ b/core/java/com/android/internal/os/ClassLoaderFactory.java
@@ -22,6 +22,8 @@
import dalvik.system.DexClassLoader;
import dalvik.system.PathClassLoader;
+import java.util.List;
+
/**
* Creates class loaders.
*
@@ -37,6 +39,13 @@
DelegateLastClassLoader.class.getName();
/**
+ * Returns the name of the class for PathClassLoader.
+ */
+ public static String getPathClassLoaderName() {
+ return PATH_CLASS_LOADER_NAME;
+ }
+
+ /**
* Returns true if {@code name} is a supported classloader. {@code name} must be a
* binary name of a class, as defined by {@code Class.getName}.
*/
@@ -68,25 +77,43 @@
* is created.
*/
public static ClassLoader createClassLoader(String dexPath,
- String librarySearchPath, ClassLoader parent, String classloaderName) {
+ String librarySearchPath, ClassLoader parent, String classloaderName,
+ List<ClassLoader> sharedLibraries) {
+ ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null)
+ ? null
+ : sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]);
if (isPathClassLoaderName(classloaderName)) {
- return new PathClassLoader(dexPath, librarySearchPath, parent);
+ return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries);
} else if (isDelegateLastClassLoaderName(classloaderName)) {
- return new DelegateLastClassLoader(dexPath, librarySearchPath, parent);
+ return new DelegateLastClassLoader(dexPath, librarySearchPath, parent,
+ arrayOfSharedLibraries);
}
throw new AssertionError("Invalid classLoaderName: " + classloaderName);
}
/**
+ * Same as {@code createClassLoader} below, but passes a null list of shared
+ * libraries.
+ */
+ public static ClassLoader createClassLoader(String dexPath,
+ String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
+ int targetSdkVersion, boolean isNamespaceShared, String classLoaderName) {
+ return createClassLoader(dexPath, librarySearchPath, libraryPermittedPath,
+ parent, targetSdkVersion, isNamespaceShared, classLoaderName, null);
+ }
+
+
+ /**
* Create a ClassLoader and initialize a linker-namespace for it.
*/
public static ClassLoader createClassLoader(String dexPath,
String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
- int targetSdkVersion, boolean isNamespaceShared, String classloaderName) {
+ int targetSdkVersion, boolean isNamespaceShared, String classLoaderName,
+ List<ClassLoader> sharedLibraries) {
final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent,
- classloaderName);
+ classLoaderName, sharedLibraries);
boolean isForVendor = false;
for (String path : dexPath.split(":")) {
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReader.java b/core/java/com/android/internal/os/KernelCpuThreadReader.java
index ade5d05..3861739 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReader.java
@@ -29,6 +29,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.function.Predicate;
/**
* Given a process, will iterate over the child threads of the process, and return the CPU usage
@@ -70,6 +71,11 @@
private static final String THREAD_NAME_FILENAME = "comm";
/**
+ * Glob pattern for the process directory names under {@code proc}
+ */
+ private static final String PROCESS_DIRECTORY_FILTER = "[0-9]*";
+
+ /**
* Default process name when the name can't be read
*/
private static final String DEFAULT_PROCESS_NAME = "unknown_process";
@@ -96,6 +102,18 @@
private static final int NUM_BUCKETS = 8;
/**
+ * Default predicate for what UIDs to check for when getting processes. This filters to only
+ * select system UIDs (1000-1999)
+ */
+ private static final Predicate<Integer> DEFAULT_UID_PREDICATE =
+ uid -> 1000 <= uid && uid < 2000;
+
+ /**
+ * Value returned when there was an error getting an integer ID value (e.g. PID, UID)
+ */
+ private static final int ID_ERROR = -1;
+
+ /**
* Where the proc filesystem is mounted
*/
private final Path mProcPath;
@@ -116,8 +134,13 @@
*/
private final FrequencyBucketCreator mFrequencyBucketCreator;
+ private final Injector mInjector;
+
private KernelCpuThreadReader() throws IOException {
- this(DEFAULT_PROC_PATH, DEFAULT_INITIAL_TIME_IN_STATE_PATH);
+ this(
+ DEFAULT_PROC_PATH,
+ DEFAULT_INITIAL_TIME_IN_STATE_PATH,
+ new Injector());
}
/**
@@ -128,9 +151,13 @@
* format
*/
@VisibleForTesting
- public KernelCpuThreadReader(Path procPath, Path initialTimeInStatePath) throws IOException {
+ public KernelCpuThreadReader(
+ Path procPath,
+ Path initialTimeInStatePath,
+ Injector injector) throws IOException {
mProcPath = procPath;
mProcTimeInStateReader = new ProcTimeInStateReader(initialTimeInStatePath);
+ mInjector = injector;
// Copy mProcTimeInState's frequencies and initialize bucketing
final long[] frequenciesKhz = mProcTimeInStateReader.getFrequenciesKhz();
@@ -154,6 +181,67 @@
}
/**
+ * Get the per-thread CPU usage of all processes belonging to UIDs between {@code [1000, 2000)}
+ */
+ @Nullable
+ public ArrayList<ProcessCpuUsage> getProcessCpuUsageByUids() {
+ return getProcessCpuUsageByUids(DEFAULT_UID_PREDICATE);
+ }
+
+ /**
+ * Get the per-thread CPU usage of all processes belonging to a set of UIDs
+ *
+ * <p>This function will crawl through all process {@code proc} directories found by the pattern
+ * {@code /proc/[0-9]*}, and then check the UID using {@code /proc/$PID/status}. This takes
+ * approximately 500ms on a Pixel 2. Therefore, this method can be computationally expensive,
+ * and should not be called more than once an hour.
+ *
+ * @param uidPredicate only get usage from processes owned by UIDs that match this predicate
+ */
+ @Nullable
+ public ArrayList<ProcessCpuUsage> getProcessCpuUsageByUids(Predicate<Integer> uidPredicate) {
+ if (DEBUG) {
+ Slog.d(TAG, "Reading CPU thread usages for processes owned by UIDs");
+ }
+
+ final ArrayList<ProcessCpuUsage> processCpuUsages = new ArrayList<>();
+
+ try (DirectoryStream<Path> processPaths =
+ Files.newDirectoryStream(mProcPath, PROCESS_DIRECTORY_FILTER)) {
+ for (Path processPath : processPaths) {
+ final int processId = getProcessId(processPath);
+ final int uid = mInjector.getUidForPid(processId);
+ if (uid == ID_ERROR || processId == ID_ERROR) {
+ continue;
+ }
+ if (!uidPredicate.test(uid)) {
+ continue;
+ }
+
+ final ProcessCpuUsage processCpuUsage =
+ getProcessCpuUsage(processPath, processId, uid);
+ if (processCpuUsage != null) {
+ processCpuUsages.add(processCpuUsage);
+ }
+ }
+ } catch (IOException e) {
+ Slog.w("Failed to iterate over process paths", e);
+ return null;
+ }
+
+ if (processCpuUsages.isEmpty()) {
+ Slog.w(TAG, "Didn't successfully get any process CPU information for UIDs specified");
+ return null;
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Read usage for " + processCpuUsages.size() + " processes");
+ }
+
+ return processCpuUsages;
+ }
+
+ /**
* Read all of the CPU usage statistics for each child thread of the current process
*
* @return process CPU usage containing usage of all child threads
@@ -162,8 +250,8 @@
public ProcessCpuUsage getCurrentProcessCpuUsage() {
return getProcessCpuUsage(
mProcPath.resolve("self"),
- Process.myPid(),
- Process.myUid());
+ mInjector.myPid(),
+ mInjector.myUid());
}
/**
@@ -172,7 +260,8 @@
* @param processPath the {@code /proc} path of the thread
* @param processId the ID of the process
* @param uid the ID of the user who owns the process
- * @return process CPU usage containing usage of all child threads
+ * @return process CPU usage containing usage of all child threads. Null if the process exited
+ * and its {@code proc} directory was removed while collecting information
*/
@Nullable
private ProcessCpuUsage getProcessCpuUsage(Path processPath, int processId, int uid) {
@@ -224,7 +313,8 @@
* Get a thread's CPU usage
*
* @param threadDirectory the {@code /proc} directory of the thread
- * @return null in the case that the directory read failed
+ * @return thread CPU usage. Null if the thread exited and its {@code proc} directory was
+ * removed while collecting information
*/
@Nullable
private ThreadCpuUsage getThreadCpuUsage(Path threadDirectory) {
@@ -280,6 +370,22 @@
}
/**
+ * Get the ID of a process from its path
+ *
+ * @param processPath {@code proc} path of the process
+ * @return the ID, {@link #ID_ERROR} if the path could not be parsed
+ */
+ private int getProcessId(Path processPath) {
+ String fileName = processPath.getFileName().toString();
+ try {
+ return Integer.parseInt(fileName);
+ } catch (NumberFormatException e) {
+ Slog.w(TAG, "Failed to parse " + fileName + " as process ID", e);
+ return ID_ERROR;
+ }
+ }
+
+ /**
* Puts frequencies and usage times into buckets
*/
@VisibleForTesting
@@ -443,4 +549,31 @@
this.usageTimesMillis = usageTimesMillis;
}
}
+
+ /**
+ * Used to inject static methods from {@link Process}
+ */
+ @VisibleForTesting
+ public static class Injector {
+ /**
+ * Get the PID of the current process
+ */
+ public int myPid() {
+ return Process.myPid();
+ }
+
+ /**
+ * Get the UID that owns the current process
+ */
+ public int myUid() {
+ return Process.myUid();
+ }
+
+ /**
+ * Get the UID for the process with ID {@code pid}
+ */
+ public int getUidForPid(int pid) {
+ return Process.getUidForPid(pid);
+ }
+ }
}
diff --git a/core/java/com/android/internal/os/ProcTimeInStateReader.java b/core/java/com/android/internal/os/ProcTimeInStateReader.java
index 3a63498..2318473 100644
--- a/core/java/com/android/internal/os/ProcTimeInStateReader.java
+++ b/core/java/com/android/internal/os/ProcTimeInStateReader.java
@@ -19,9 +19,15 @@
import android.annotation.Nullable;
import android.os.Process;
+import com.android.internal.util.ArrayUtils;
+
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
/**
* Reads and parses {@code time_in_state} files in the {@code proc} filesystem.
@@ -43,6 +49,17 @@
*
* This file would indicate that the CPU has spent 30 milliseconds at frequency 300,000KHz (300Mhz)
* and 10 milliseconds at frequency 1,900,800KHz (1.9GHz).
+ *
+ * <p>This class will also read {@code time_in_state} files with headers, such as:
+ * <pre>
+ * cpu0
+ * 300000 3
+ * 364800 0
+ * ...
+ * cpu4
+ * 300000 1
+ * 364800 4
+ * </pre>
*/
public class ProcTimeInStateReader {
private static final String TAG = "ProcTimeInStateReader";
@@ -51,24 +68,28 @@
* The format of a single line of the {@code time_in_state} file that exports the frequency
* values
*/
- private static final int[] TIME_IN_STATE_LINE_FREQUENCY_FORMAT = {
+ private static final List<Integer> TIME_IN_STATE_LINE_FREQUENCY_FORMAT = Arrays.asList(
Process.PROC_OUT_LONG | Process.PROC_SPACE_TERM,
- Process.PROC_NEWLINE_TERM,
- };
+ Process.PROC_NEWLINE_TERM
+ );
/**
* The format of a single line of the {@code time_in_state} file that exports the time values
*/
- private static final int[] TIME_IN_STATE_LINE_TIME_FORMAT = {
+ private static final List<Integer> TIME_IN_STATE_LINE_TIME_FORMAT = Arrays.asList(
Process.PROC_SPACE_TERM,
- Process.PROC_OUT_LONG | Process.PROC_NEWLINE_TERM,
- };
+ Process.PROC_OUT_LONG | Process.PROC_NEWLINE_TERM
+ );
/**
- * The format of the {@code time_in_state} file, defined using {@link Process}'s {@code
- * PROC_OUT_LONG} and related variables
- *
- * Defined on first successful read of {@code time_in_state} file.
+ * The format of a header line of the {@code time_in_state} file
+ */
+ private static final List<Integer> TIME_IN_STATE_HEADER_LINE_FORMAT =
+ Collections.singletonList(Process.PROC_NEWLINE_TERM);
+
+ /**
+ * The format of the {@code time_in_state} file to extract times, defined using {@link
+ * Process}'s {@code PROC_OUT_LONG} and related variables
*/
private int[] mTimeInStateTimeFormat;
@@ -141,46 +162,44 @@
// Read the bytes of the `time_in_state` file
byte[] timeInStateBytes = Files.readAllBytes(timeInStatePath);
- // The number of lines in the `time_in_state` file is the number of frequencies available
+ // Iterate over the lines of the time_in_state file, for each one adding a line to the
+ // formats. These formats are used to extract either the frequencies or the times from a
+ // time_in_state file
+ // Also check if each line is a header, and handle this in the created format arrays
+ ArrayList<Integer> timeInStateFrequencyFormat = new ArrayList<>();
+ ArrayList<Integer> timeInStateTimeFormat = new ArrayList<>();
int numFrequencies = 0;
for (int i = 0; i < timeInStateBytes.length; i++) {
- if (timeInStateBytes[i] == '\n') {
+ // If the first character of the line is not a digit, we treat it as a header
+ if (!Character.isDigit(timeInStateBytes[i])) {
+ timeInStateFrequencyFormat.addAll(TIME_IN_STATE_HEADER_LINE_FORMAT);
+ timeInStateTimeFormat.addAll(TIME_IN_STATE_HEADER_LINE_FORMAT);
+ } else {
+ timeInStateFrequencyFormat.addAll(TIME_IN_STATE_LINE_FREQUENCY_FORMAT);
+ timeInStateTimeFormat.addAll(TIME_IN_STATE_LINE_TIME_FORMAT);
numFrequencies++;
}
- }
- if (numFrequencies == 0) {
- throw new IOException("Empty time_in_state file");
+ // Go to the next line
+ while (i < timeInStateBytes.length && timeInStateBytes[i] != '\n') {
+ i++;
+ }
}
- // Set `mTimeInStateTimeFormat` and `timeInStateFrequencyFormat` to the correct length, and
- // then copy in the `TIME_IN_STATE_{FREQUENCY,TIME}_LINE_FORMAT` until it's full. As we only
- // use the frequency format in this method, it is not an member variable.
- final int[] timeInStateTimeFormat =
- new int[numFrequencies * TIME_IN_STATE_LINE_TIME_FORMAT.length];
- final int[] timeInStateFrequencyFormat =
- new int[numFrequencies * TIME_IN_STATE_LINE_FREQUENCY_FORMAT.length];
- for (int i = 0; i < numFrequencies; i++) {
- System.arraycopy(
- TIME_IN_STATE_LINE_FREQUENCY_FORMAT, 0, timeInStateFrequencyFormat,
- i * TIME_IN_STATE_LINE_FREQUENCY_FORMAT.length,
- TIME_IN_STATE_LINE_FREQUENCY_FORMAT.length);
- System.arraycopy(
- TIME_IN_STATE_LINE_TIME_FORMAT, 0, timeInStateTimeFormat,
- i * TIME_IN_STATE_LINE_TIME_FORMAT.length,
- TIME_IN_STATE_LINE_TIME_FORMAT.length);
+ if (numFrequencies == 0) {
+ throw new IOException("Empty time_in_state file");
}
// Read the frequencies from the `time_in_state` file and store them, as they will be the
// same for every `time_in_state` file
final long[] readLongs = new long[numFrequencies];
final boolean readSuccess = Process.parseProcLine(
- timeInStateBytes, 0, timeInStateBytes.length, timeInStateFrequencyFormat,
- null, readLongs, null);
+ timeInStateBytes, 0, timeInStateBytes.length,
+ ArrayUtils.convertToIntArray(timeInStateFrequencyFormat), null, readLongs, null);
if (!readSuccess) {
throw new IOException("Failed to parse time_in_state file");
}
- mTimeInStateTimeFormat = timeInStateTimeFormat;
+ mTimeInStateTimeFormat = ArrayUtils.convertToIntArray(timeInStateTimeFormat);
mFrequenciesKhz = readLongs;
}
}
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index ccbe0ee..49d5007 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -692,14 +692,8 @@
static long get_allocated_vmalloc_memory() {
char line[1024];
- // Ignored tags that don't actually consume memory (ie remappings)
- static const char* const ignored_tags[] = {
- "ioremap",
- "map_lowmem",
- "vm_map_ram",
- NULL
- };
- long size, vmalloc_allocated_size = 0;
+
+ long vmalloc_allocated_size = 0;
UniqueFile fp = MakeUniqueFile("/proc/vmallocinfo", "re");
if (fp == nullptr) {
@@ -710,17 +704,15 @@
if (fgets(line, 1024, fp.get()) == NULL) {
break;
}
- bool valid_line = true;
- int i = 0;
- while (ignored_tags[i]) {
- if (strstr(line, ignored_tags[i]) != NULL) {
- valid_line = false;
- break;
- }
- i++;
+
+ // check to see if there are pages mapped in vmalloc area
+ if (!strstr(line, "pages=")) {
+ continue;
}
- if (valid_line && (sscanf(line, "%*x-%*x %ld", &size) == 1)) {
- vmalloc_allocated_size += size;
+
+ long nr_pages;
+ if (sscanf(line, "%*x-%*x %*ld %*s pages=%ld", &nr_pages) == 1) {
+ vmalloc_allocated_size += (nr_pages * getpagesize());
}
}
return vmalloc_allocated_size;
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/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 3a33d57..46aa5b4 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -16,12 +16,9 @@
package android.view.textclassifier;
-import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.any;
@@ -41,315 +38,24 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TextClassificationManagerTest {
private static final LocaleList LOCALES = LocaleList.forLanguageTags("en-US");
- private static final String NO_TYPE = null;
private Context mContext;
private TextClassificationManager mTcm;
- private TextClassifier mClassifier;
@Before
public void setup() {
mContext = InstrumentationRegistry.getTargetContext();
mTcm = mContext.getSystemService(TextClassificationManager.class);
- // Test with the local textClassifier only. (We only bundle "en" model by default).
- // It's hard to reliably test the results of the device's TextClassifierServiceImpl here.
- mClassifier = mTcm.getTextClassifier(TextClassifier.LOCAL);
- }
-
- @Test
- public void testSmartSelection() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Contact me at droid@android.com";
- String selected = "droid";
- String suggested = "droid@android.com";
- int startIndex = text.indexOf(selected);
- int endIndex = startIndex + selected.length();
- int smartStartIndex = text.indexOf(suggested);
- int smartEndIndex = smartStartIndex + suggested.length();
- TextSelection.Request request = new TextSelection.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextSelection selection = mClassifier.suggestSelection(request);
- assertThat(selection,
- isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
- }
-
- @Test
- public void testSmartSelection_url() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Visit http://www.android.com for more information";
- String selected = "http";
- String suggested = "http://www.android.com";
- int startIndex = text.indexOf(selected);
- int endIndex = startIndex + selected.length();
- int smartStartIndex = text.indexOf(suggested);
- int smartEndIndex = smartStartIndex + suggested.length();
- TextSelection.Request request = new TextSelection.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextSelection selection = mClassifier.suggestSelection(request);
- assertThat(selection,
- isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_URL));
- }
-
- @Test
- public void testSmartSelection_withEmoji() {
- if (isTextClassifierDisabled()) return;
-
- String text = "\uD83D\uDE02 Hello.";
- String selected = "Hello";
- int startIndex = text.indexOf(selected);
- int endIndex = startIndex + selected.length();
- TextSelection.Request request = new TextSelection.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextSelection selection = mClassifier.suggestSelection(request);
- assertThat(selection,
- isTextSelection(startIndex, endIndex, NO_TYPE));
- }
-
- @Test
- public void testClassifyText() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Contact me at droid@android.com";
- String classifiedText = "droid@android.com";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_EMAIL));
- }
-
- @Test
- public void testTextClassifyText_url() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Visit www.android.com for more information";
- String classifiedText = "www.android.com";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
- }
-
- @Test
- public void testTextClassifyText_address() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Brandschenkestrasse 110, Zürich, Switzerland";
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, 0, text.length())
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification, isTextClassification(text, TextClassifier.TYPE_ADDRESS));
- }
-
- @Test
- public void testTextClassifyText_url_inCaps() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Visit HTTP://ANDROID.COM for more information";
- String classifiedText = "HTTP://ANDROID.COM";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
- }
-
- @Test
- public void testTextClassifyText_date() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Let's meet on January 9, 2018.";
- String classifiedText = "January 9, 2018";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_DATE));
- }
-
- @Test
- public void testTextClassifyText_datetime() {
- if (isTextClassifierDisabled()) return;
-
- String text = "Let's meet 2018/01/01 10:30:20.";
- String classifiedText = "2018/01/01 10:30:20";
- int startIndex = text.indexOf(classifiedText);
- int endIndex = startIndex + classifiedText.length();
- TextClassification.Request request = new TextClassification.Request.Builder(
- text, startIndex, endIndex)
- .setDefaultLocales(LOCALES)
- .build();
-
- TextClassification classification = mClassifier.classifyText(request);
- assertThat(classification,
- isTextClassification(classifiedText, TextClassifier.TYPE_DATE_TIME));
- }
-
- @Test
- public void testGenerateLinks_phone() {
- if (isTextClassifierDisabled()) return;
- String text = "The number is +12122537077. See you tonight!";
- TextLinks.Request request = new TextLinks.Request.Builder(text).build();
- assertThat(mClassifier.generateLinks(request),
- isTextLinksContaining(text, "+12122537077", TextClassifier.TYPE_PHONE));
- }
-
- @Test
- public void testGenerateLinks_exclude() {
- if (isTextClassifierDisabled()) return;
- String text = "You want apple@banana.com. See you tonight!";
- List<String> hints = Collections.EMPTY_LIST;
- List<String> included = Collections.EMPTY_LIST;
- List<String> excluded = Arrays.asList(TextClassifier.TYPE_EMAIL);
- TextLinks.Request request = new TextLinks.Request.Builder(text)
- .setEntityConfig(TextClassifier.EntityConfig.create(hints, included, excluded))
- .setDefaultLocales(LOCALES)
- .build();
- assertThat(mClassifier.generateLinks(request),
- not(isTextLinksContaining(text, "apple@banana.com", TextClassifier.TYPE_EMAIL)));
- }
-
- @Test
- public void testGenerateLinks_explicit_address() {
- if (isTextClassifierDisabled()) return;
- String text = "The address is 1600 Amphitheater Parkway, Mountain View, CA. See you!";
- List<String> explicit = Arrays.asList(TextClassifier.TYPE_ADDRESS);
- TextLinks.Request request = new TextLinks.Request.Builder(text)
- .setEntityConfig(TextClassifier.EntityConfig.createWithExplicitEntityList(explicit))
- .setDefaultLocales(LOCALES)
- .build();
- assertThat(mClassifier.generateLinks(request),
- isTextLinksContaining(text, "1600 Amphitheater Parkway, Mountain View, CA",
- TextClassifier.TYPE_ADDRESS));
- }
-
- @Test
- public void testGenerateLinks_exclude_override() {
- if (isTextClassifierDisabled()) return;
- String text = "You want apple@banana.com. See you tonight!";
- List<String> hints = Collections.EMPTY_LIST;
- List<String> included = Arrays.asList(TextClassifier.TYPE_EMAIL);
- List<String> excluded = Arrays.asList(TextClassifier.TYPE_EMAIL);
- TextLinks.Request request = new TextLinks.Request.Builder(text)
- .setEntityConfig(TextClassifier.EntityConfig.create(hints, included, excluded))
- .setDefaultLocales(LOCALES)
- .build();
- assertThat(mClassifier.generateLinks(request),
- not(isTextLinksContaining(text, "apple@banana.com", TextClassifier.TYPE_EMAIL)));
- }
-
- @Test
- public void testGenerateLinks_maxLength() {
- if (isTextClassifierDisabled()) return;
- char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength()];
- Arrays.fill(manySpaces, ' ');
- TextLinks.Request request = new TextLinks.Request.Builder(new String(manySpaces)).build();
- TextLinks links = mClassifier.generateLinks(request);
- assertTrue(links.getLinks().isEmpty());
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testGenerateLinks_tooLong() {
- if (isTextClassifierDisabled()) {
- throw new IllegalArgumentException("pass if disabled");
- }
- char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength() + 1];
- Arrays.fill(manySpaces, ' ');
- TextLinks.Request request = new TextLinks.Request.Builder(new String(manySpaces)).build();
- mClassifier.generateLinks(request);
- }
-
- @Test
- public void testDetectLanguage() {
- if (isTextClassifierDisabled()) return;
- String text = "This is English text";
- TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
- TextLanguage textLanguage = mClassifier.detectLanguage(request);
- assertThat(textLanguage, isTextLanguage("en"));
- }
-
- @Test
- public void testDetectLanguage_japanese() {
- if (isTextClassifierDisabled()) return;
- String text = "これは日本語のテキストです";
- TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
- TextLanguage textLanguage = mClassifier.detectLanguage(request);
- assertThat(textLanguage, isTextLanguage("ja"));
- }
-
- @Test
- public void testSuggestConversationActions_textReplyOnly_maxThree() {
- if (isTextClassifierDisabled()) return;
- ConversationActions.Message message =
- new ConversationActions.Message.Builder().setText("Hello").build();
- ConversationActions.TypeConfig typeConfig =
- new ConversationActions.TypeConfig.Builder().includeTypesFromTextClassifier(false)
- .setIncludedTypes(
- Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
- .build();
- ConversationActions.Request request =
- new ConversationActions.Request.Builder(Collections.singletonList(message))
- .setMaxSuggestions(1)
- .setTypeConfig(typeConfig)
- .build();
-
- ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
- assertTrue(conversationActions.getConversationActions().size() <= 1);
- for (ConversationActions.ConversationAction conversationAction :
- conversationActions.getConversationActions()) {
- assertEquals(conversationAction.getType(), ConversationActions.TYPE_TEXT_REPLY);
- assertNotNull(conversationAction.getTextReply());
- assertTrue(conversationAction.getConfidenceScore() > 0);
- assertTrue(conversationAction.getConfidenceScore() <= 1);
- }
}
@Test
@@ -411,102 +117,4 @@
assertFalse(result.getActions().isEmpty());
assertNotSame(result, fallbackResult);
}
-
- private boolean isTextClassifierDisabled() {
- return mClassifier == TextClassifier.NO_OP;
- }
-
- private static Matcher<TextSelection> isTextSelection(
- final int startIndex, final int endIndex, final String type) {
- return new BaseMatcher<TextSelection>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof TextSelection) {
- TextSelection selection = (TextSelection) o;
- return startIndex == selection.getSelectionStartIndex()
- && endIndex == selection.getSelectionEndIndex()
- && typeMatches(selection, type);
- }
- return false;
- }
-
- private boolean typeMatches(TextSelection selection, String type) {
- return type == null
- || (selection.getEntityCount() > 0
- && type.trim().equalsIgnoreCase(selection.getEntity(0)));
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendValue(
- String.format("%d, %d, %s", startIndex, endIndex, type));
- }
- };
- }
-
- private static Matcher<TextLinks> isTextLinksContaining(
- final String text, final String substring, final String type) {
- return new BaseMatcher<TextLinks>() {
-
- @Override
- public void describeTo(Description description) {
- description.appendText("text=").appendValue(text)
- .appendText(", substring=").appendValue(substring)
- .appendText(", type=").appendValue(type);
- }
-
- @Override
- public boolean matches(Object o) {
- if (o instanceof TextLinks) {
- for (TextLinks.TextLink link : ((TextLinks) o).getLinks()) {
- if (text.subSequence(link.getStart(), link.getEnd()).equals(substring)) {
- return type.equals(link.getEntity(0));
- }
- }
- }
- return false;
- }
- };
- }
-
- private static Matcher<TextClassification> isTextClassification(
- final String text, final String type) {
- return new BaseMatcher<TextClassification>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof TextClassification) {
- TextClassification result = (TextClassification) o;
- return text.equals(result.getText())
- && result.getEntityCount() > 0
- && type.equals(result.getEntity(0));
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("text=").appendValue(text)
- .appendText(", type=").appendValue(type);
- }
- };
- }
-
- private static Matcher<TextLanguage> isTextLanguage(final String languageTag) {
- return new BaseMatcher<TextLanguage>() {
- @Override
- public boolean matches(Object o) {
- if (o instanceof TextLanguage) {
- TextLanguage result = (TextLanguage) o;
- return result.getLocaleHypothesisCount() > 0
- && languageTag.equals(result.getLocale(0).toLanguageTag());
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("locale=").appendValue(languageTag);
- }
- };
- }
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
new file mode 100644
index 0000000..06ba15e
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -0,0 +1,454 @@
+/*
+ * 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.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.os.LocaleList;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Testing {@link TextClassifierTest} APIs on local and system textclassifier.
+ * <p>
+ * Tests are skipped if such a textclassifier does not exist.
+ */
+@SmallTest
+@RunWith(Parameterized.class)
+public class TextClassifierTest {
+ private static final String LOCAL = "local";
+ private static final String SYSTEM = "system";
+
+ @Parameterized.Parameters(name = "{0}")
+ public static Iterable<Object> textClassifierTypes() {
+ return Arrays.asList(LOCAL, SYSTEM);
+ }
+
+ @Parameterized.Parameter
+ public String mTextClassifierType;
+
+ private static final LocaleList LOCALES = LocaleList.forLanguageTags("en-US");
+ private static final String NO_TYPE = null;
+
+ private Context mContext;
+ private TextClassificationManager mTcm;
+ private TextClassifier mClassifier;
+
+ @Before
+ public void setup() {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mTcm = mContext.getSystemService(TextClassificationManager.class);
+ mClassifier = mTcm.getTextClassifier(
+ mTextClassifierType.equals(LOCAL) ? TextClassifier.LOCAL : TextClassifier.SYSTEM);
+ }
+
+ @Test
+ public void testSmartSelection() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Contact me at droid@android.com";
+ String selected = "droid";
+ String suggested = "droid@android.com";
+ int startIndex = text.indexOf(selected);
+ int endIndex = startIndex + selected.length();
+ int smartStartIndex = text.indexOf(suggested);
+ int smartEndIndex = smartStartIndex + suggested.length();
+ TextSelection.Request request = new TextSelection.Request.Builder(
+ text, startIndex, endIndex)
+ .setDefaultLocales(LOCALES)
+ .build();
+
+ TextSelection selection = mClassifier.suggestSelection(request);
+ assertThat(selection,
+ isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
+ }
+
+ @Test
+ public void testSmartSelection_url() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Visit http://www.android.com for more information";
+ String selected = "http";
+ String suggested = "http://www.android.com";
+ int startIndex = text.indexOf(selected);
+ int endIndex = startIndex + selected.length();
+ int smartStartIndex = text.indexOf(suggested);
+ int smartEndIndex = smartStartIndex + suggested.length();
+ TextSelection.Request request = new TextSelection.Request.Builder(
+ text, startIndex, endIndex)
+ .setDefaultLocales(LOCALES)
+ .build();
+
+ TextSelection selection = mClassifier.suggestSelection(request);
+ assertThat(selection,
+ isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_URL));
+ }
+
+ @Test
+ public void testSmartSelection_withEmoji() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "\uD83D\uDE02 Hello.";
+ String selected = "Hello";
+ int startIndex = text.indexOf(selected);
+ int endIndex = startIndex + selected.length();
+ TextSelection.Request request = new TextSelection.Request.Builder(
+ text, startIndex, endIndex)
+ .setDefaultLocales(LOCALES)
+ .build();
+
+ TextSelection selection = mClassifier.suggestSelection(request);
+ assertThat(selection,
+ isTextSelection(startIndex, endIndex, NO_TYPE));
+ }
+
+ @Test
+ public void testClassifyText() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Contact me at droid@android.com";
+ String classifiedText = "droid@android.com";
+ int startIndex = text.indexOf(classifiedText);
+ int endIndex = startIndex + classifiedText.length();
+ TextClassification.Request request = new TextClassification.Request.Builder(
+ text, startIndex, endIndex)
+ .setDefaultLocales(LOCALES)
+ .build();
+
+ TextClassification classification = mClassifier.classifyText(request);
+ assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_EMAIL));
+ }
+
+ @Test
+ public void testTextClassifyText_url() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Visit www.android.com for more information";
+ String classifiedText = "www.android.com";
+ int startIndex = text.indexOf(classifiedText);
+ int endIndex = startIndex + classifiedText.length();
+ TextClassification.Request request = new TextClassification.Request.Builder(
+ text, startIndex, endIndex)
+ .setDefaultLocales(LOCALES)
+ .build();
+
+ TextClassification classification = mClassifier.classifyText(request);
+ assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
+ }
+
+ @Test
+ public void testTextClassifyText_address() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Brandschenkestrasse 110, Zürich, Switzerland";
+ TextClassification.Request request = new TextClassification.Request.Builder(
+ text, 0, text.length())
+ .setDefaultLocales(LOCALES)
+ .build();
+
+ TextClassification classification = mClassifier.classifyText(request);
+ assertThat(classification, isTextClassification(text, TextClassifier.TYPE_ADDRESS));
+ }
+
+ @Test
+ public void testTextClassifyText_url_inCaps() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Visit HTTP://ANDROID.COM for more information";
+ String classifiedText = "HTTP://ANDROID.COM";
+ int startIndex = text.indexOf(classifiedText);
+ int endIndex = startIndex + classifiedText.length();
+ TextClassification.Request request = new TextClassification.Request.Builder(
+ text, startIndex, endIndex)
+ .setDefaultLocales(LOCALES)
+ .build();
+
+ TextClassification classification = mClassifier.classifyText(request);
+ assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
+ }
+
+ @Test
+ public void testTextClassifyText_date() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Let's meet on January 9, 2018.";
+ String classifiedText = "January 9, 2018";
+ int startIndex = text.indexOf(classifiedText);
+ int endIndex = startIndex + classifiedText.length();
+ TextClassification.Request request = new TextClassification.Request.Builder(
+ text, startIndex, endIndex)
+ .setDefaultLocales(LOCALES)
+ .build();
+
+ TextClassification classification = mClassifier.classifyText(request);
+ assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_DATE));
+ }
+
+ @Test
+ public void testTextClassifyText_datetime() {
+ if (isTextClassifierDisabled()) return;
+
+ String text = "Let's meet 2018/01/01 10:30:20.";
+ String classifiedText = "2018/01/01 10:30:20";
+ int startIndex = text.indexOf(classifiedText);
+ int endIndex = startIndex + classifiedText.length();
+ TextClassification.Request request = new TextClassification.Request.Builder(
+ text, startIndex, endIndex)
+ .setDefaultLocales(LOCALES)
+ .build();
+
+ TextClassification classification = mClassifier.classifyText(request);
+ assertThat(classification,
+ isTextClassification(classifiedText, TextClassifier.TYPE_DATE_TIME));
+ }
+
+ @Test
+ public void testGenerateLinks_phone() {
+ if (isTextClassifierDisabled()) return;
+ String text = "The number is +12122537077. See you tonight!";
+ TextLinks.Request request = new TextLinks.Request.Builder(text).build();
+ assertThat(mClassifier.generateLinks(request),
+ isTextLinksContaining(text, "+12122537077", TextClassifier.TYPE_PHONE));
+ }
+
+ @Test
+ public void testGenerateLinks_exclude() {
+ if (isTextClassifierDisabled()) return;
+ String text = "You want apple@banana.com. See you tonight!";
+ List<String> hints = Collections.EMPTY_LIST;
+ List<String> included = Collections.EMPTY_LIST;
+ List<String> excluded = Arrays.asList(TextClassifier.TYPE_EMAIL);
+ TextLinks.Request request = new TextLinks.Request.Builder(text)
+ .setEntityConfig(TextClassifier.EntityConfig.create(hints, included, excluded))
+ .setDefaultLocales(LOCALES)
+ .build();
+ assertThat(mClassifier.generateLinks(request),
+ not(isTextLinksContaining(text, "apple@banana.com", TextClassifier.TYPE_EMAIL)));
+ }
+
+ @Test
+ public void testGenerateLinks_explicit_address() {
+ if (isTextClassifierDisabled()) return;
+ String text = "The address is 1600 Amphitheater Parkway, Mountain View, CA. See you!";
+ List<String> explicit = Arrays.asList(TextClassifier.TYPE_ADDRESS);
+ TextLinks.Request request = new TextLinks.Request.Builder(text)
+ .setEntityConfig(TextClassifier.EntityConfig.createWithExplicitEntityList(explicit))
+ .setDefaultLocales(LOCALES)
+ .build();
+ assertThat(mClassifier.generateLinks(request),
+ isTextLinksContaining(text, "1600 Amphitheater Parkway, Mountain View, CA",
+ TextClassifier.TYPE_ADDRESS));
+ }
+
+ @Test
+ public void testGenerateLinks_exclude_override() {
+ if (isTextClassifierDisabled()) return;
+ String text = "You want apple@banana.com. See you tonight!";
+ List<String> hints = Collections.EMPTY_LIST;
+ List<String> included = Arrays.asList(TextClassifier.TYPE_EMAIL);
+ List<String> excluded = Arrays.asList(TextClassifier.TYPE_EMAIL);
+ TextLinks.Request request = new TextLinks.Request.Builder(text)
+ .setEntityConfig(TextClassifier.EntityConfig.create(hints, included, excluded))
+ .setDefaultLocales(LOCALES)
+ .build();
+ assertThat(mClassifier.generateLinks(request),
+ not(isTextLinksContaining(text, "apple@banana.com", TextClassifier.TYPE_EMAIL)));
+ }
+
+ @Test
+ public void testGenerateLinks_maxLength() {
+ if (isTextClassifierDisabled()) return;
+ char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength()];
+ Arrays.fill(manySpaces, ' ');
+ TextLinks.Request request = new TextLinks.Request.Builder(new String(manySpaces)).build();
+ TextLinks links = mClassifier.generateLinks(request);
+ assertTrue(links.getLinks().isEmpty());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testGenerateLinks_tooLong() {
+ if (isTextClassifierDisabled()) {
+ throw new IllegalArgumentException("pass if disabled");
+ }
+ char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength() + 1];
+ Arrays.fill(manySpaces, ' ');
+ TextLinks.Request request = new TextLinks.Request.Builder(new String(manySpaces)).build();
+ mClassifier.generateLinks(request);
+ }
+
+ @Test
+ public void testDetectLanguage() {
+ if (isTextClassifierDisabled()) return;
+ String text = "This is English text";
+ TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
+ TextLanguage textLanguage = mClassifier.detectLanguage(request);
+ assertThat(textLanguage, isTextLanguage("en"));
+ }
+
+ @Test
+ public void testDetectLanguage_japanese() {
+ if (isTextClassifierDisabled()) return;
+ String text = "これは日本語のテキストです";
+ TextLanguage.Request request = new TextLanguage.Request.Builder(text).build();
+ TextLanguage textLanguage = mClassifier.detectLanguage(request);
+ assertThat(textLanguage, isTextLanguage("ja"));
+ }
+
+ @Test
+ public void testSuggestConversationActions_textReplyOnly_maxThree() {
+ if (isTextClassifierDisabled()) return;
+ ConversationActions.Message message =
+ new ConversationActions.Message.Builder().setText("Hello").build();
+ ConversationActions.TypeConfig typeConfig =
+ new ConversationActions.TypeConfig.Builder().includeTypesFromTextClassifier(false)
+ .setIncludedTypes(
+ Collections.singletonList(ConversationActions.TYPE_TEXT_REPLY))
+ .build();
+ ConversationActions.Request request =
+ new ConversationActions.Request.Builder(Collections.singletonList(message))
+ .setMaxSuggestions(3)
+ .setTypeConfig(typeConfig)
+ .build();
+
+ ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
+ assertTrue(conversationActions.getConversationActions().size() > 0);
+ assertTrue(conversationActions.getConversationActions().size() <= 3);
+ for (ConversationActions.ConversationAction conversationAction :
+ conversationActions.getConversationActions()) {
+ assertEquals(conversationAction.getType(), ConversationActions.TYPE_TEXT_REPLY);
+ assertNotNull(conversationAction.getTextReply());
+ assertTrue(conversationAction.getConfidenceScore() > 0);
+ assertTrue(conversationAction.getConfidenceScore() <= 1);
+ }
+ }
+
+
+ private boolean isTextClassifierDisabled() {
+ return mClassifier == null || mClassifier == TextClassifier.NO_OP;
+ }
+
+ private static Matcher<TextSelection> isTextSelection(
+ final int startIndex, final int endIndex, final String type) {
+ return new BaseMatcher<TextSelection>() {
+ @Override
+ public boolean matches(Object o) {
+ if (o instanceof TextSelection) {
+ TextSelection selection = (TextSelection) o;
+ return startIndex == selection.getSelectionStartIndex()
+ && endIndex == selection.getSelectionEndIndex()
+ && typeMatches(selection, type);
+ }
+ return false;
+ }
+
+ private boolean typeMatches(TextSelection selection, String type) {
+ return type == null
+ || (selection.getEntityCount() > 0
+ && type.trim().equalsIgnoreCase(selection.getEntity(0)));
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendValue(
+ String.format("%d, %d, %s", startIndex, endIndex, type));
+ }
+ };
+ }
+
+ private static Matcher<TextLinks> isTextLinksContaining(
+ final String text, final String substring, final String type) {
+ return new BaseMatcher<TextLinks>() {
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("text=").appendValue(text)
+ .appendText(", substring=").appendValue(substring)
+ .appendText(", type=").appendValue(type);
+ }
+
+ @Override
+ public boolean matches(Object o) {
+ if (o instanceof TextLinks) {
+ for (TextLinks.TextLink link : ((TextLinks) o).getLinks()) {
+ if (text.subSequence(link.getStart(), link.getEnd()).equals(substring)) {
+ return type.equals(link.getEntity(0));
+ }
+ }
+ }
+ return false;
+ }
+ };
+ }
+
+ private static Matcher<TextClassification> isTextClassification(
+ final String text, final String type) {
+ return new BaseMatcher<TextClassification>() {
+ @Override
+ public boolean matches(Object o) {
+ if (o instanceof TextClassification) {
+ TextClassification result = (TextClassification) o;
+ return text.equals(result.getText())
+ && result.getEntityCount() > 0
+ && type.equals(result.getEntity(0));
+ }
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("text=").appendValue(text)
+ .appendText(", type=").appendValue(type);
+ }
+ };
+ }
+
+ private static Matcher<TextLanguage> isTextLanguage(final String languageTag) {
+ return new BaseMatcher<TextLanguage>() {
+ @Override
+ public boolean matches(Object o) {
+ if (o instanceof TextLanguage) {
+ TextLanguage result = (TextLanguage) o;
+ return result.getLocaleHypothesisCount() > 0
+ && languageTag.equals(result.getLocale(0).toLanguageTag());
+ }
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("locale=").appendValue(languageTag);
+ }
+ };
+ }
+}
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 c866bc4..b242a34 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelCpuThreadReaderTest.java
@@ -39,13 +39,16 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.function.Predicate;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class KernelCpuThreadReaderTest {
- private static final String PROCESS_NAME = "test_process";
+ private static final int UID = 1000;
+ private static final int PROCESS_ID = 1234;
private static final int[] THREAD_IDS = {0, 1000, 1235, 4321};
+ private static final String PROCESS_NAME = "test_process";
private static final String[] THREAD_NAMES = {
"test_thread_1", "test_thread_2", "test_thread_3", "test_thread_4"
};
@@ -73,49 +76,126 @@
}
@Test
- public void testSimple() throws IOException {
- // Make /proc/self
- final Path selfPath = mProcDirectory.toPath().resolve("self");
- assertTrue(selfPath.toFile().mkdirs());
+ public void testReader_currentProcess() throws IOException {
+ KernelCpuThreadReader.Injector processUtils =
+ new KernelCpuThreadReader.Injector() {
+ @Override
+ public int myPid() {
+ return PROCESS_ID;
+ }
- // Make /proc/self/task
- final Path selfThreadsPath = selfPath.resolve("task");
+ @Override
+ public int myUid() {
+ return UID;
+ }
+
+ @Override
+ public int getUidForPid(int pid) {
+ return 0;
+ }
+ };
+ setupDirectory(mProcDirectory.toPath().resolve("self"), THREAD_IDS, PROCESS_NAME,
+ THREAD_NAMES, THREAD_CPU_FREQUENCIES, THREAD_CPU_TIMES);
+
+ final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
+ mProcDirectory.toPath(),
+ mProcDirectory.toPath().resolve("self/task/" + THREAD_IDS[0] + "/time_in_state"),
+ processUtils);
+ final KernelCpuThreadReader.ProcessCpuUsage processCpuUsage =
+ kernelCpuThreadReader.getCurrentProcessCpuUsage();
+ checkResults(processCpuUsage, kernelCpuThreadReader.getCpuFrequenciesKhz(), UID, PROCESS_ID,
+ THREAD_IDS, PROCESS_NAME, THREAD_NAMES, THREAD_CPU_FREQUENCIES, THREAD_CPU_TIMES);
+ }
+
+ @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;
+ int[] expectedUids = new int[]{0, 4, 5, 6000};
+ KernelCpuThreadReader.Injector processUtils =
+ new KernelCpuThreadReader.Injector() {
+ @Override
+ public int myPid() {
+ return 0;
+ }
+
+ @Override
+ public int myUid() {
+ return 0;
+ }
+
+ @Override
+ public int getUidForPid(int pid) {
+ return pid;
+ }
+ };
+
+ for (int uid : uids) {
+ setupDirectory(mProcDirectory.toPath().resolve(String.valueOf(uid)),
+ new int[]{uid * 10},
+ "process" + uid, new String[]{"thread" + uid}, new int[]{1000},
+ new int[][]{{uid}});
+ }
+ final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
+ mProcDirectory.toPath(),
+ mProcDirectory.toPath().resolve(uids[0] + "/task/" + uids[0] + "/time_in_state"),
+ processUtils);
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsageByUids =
+ kernelCpuThreadReader.getProcessCpuUsageByUids(uidPredicate);
+ processCpuUsageByUids.sort(Comparator.comparing(usage -> usage.processId));
+
+ assertEquals(expectedUids.length, processCpuUsageByUids.size());
+ for (int i = 0; i < expectedUids.length; i++) {
+ KernelCpuThreadReader.ProcessCpuUsage processCpuUsage =
+ processCpuUsageByUids.get(i);
+ 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}});
+ }
+ }
+
+ private void setupDirectory(Path processPath, int[] threadIds, String processName,
+ String[] threadNames, int[] cpuFrequencies, int[][] cpuTimes) throws IOException {
+ // Make /proc/$PID
+ assertTrue(processPath.toFile().mkdirs());
+
+ // Make /proc/$PID/task
+ final Path selfThreadsPath = processPath.resolve("task");
assertTrue(selfThreadsPath.toFile().mkdirs());
- // Make /proc/self/cmdline
- Files.write(selfPath.resolve("cmdline"), PROCESS_NAME.getBytes());
+ // Make /proc/$PID/cmdline
+ Files.write(processPath.resolve("cmdline"), processName.getBytes());
// Make thread directories in reverse order, as they are read in order of creation by
// CpuThreadProcReader
- for (int i = 0; i < THREAD_IDS.length; i++) {
- // Make /proc/self/task/$TID
- final Path threadPath = selfThreadsPath.resolve(String.valueOf(THREAD_IDS[i]));
+ for (int i = 0; i < threadIds.length; i++) {
+ // Make /proc/$PID/task/$TID
+ final Path threadPath = selfThreadsPath.resolve(String.valueOf(threadIds[i]));
assertTrue(threadPath.toFile().mkdirs());
- // Make /proc/self/task/$TID/comm
- Files.write(threadPath.resolve("comm"), THREAD_NAMES[i].getBytes());
+ // Make /proc/$PID/task/$TID/comm
+ Files.write(threadPath.resolve("comm"), threadNames[i].getBytes());
- // Make /proc/self/task/$TID/time_in_state
+ // Make /proc/$PID/task/$TID/time_in_state
final OutputStream timeInStateStream =
Files.newOutputStream(threadPath.resolve("time_in_state"));
- for (int j = 0; j < THREAD_CPU_FREQUENCIES.length; j++) {
- final String line = String.valueOf(THREAD_CPU_FREQUENCIES[j]) + " "
- + String.valueOf(THREAD_CPU_TIMES[i][j]) + "\n";
+ for (int j = 0; j < cpuFrequencies.length; j++) {
+ final String line = String.valueOf(cpuFrequencies[j]) + " "
+ + String.valueOf(cpuTimes[i][j]) + "\n";
timeInStateStream.write(line.getBytes());
}
timeInStateStream.close();
}
+ }
- final KernelCpuThreadReader kernelCpuThreadReader = new KernelCpuThreadReader(
- mProcDirectory.toPath(),
- mProcDirectory.toPath().resolve("self/task/" + THREAD_IDS[0] + "/time_in_state"));
- final KernelCpuThreadReader.ProcessCpuUsage processCpuUsage =
- kernelCpuThreadReader.getCurrentProcessCpuUsage();
-
+ private void checkResults(KernelCpuThreadReader.ProcessCpuUsage processCpuUsage,
+ int[] readerCpuFrequencies, int uid, int processId, int[] threadIds, String processName,
+ String[] threadNames, int[] cpuFrequencies, int[][] cpuTimes) {
assertNotNull(processCpuUsage);
- assertEquals(android.os.Process.myPid(), processCpuUsage.processId);
- assertEquals(android.os.Process.myUid(), processCpuUsage.uid);
- assertEquals(PROCESS_NAME, processCpuUsage.processName);
+ assertEquals(processId, processCpuUsage.processId);
+ assertEquals(uid, processCpuUsage.uid);
+ assertEquals(processName, processCpuUsage.processName);
// Sort the thread CPU usages to compare with test case
final ArrayList<KernelCpuThreadReader.ThreadCpuUsage> threadCpuUsages =
@@ -124,21 +204,21 @@
int threadCount = 0;
for (KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage : threadCpuUsages) {
- assertEquals(THREAD_IDS[threadCount], threadCpuUsage.threadId);
- assertEquals(THREAD_NAMES[threadCount], threadCpuUsage.threadName);
+ assertEquals(threadIds[threadCount], threadCpuUsage.threadId);
+ assertEquals(threadNames[threadCount], threadCpuUsage.threadName);
for (int i = 0; i < threadCpuUsage.usageTimesMillis.length; i++) {
assertEquals(
- THREAD_CPU_TIMES[threadCount][i] * 10,
+ cpuTimes[threadCount][i] * 10,
threadCpuUsage.usageTimesMillis[i]);
assertEquals(
- THREAD_CPU_FREQUENCIES[i],
- kernelCpuThreadReader.getCpuFrequenciesKhz()[i]);
+ cpuFrequencies[i],
+ readerCpuFrequencies[i]);
}
threadCount++;
}
- assertEquals(threadCount, THREAD_IDS.length);
+ assertEquals(threadCount, threadIds.length);
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java b/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
index f2a531f..2893066 100644
--- a/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/ProcTimeInStateReaderTest.java
@@ -70,6 +70,23 @@
}
@Test
+ public void testHeaderFormat() throws IOException {
+ final Path initialTimeInStateFile = mProcDirectory.toPath().resolve(
+ "initial-time-in-state");
+ Files.write(initialTimeInStateFile, "header1\n1 2\nheader2:\n3 4\n5 6\n7 8\n".getBytes());
+ final ProcTimeInStateReader reader = new ProcTimeInStateReader(initialTimeInStateFile);
+
+ assertArrayEquals(
+ "Reported frequencies are correct",
+ new long[]{1, 3, 5, 7},
+ reader.getFrequenciesKhz());
+ assertArrayEquals(
+ "Reported usage times are correct",
+ new long[]{20, 40, 60, 80},
+ reader.getUsageTimesMillis(initialTimeInStateFile));
+ }
+
+ @Test
public void testDifferentFile() throws IOException {
Path initialTimeInStateFile = mProcDirectory.toPath().resolve("initial-time-in-state");
Files.write(initialTimeInStateFile, "1 2\n3 4\n5 6\n7 8\n".getBytes());
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 7216a22..072fe73 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -282,8 +282,11 @@
* Returns {@code true} if the entry no longer exists.
*/
public static boolean deleteUserKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
- return keystore.delete(Credentials.USER_PRIVATE_KEY + alias, uid) ||
- keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
+ int ret = keystore.delete2(Credentials.USER_PRIVATE_KEY + alias, uid);
+ if (ret == KeyStore.KEY_NOT_FOUND) {
+ return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
+ }
+ return ret == KeyStore.NO_ERROR;
}
/**
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 6d58d95..6e6ed30 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -267,16 +267,20 @@
}
}
- public boolean delete(String key, int uid) {
+ int delete2(String key, int uid) {
try {
- int ret = mBinder.del(key, uid);
- return (ret == NO_ERROR || ret == KEY_NOT_FOUND);
+ return mBinder.del(key, uid);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
- return false;
+ return SYSTEM_ERROR;
}
}
+ public boolean delete(String key, int uid) {
+ int ret = delete2(key, uid);
+ return ret == NO_ERROR || ret == KEY_NOT_FOUND;
+ }
+
@UnsupportedAppUsage
public boolean delete(String key) {
return delete(key, UID_SELF);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 9c707bab..9a15ff2 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -30,6 +30,7 @@
#include <SkColorSpaceXformCanvas.h>
#include <SkDeque.h>
#include <SkDrawable.h>
+#include <SkFont.h>
#include <SkGraphics.h>
#include <SkImage.h>
#include <SkImagePriv.h>
@@ -732,6 +733,7 @@
float y, float boundsLeft, float boundsTop, float boundsRight,
float boundsBottom, float totalAdvance) {
if (count <= 0 || paint.nothingToDraw()) return;
+ SkFont font = SkFont::LEGACY_ExtractFromPaint(paint);
SkPaint paintCopy(paint);
if (mPaintFilter) {
mPaintFilter->filter(&paintCopy);
@@ -748,7 +750,7 @@
SkRect::MakeLTRB(boundsLeft + x, boundsTop + y, boundsRight + x, boundsBottom + y);
SkTextBlobBuilder builder;
- const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPos(paintCopy, count, &bounds);
+ const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPos(font, count, &bounds);
glyphFunc(buffer.glyphs, buffer.pos);
sk_sp<SkTextBlob> textBlob(builder.make());
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index c5a6ec5..f1d9397 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -28,10 +28,13 @@
"libgui",
"libui",
"libinput",
- "libinputflinger",
"libnativewindow",
],
+ header_libs: [
+ "libinputflinger_headers",
+ ],
+
include_dirs: ["frameworks/native/services"],
cflags: [
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index eb3469e..7f4e5a5 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -24,7 +24,7 @@
#include <ui/DisplayInfo.h>
#include <input/Input.h>
-#include <inputflinger/PointerControllerInterface.h>
+#include <PointerControllerInterface.h>
#include <utils/BitSet.h>
#include <utils/RefBase.h>
#include <utils/Looper.h>
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index f1325ce..4f23cca 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -595,10 +595,10 @@
case CONTENT_TYPE_MUSIC:
case CONTENT_TYPE_SONIFICATION:
case CONTENT_TYPE_SPEECH:
- mContentType = contentType;
- break;
+ mContentType = contentType;
+ break;
default:
- mUsage = CONTENT_TYPE_UNKNOWN;
+ mContentType = CONTENT_TYPE_UNKNOWN;
}
return this;
}
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
deleted file mode 100644
index a633e5f..0000000
--- a/media/java/android/media/MediaController2.java
+++ /dev/null
@@ -1,863 +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;
-
-import static android.media.MediaPlayerBase.BUFFERING_STATE_UNKNOWN;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.media.MediaPlaylistAgent.RepeatMode;
-import android.media.MediaPlaylistAgent.ShuffleMode;
-import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.ControllerInfo;
-import android.media.MediaSession2.ErrorCode;
-import android.media.session.MediaSessionManager;
-import android.media.update.ApiLoader;
-import android.media.update.MediaController2Provider;
-import android.media.update.MediaController2Provider.PlaybackInfoProvider;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * @hide
- * Allows an app to interact with an active {@link MediaSession2} in any status. Media buttons and
- * other commands can be sent to the session.
- * <p>
- * When you're done, use {@link #close()} to clean up resources. This also helps session service
- * to be destroyed when there's no controller associated with it.
- * <p>
- * When controlling {@link MediaSession2}, the controller will be available immediately after
- * the creation.
- * <p>
- * A controller can be created through token from {@link MediaSessionManager} if you hold the
- * signature|privileged permission "android.permission.MEDIA_CONTENT_CONTROL" permission or are
- * an enabled notification listener or by getting a {@link SessionToken2} directly the
- * the session owner.
- * <p>
- * MediaController2 objects are thread-safe.
- * <p>
- * @see MediaSession2
- */
-public class MediaController2 implements AutoCloseable {
- /**
- * Interface for listening to change in activeness of the {@link MediaSession2}. It's
- * active if and only if it has set a player.
- */
- public abstract static class ControllerCallback {
- /**
- * Called when the controller is successfully connected to the session. The controller
- * becomes available afterwards.
- *
- * @param controller the controller for this event
- * @param allowedCommands commands that's allowed by the session.
- */
- public void onConnected(@NonNull MediaController2 controller,
- @NonNull SessionCommandGroup2 allowedCommands) { }
-
- /**
- * Called when the session refuses the controller or the controller is disconnected from
- * the session. The controller becomes unavailable afterwards and the callback wouldn't
- * be called.
- * <p>
- * It will be also called after the {@link #close()}, so you can put clean up code here.
- * You don't need to call {@link #close()} after this.
- *
- * @param controller the controller for this event
- * @param controller controller for this event
- */
- public void onDisconnected(@NonNull MediaController2 controller) { }
-
- /**
- * Called when the session set the custom layout through the
- * {@link MediaSession2#setCustomLayout(ControllerInfo, List)}.
- * <p>
- * Can be called before {@link #onConnected(MediaController2, SessionCommandGroup2)} is
- * called.
- *
- * @param controller the controller for this event
- * @param layout
- */
- public void onCustomLayoutChanged(@NonNull MediaController2 controller,
- @NonNull List<CommandButton> layout) { }
-
- /**
- * Called when the session has changed anything related with the {@link PlaybackInfo}.
- *
- * @param controller the controller for this event
- * @param info new playback info
- */
- public void onPlaybackInfoChanged(@NonNull MediaController2 controller,
- @NonNull PlaybackInfo info) { }
-
- /**
- * Called when the allowed commands are changed by session.
- *
- * @param controller the controller for this event
- * @param commands newly allowed commands
- */
- public void onAllowedCommandsChanged(@NonNull MediaController2 controller,
- @NonNull SessionCommandGroup2 commands) { }
-
- /**
- * Called when the session sent a custom command.
- *
- * @param controller the controller for this event
- * @param command
- * @param args
- * @param receiver
- */
- public void onCustomCommand(@NonNull MediaController2 controller,
- @NonNull SessionCommand2 command, @Nullable Bundle args,
- @Nullable ResultReceiver receiver) { }
-
- /**
- * Called when the player state is changed.
- *
- * @param controller the controller for this event
- * @param state
- */
- public void onPlayerStateChanged(@NonNull MediaController2 controller, int state) { }
-
- /**
- * Called when playback speed is changed.
- *
- * @param controller the controller for this event
- * @param speed speed
- */
- public void onPlaybackSpeedChanged(@NonNull MediaController2 controller,
- float speed) { }
-
- /**
- * Called to report buffering events for a data source.
- * <p>
- * Use {@link #getBufferedPosition()} for current buffering position.
- *
- * @param controller the controller for this event
- * @param item the media item for which buffering is happening.
- * @param state the new buffering state.
- */
- public void onBufferingStateChanged(@NonNull MediaController2 controller,
- @NonNull MediaItem2 item, @MediaPlayerBase.BuffState int state) { }
-
- /**
- * Called to indicate that seeking is completed.
- *
- * @param controller the controller for this event.
- * @param position the previous seeking request.
- */
- public void onSeekCompleted(@NonNull MediaController2 controller, long position) { }
-
- /**
- * Called when a error from
- *
- * @param controller the controller for this event
- * @param errorCode error code
- * @param extras extra information
- */
- public void onError(@NonNull MediaController2 controller, @ErrorCode int errorCode,
- @Nullable Bundle extras) { }
-
- /**
- * Called when the player's currently playing item is changed
- * <p>
- * When it's called, you should invalidate previous playback information and wait for later
- * callbacks.
- *
- * @param controller the controller for this event
- * @param item new item
- * @see #onBufferingStateChanged(MediaController2, MediaItem2, int)
- */
- // TODO(jaewan): Use this (b/74316764)
- public void onCurrentMediaItemChanged(@NonNull MediaController2 controller,
- @NonNull MediaItem2 item) { }
-
- /**
- * Called when a playlist is changed.
- *
- * @param controller the controller for this event
- * @param list new playlist
- * @param metadata new metadata
- */
- public void onPlaylistChanged(@NonNull MediaController2 controller,
- @NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) { }
-
- /**
- * Called when a playlist metadata is changed.
- *
- * @param controller the controller for this event
- * @param metadata new metadata
- */
- public void onPlaylistMetadataChanged(@NonNull MediaController2 controller,
- @Nullable MediaMetadata2 metadata) { }
-
- /**
- * Called when the shuffle mode is changed.
- *
- * @param controller the controller for this event
- * @param shuffleMode repeat mode
- * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE
- * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL
- * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP
- */
- public void onShuffleModeChanged(@NonNull MediaController2 controller,
- @MediaPlaylistAgent.ShuffleMode int shuffleMode) { }
-
- /**
- * Called when the repeat mode is changed.
- *
- * @param controller the controller for this event
- * @param repeatMode repeat mode
- * @see MediaPlaylistAgent#REPEAT_MODE_NONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ALL
- * @see MediaPlaylistAgent#REPEAT_MODE_GROUP
- */
- public void onRepeatModeChanged(@NonNull MediaController2 controller,
- @MediaPlaylistAgent.RepeatMode int repeatMode) { }
- }
-
- /**
- * Holds information about the current playback and how audio is handled for
- * this session.
- */
- // The same as MediaController.PlaybackInfo
- public static final class PlaybackInfo {
- /**
- * The session uses remote playback.
- */
- public static final int PLAYBACK_TYPE_REMOTE = 2;
- /**
- * The session uses local playback.
- */
- public static final int PLAYBACK_TYPE_LOCAL = 1;
-
- private final PlaybackInfoProvider mProvider;
-
- /**
- * @hide
- */
- public PlaybackInfo(PlaybackInfoProvider provider) {
- mProvider = provider;
- }
-
- /**
- * @hide
- */
- public PlaybackInfoProvider getProvider() {
- return mProvider;
- }
-
- /**
- * Get the type of playback which affects volume handling. One of:
- * <ul>
- * <li>{@link #PLAYBACK_TYPE_LOCAL}</li>
- * <li>{@link #PLAYBACK_TYPE_REMOTE}</li>
- * </ul>
- *
- * @return The type of playback this session is using.
- */
- public int getPlaybackType() {
- return mProvider.getPlaybackType_impl();
- }
-
- /**
- * Get the audio attributes for this session. The attributes will affect
- * volume handling for the session. When the volume type is
- * {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} these may be ignored by the
- * remote volume handler.
- *
- * @return The attributes for this session.
- */
- public AudioAttributes getAudioAttributes() {
- return mProvider.getAudioAttributes_impl();
- }
-
- /**
- * Get the type of volume control that can be used. One of:
- * <ul>
- * <li>{@link VolumeProvider2#VOLUME_CONTROL_ABSOLUTE}</li>
- * <li>{@link VolumeProvider2#VOLUME_CONTROL_RELATIVE}</li>
- * <li>{@link VolumeProvider2#VOLUME_CONTROL_FIXED}</li>
- * </ul>
- *
- * @return The type of volume control that may be used with this session.
- */
- public int getControlType() {
- return mProvider.getControlType_impl();
- }
-
- /**
- * Get the maximum volume that may be set for this session.
- *
- * @return The maximum allowed volume where this session is playing.
- */
- public int getMaxVolume() {
- return mProvider.getMaxVolume_impl();
- }
-
- /**
- * Get the current volume for this session.
- *
- * @return The current volume where this session is playing.
- */
- public int getCurrentVolume() {
- return mProvider.getCurrentVolume_impl();
- }
- }
-
- private final MediaController2Provider mProvider;
-
- /**
- * Create a {@link MediaController2} from the {@link SessionToken2}.
- * This connects to the session and may wake up the service if it's not available.
- *
- * @param context Context
- * @param token token to connect to
- * @param executor executor to run callbacks on.
- * @param callback controller callback to receive changes in
- */
- public MediaController2(@NonNull Context context, @NonNull SessionToken2 token,
- @NonNull @CallbackExecutor Executor executor, @NonNull ControllerCallback callback) {
- super();
-
- mProvider = createProvider(context, token, executor, callback);
- // This also connects to the token.
- // Explicit connect() isn't added on purpose because retrying connect() is impossible with
- // session whose session binder is only valid while it's active.
- // prevent a controller from reusable after the
- // session is released and recreated.
- mProvider.initialize();
- }
-
- MediaController2Provider createProvider(@NonNull Context context,
- @NonNull SessionToken2 token, @NonNull Executor executor,
- @NonNull ControllerCallback callback) {
- return ApiLoader.getProvider().createMediaController2(
- context, this, token, executor, callback);
- }
-
- /**
- * Release this object, and disconnect from the session. After this, callbacks wouldn't be
- * received.
- */
- @Override
- public void close() {
- mProvider.close_impl();
- }
-
- /**
- * @hide
- */
- public MediaController2Provider getProvider() {
- return mProvider;
- }
-
- /**
- * @return token
- */
- public @NonNull SessionToken2 getSessionToken() {
- return mProvider.getSessionToken_impl();
- }
-
- /**
- * Returns whether this class is connected to active {@link MediaSession2} or not.
- */
- public boolean isConnected() {
- return mProvider.isConnected_impl();
- }
-
- public void play() {
- mProvider.play_impl();
- }
-
- public void pause() {
- mProvider.pause_impl();
- }
-
- public void stop() {
- mProvider.stop_impl();
- }
-
- /**
- * Request that the player prepare its playback. In other words, other sessions can continue
- * to play during the preparation of this session. This method can be used to speed up the
- * start of the playback. Once the preparation is done, the session will change its playback
- * state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards, {@link #play} can be called
- * to start playback.
- */
- public void prepare() {
- mProvider.prepare_impl();
- }
-
- /**
- * Fast forwards playback. If playback is already fast forwarding this may increase the rate.
- */
- public void fastForward() {
- mProvider.fastForward_impl();
- }
-
- /**
- * Rewinds playback. If playback is already rewinding this may increase the rate.
- */
- public void rewind() {
- mProvider.rewind_impl();
- }
-
- /**
- * Move to a new location in the media stream.
- *
- * @param pos Position to move to, in milliseconds.
- */
- public void seekTo(long pos) {
- mProvider.seekTo_impl(pos);
- }
-
- /**
- * Revisit this API later.
- * @hide
- */
- public void skipForward() {
- // TODO(jaewan): (Post-P) Discuss this API later.
- // To match with KEYCODE_MEDIA_SKIP_FORWARD
- }
-
- /**
- * @hide
- */
- public void skipBackward() {
- // TODO(jaewan): (Post-P) Discuss this API later.
- // To match with KEYCODE_MEDIA_SKIP_BACKWARD
- }
-
- /**
- * Request that the player start playback for a specific media id.
- *
- * @param mediaId The id of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be played.
- */
- public void playFromMediaId(@NonNull String mediaId, @Nullable Bundle extras) {
- mProvider.playFromMediaId_impl(mediaId, extras);
- }
-
- /**
- * Request that the player start playback for a specific search query.
- *
- * @param query The search query. Should not be an empty string.
- * @param extras Optional extras that can include extra information about the query.
- */
- public void playFromSearch(@NonNull String query, @Nullable Bundle extras) {
- mProvider.playFromSearch_impl(query, extras);
- }
-
- /**
- * Request that the player start playback for a specific {@link Uri}.
- *
- * @param uri The URI of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be played.
- */
- public void playFromUri(@NonNull Uri uri, @Nullable Bundle extras) {
- mProvider.playFromUri_impl(uri, extras);
- }
-
- /**
- * Request that the player prepare playback for a specific media id. In other words, other
- * sessions can continue to play during the preparation of this session. This method can be
- * used to speed up the start of the playback. Once the preparation is done, the session
- * will change its playback state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards,
- * {@link #play} can be called to start playback. If the preparation is not needed,
- * {@link #playFromMediaId} can be directly called without this method.
- *
- * @param mediaId The id of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be prepared.
- */
- public void prepareFromMediaId(@NonNull String mediaId, @Nullable Bundle extras) {
- mProvider.prepareFromMediaId_impl(mediaId, extras);
- }
-
- /**
- * Request that the player prepare playback for a specific search query.
- * In other words, other sessions can continue to play during the preparation of this session.
- * This method can be used to speed up the start of the playback.
- * Once the preparation is done, the session will change its playback state to
- * {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards,
- * {@link #play} can be called to start playback. If the preparation is not needed,
- * {@link #playFromSearch} can be directly called without this method.
- *
- * @param query The search query. Should not be an empty string.
- * @param extras Optional extras that can include extra information about the query.
- */
- public void prepareFromSearch(@NonNull String query, @Nullable Bundle extras) {
- mProvider.prepareFromSearch_impl(query, extras);
- }
-
- /**
- * Request that the player prepare playback for a specific {@link Uri}. In other words,
- * other sessions can continue to play during the preparation of this session. This method
- * can be used to speed up the start of the playback. Once the preparation is done, the
- * session will change its playback state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}.
- * Afterwards, {@link #play} can be called to start playback. If the preparation is not needed,
- * {@link #playFromUri} can be directly called without this method.
- *
- * @param uri The URI of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be prepared.
- */
- public void prepareFromUri(@NonNull Uri uri, @Nullable Bundle extras) {
- mProvider.prepareFromUri_impl(uri, extras);
- }
-
- /**
- * Set the volume of the output this session is playing on. The command will be ignored if it
- * does not support {@link VolumeProvider2#VOLUME_CONTROL_ABSOLUTE}.
- * <p>
- * If the session is local playback, this changes the device's volume with the stream that
- * session's player is using. Flags will be specified for the {@link AudioManager}.
- * <p>
- * If the session is remote player (i.e. session has set volume provider), its volume provider
- * will receive this request instead.
- *
- * @see #getPlaybackInfo()
- * @param value The value to set it to, between 0 and the reported max.
- * @param flags flags from {@link AudioManager} to include with the volume request for local
- * playback
- */
- public void setVolumeTo(int value, int flags) {
- mProvider.setVolumeTo_impl(value, flags);
- }
-
- /**
- * Adjust the volume of the output this session is playing on. The direction
- * must be one of {@link AudioManager#ADJUST_LOWER},
- * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.
- * The command will be ignored if the session does not support
- * {@link VolumeProvider2#VOLUME_CONTROL_RELATIVE} or
- * {@link VolumeProvider2#VOLUME_CONTROL_ABSOLUTE}.
- * <p>
- * If the session is local playback, this changes the device's volume with the stream that
- * session's player is using. Flags will be specified for the {@link AudioManager}.
- * <p>
- * If the session is remote player (i.e. session has set volume provider), its volume provider
- * will receive this request instead.
- *
- * @see #getPlaybackInfo()
- * @param direction The direction to adjust the volume in.
- * @param flags flags from {@link AudioManager} to include with the volume request for local
- * playback
- */
- public void adjustVolume(int direction, int flags) {
- mProvider.adjustVolume_impl(direction, flags);
- }
-
- /**
- * Get an intent for launching UI associated with this session if one exists.
- *
- * @return A {@link PendingIntent} to launch UI or null.
- */
- public @Nullable PendingIntent getSessionActivity() {
- return mProvider.getSessionActivity_impl();
- }
-
- /**
- * Get the lastly cached player state from
- * {@link ControllerCallback#onPlayerStateChanged(MediaController2, int)}.
- *
- * @return player state
- */
- public int getPlayerState() {
- return mProvider.getPlayerState_impl();
- }
-
- /**
- * Gets the current playback position.
- * <p>
- * This returns the calculated value of the position, based on the difference between the
- * update time and current time.
- *
- * @return position
- */
- public long getCurrentPosition() {
- return mProvider.getCurrentPosition_impl();
- }
-
- /**
- * Get the lastly cached playback speed from
- * {@link ControllerCallback#onPlaybackSpeedChanged(MediaController2, float)}.
- *
- * @return speed
- */
- public float getPlaybackSpeed() {
- return mProvider.getPlaybackSpeed_impl();
- }
-
- /**
- * Set the playback speed.
- */
- public void setPlaybackSpeed(float speed) {
- // TODO(jaewan): implement this (b/74093080)
- }
-
-
- /**
- * Gets the current buffering state of the player.
- * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already
- * buffered.
- * @return the buffering state.
- */
- public @MediaPlayerBase.BuffState int getBufferingState() {
- // TODO(jaewan): Implement.
- return BUFFERING_STATE_UNKNOWN;
- }
-
- /**
- * Gets the lastly cached buffered position from the session when
- * {@link ControllerCallback#onBufferingStateChanged(MediaController2, MediaItem2, int)} is
- * called.
- *
- * @return buffering position in millis
- */
- public long getBufferedPosition() {
- return mProvider.getBufferedPosition_impl();
- }
-
- /**
- * Get the current playback info for this session.
- *
- * @return The current playback info or null.
- */
- public @Nullable PlaybackInfo getPlaybackInfo() {
- return mProvider.getPlaybackInfo_impl();
- }
-
- /**
- * Rate the media. This will cause the rating to be set for the current user.
- * The rating style must follow the user rating style from the session.
- * You can get the rating style from the session through the
- * {@link MediaMetadata#getRating(String)} with the key
- * {@link MediaMetadata#METADATA_KEY_USER_RATING}.
- * <p>
- * If the user rating was {@code null}, the media item does not accept setting user rating.
- *
- * @param mediaId The id of the media
- * @param rating The rating to set
- */
- public void setRating(@NonNull String mediaId, @NonNull Rating2 rating) {
- mProvider.setRating_impl(mediaId, rating);
- }
-
- /**
- * Send custom command to the session
- *
- * @param command custom command
- * @param args optional argument
- * @param cb optional result receiver
- */
- public void sendCustomCommand(@NonNull SessionCommand2 command, @Nullable Bundle args,
- @Nullable ResultReceiver cb) {
- mProvider.sendCustomCommand_impl(command, args, cb);
- }
-
- /**
- * Returns the cached playlist from
- * {@link ControllerCallback#onPlaylistChanged(MediaController2, List, MediaMetadata2)}.
- * <p>
- * This list may differ with the list that was specified with
- * {@link #setPlaylist(List, MediaMetadata2)} depending on the session implementation. Use media
- * items returned here for other playlist APIs such as {@link #skipToPlaylistItem(MediaItem2)}.
- *
- * @return The playlist. Can be {@code null} if the controller doesn't have enough permission or
- * the session hasn't set any playlist.
- */
- public @Nullable List<MediaItem2> getPlaylist() {
- return mProvider.getPlaylist_impl();
- }
-
- /**
- * Sets the playlist.
- * <p>
- * Even when the playlist is successfully set, use the playlist returned from
- * {@link #getPlaylist()} for playlist APIs such as {@link #skipToPlaylistItem(MediaItem2)}.
- * Otherwise the session in the remote process can't distinguish between media items.
- *
- * @param list playlist
- * @param metadata metadata of the playlist
- * @see #getPlaylist()
- * @see ControllerCallback#onPlaylistChanged(MediaController2, List, MediaMetadata2)
- */
- public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) {
- mProvider.setPlaylist_impl(list, metadata);
- }
-
- /**
- * Updates the playlist metadata
- *
- * @param metadata metadata of the playlist
- */
- public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) {
- mProvider.updatePlaylistMetadata_impl(metadata);
- }
-
- /**
- * Gets the lastly cached playlist playlist metadata either from
- * {@link ControllerCallback#onPlaylistMetadataChanged(MediaController2, MediaMetadata2)} or
- * {@link ControllerCallback#onPlaylistChanged(MediaController2, List, MediaMetadata2)}.
- *
- * @return metadata metadata of the playlist, or null if none is set
- */
- public @Nullable MediaMetadata2 getPlaylistMetadata() {
- return mProvider.getPlaylistMetadata_impl();
- }
-
-
- /**
- * Adds the media item to the playlist at position index. Index equals or greater than
- * the current playlist size will add the item at the end of the playlist.
- * <p>
- * This will not change the currently playing media item.
- * If index is less than or equal to the current index of the playlist,
- * the current index of the playlist will be incremented correspondingly.
- *
- * @param index the index you want to add
- * @param item the media item you want to add
- */
- public void addPlaylistItem(int index, @NonNull MediaItem2 item) {
- mProvider.addPlaylistItem_impl(index, item);
- }
-
- /**
- * Removes the media item at index in the playlist.
- *<p>
- * If the item is the currently playing item of the playlist, current playback
- * will be stopped and playback moves to next source in the list.
- *
- * @param item the media item you want to add
- */
- public void removePlaylistItem(@NonNull MediaItem2 item) {
- mProvider.removePlaylistItem_impl(item);
- }
-
- /**
- * Replace the media item at index in the playlist. This can be also used to update metadata of
- * an item.
- *
- * @param index the index of the item to replace
- * @param item the new item
- */
- public void replacePlaylistItem(int index, @NonNull MediaItem2 item) {
- mProvider.replacePlaylistItem_impl(index, item);
- }
-
- /**
- * Get the lastly cached current item from
- * {@link ControllerCallback#onCurrentMediaItemChanged(MediaController2, MediaItem2)}.
- *
- * @return index of the current item
- */
- public MediaItem2 getCurrentMediaItem() {
- return mProvider.getCurrentMediaItem_impl();
- }
-
- /**
- * Skips to the previous item in the playlist.
- * <p>
- * This calls {@link MediaSession2#skipToPreviousItem()} if the session allows.
- */
- public void skipToPreviousItem() {
- mProvider.skipToPreviousItem_impl();
- }
-
- /**
- * Skips to the next item in the playlist.
- * <p>
- * This calls {@link MediaSession2#skipToNextItem()} if the session allows.
- */
- public void skipToNextItem() {
- mProvider.skipToNextItem_impl();
- }
-
- /**
- * Skips to the item in the playlist.
- * <p>
- * This calls {@link MediaSession2#skipToPlaylistItem(MediaItem2)} if the session allows.
- *
- * @param item The item in the playlist you want to play
- */
- public void skipToPlaylistItem(@NonNull MediaItem2 item) {
- mProvider.skipToPlaylistItem_impl(item);
- }
-
- /**
- * Gets the cached repeat mode from the {@link ControllerCallback#onRepeatModeChanged(
- * MediaController2, int)}.
- *
- * @return repeat mode
- * @see MediaPlaylistAgent#REPEAT_MODE_NONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ALL
- * @see MediaPlaylistAgent#REPEAT_MODE_GROUP
- */
- public @RepeatMode int getRepeatMode() {
- return mProvider.getRepeatMode_impl();
- }
-
- /**
- * Sets the repeat mode.
- *
- * @param repeatMode repeat mode
- * @see MediaPlaylistAgent#REPEAT_MODE_NONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ALL
- * @see MediaPlaylistAgent#REPEAT_MODE_GROUP
- */
- public void setRepeatMode(@RepeatMode int repeatMode) {
- mProvider.setRepeatMode_impl(repeatMode);
- }
-
- /**
- * Gets the cached shuffle mode from the {@link ControllerCallback#onShuffleModeChanged(
- * MediaController2, int)}.
- *
- * @return The shuffle mode
- * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE
- * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL
- * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP
- */
- public @ShuffleMode int getShuffleMode() {
- return mProvider.getShuffleMode_impl();
- }
-
- /**
- * Sets the shuffle mode.
- *
- * @param shuffleMode The shuffle mode
- * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE
- * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL
- * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP
- */
- public void setShuffleMode(@ShuffleMode int shuffleMode) {
- mProvider.setShuffleMode_impl(shuffleMode);
- }
-}
diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java
deleted file mode 100644
index 423a1fd..0000000
--- a/media/java/android/media/MediaItem2.java
+++ /dev/null
@@ -1,220 +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;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.media.update.ApiLoader;
-import android.media.update.MediaItem2Provider;
-import android.os.Bundle;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * @hide
- * A class with information on a single media item with the metadata information.
- * Media item are application dependent so we cannot guarantee that they contain the right values.
- * <p>
- * When it's sent to a controller or browser, it's anonymized and data descriptor wouldn't be sent.
- * <p>
- * This object isn't a thread safe.
- */
-public class MediaItem2 {
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
- public @interface Flags { }
-
- /**
- * Flag: Indicates that the item has children of its own.
- */
- public static final int FLAG_BROWSABLE = 1 << 0;
-
- /**
- * Flag: Indicates that the item is playable.
- * <p>
- * The id of this item may be passed to
- * {@link MediaController2#playFromMediaId(String, Bundle)}
- */
- public static final int FLAG_PLAYABLE = 1 << 1;
-
- private final MediaItem2Provider mProvider;
-
- /**
- * Create a new media item
- * @hide
- */
- public MediaItem2(MediaItem2Provider provider) {
- mProvider = provider;
- }
-
- /**
- * @hide
- */
- public MediaItem2Provider getProvider() {
- return mProvider;
- }
-
- /**
- * Return this object as a bundle to share between processes.
- *
- * @return a new bundle instance
- */
- public Bundle toBundle() {
- return mProvider.toBundle_impl();
- }
-
- public static MediaItem2 fromBundle(Bundle bundle) {
- return ApiLoader.getProvider().fromBundle_MediaItem2(bundle);
- }
-
- public String toString() {
- return mProvider.toString_impl();
- }
-
- /**
- * Gets the flags of the item.
- */
- public @Flags int getFlags() {
- return mProvider.getFlags_impl();
- }
-
- /**
- * Returns whether this item is browsable.
- * @see #FLAG_BROWSABLE
- */
- public boolean isBrowsable() {
- return mProvider.isBrowsable_impl();
- }
-
- /**
- * Returns whether this item is playable.
- * @see #FLAG_PLAYABLE
- */
- public boolean isPlayable() {
- return mProvider.isPlayable_impl();
- }
-
- /**
- * Set a metadata. If the metadata is not null, its id should be matched with this instance's
- * media id.
- *
- * @param metadata metadata to update
- */
- public void setMetadata(@Nullable MediaMetadata2 metadata) {
- mProvider.setMetadata_impl(metadata);
- }
-
- /**
- * Returns the metadata of the media.
- */
- public @Nullable MediaMetadata2 getMetadata() {
- return mProvider.getMetadata_impl();
- }
-
- /**
- * Returns the media id for this item.
- */
- public @NonNull String getMediaId() {
- return mProvider.getMediaId_impl();
- }
-
- /**
- * Return the {@link DataSourceDesc}
- * <p>
- * Can be {@code null} if the MediaItem2 came from another process and anonymized
- *
- * @return data source descriptor
- */
- public @Nullable DataSourceDesc getDataSourceDesc() {
- return mProvider.getDataSourceDesc_impl();
- }
-
- @Override
- public boolean equals(Object obj) {
- return mProvider.equals_impl(obj);
- }
-
- /**
- * Build {@link MediaItem2}
- */
- public static final class Builder {
- private final MediaItem2Provider.BuilderProvider mProvider;
-
- /**
- * Constructor for {@link Builder}
- *
- * @param flags
- */
- public Builder(@Flags int flags) {
- mProvider = ApiLoader.getProvider().createMediaItem2Builder(this, flags);
- }
-
- /**
- * Set the media id of this instance. {@code null} for unset.
- * <p>
- * Media id is used to identify a media contents between session and controller.
- * <p>
- * If the metadata is set with the {@link #setMetadata(MediaMetadata2)} and it has
- * media id, id from {@link #setMediaId(String)} will be ignored and metadata's id will be
- * used instead. If the id isn't set neither by {@link #setMediaId(String)} nor
- * {@link #setMetadata(MediaMetadata2)}, id will be automatically generated.
- *
- * @param mediaId media id
- * @return this instance for chaining
- */
- public Builder setMediaId(@Nullable String mediaId) {
- return mProvider.setMediaId_impl(mediaId);
- }
-
- /**
- * Set the metadata of this instance. {@code null} for unset.
- * <p>
- * If the metadata is set with the {@link #setMetadata(MediaMetadata2)} and it has
- * media id, id from {@link #setMediaId(String)} will be ignored and metadata's id will be
- * used instead. If the id isn't set neither by {@link #setMediaId(String)} nor
- * {@link #setMetadata(MediaMetadata2)}, id will be automatically generated.
- *
- * @param metadata metadata
- * @return this instance for chaining
- */
- public Builder setMetadata(@Nullable MediaMetadata2 metadata) {
- return mProvider.setMetadata_impl(metadata);
- }
-
- /**
- * Set the data source descriptor for this instance. {@code null} for unset.
- *
- * @param dataSourceDesc data source descriptor
- * @return this instance for chaining
- */
- public Builder setDataSourceDesc(@Nullable DataSourceDesc dataSourceDesc) {
- return mProvider.setDataSourceDesc_impl(dataSourceDesc);
- }
-
- /**
- * Build {@link MediaItem2}.
- *
- * @return a new {@link MediaItem2}.
- */
- public MediaItem2 build() {
- return mProvider.build_impl();
- }
- }
-}
diff --git a/media/java/android/media/MediaMetadata2.java b/media/java/android/media/MediaMetadata2.java
deleted file mode 100644
index 7b03ae0..0000000
--- a/media/java/android/media/MediaMetadata2.java
+++ /dev/null
@@ -1,854 +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;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringDef;
-import android.graphics.Bitmap;
-import android.media.update.ApiLoader;
-import android.media.update.MediaMetadata2Provider;
-import android.net.Uri;
-import android.os.Bundle;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Set;
-
-/**
- * @hide
- * Contains metadata about an item, such as the title, artist, etc.
- */
-// New version of MediaMetadata with following changes
-// - Don't implement Parcelable for updatable support.
-// - Also support MediaDescription features. MediaDescription is deprecated instead because
-// it was insufficient for controller to display media contents.
-public final class MediaMetadata2 {
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the title of the media.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the artist of the media.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
-
- /**
- * The metadata key for a {@link Long} typed value to retrieve the information about the
- * duration of the media in ms. A negative duration indicates that the duration is unknown
- * (or infinite).
- *
- * @see Builder#putLong(String, long)
- * @see #getLong(String)
- */
- public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the album title for the media.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the author of the media.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the writer of the media.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the composer of the media.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the compilation status of the media.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the date the media was created or published.
- * The format is unspecified but RFC 3339 is recommended.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
-
- /**
- * The metadata key for a {@link Long} typed value to retrieve the information about the year
- * the media was created or published.
- *
- * @see Builder#putLong(String, long)
- * @see #getLong(String)
- */
- public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the genre of the media.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
-
- /**
- * The metadata key for a {@link Long} typed value to retrieve the information about the
- * track number for the media.
- *
- * @see Builder#putLong(String, long)
- * @see #getLong(String)
- */
- public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
-
- /**
- * The metadata key for a {@link Long} typed value to retrieve the information about the
- * number of tracks in the media's original source.
- *
- * @see Builder#putLong(String, long)
- * @see #getLong(String)
- */
- public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
-
- /**
- * The metadata key for a {@link Long} typed value to retrieve the information about the
- * disc number for the media's original source.
- *
- * @see Builder#putLong(String, long)
- * @see #getLong(String)
- */
- public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the artist for the album of the media's original source.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
-
- /**
- * The metadata key for a {@link Bitmap} typed value to retrieve the information about the
- * artwork for the media.
- * The artwork should be relatively small and may be scaled down if it is too large.
- * For higher resolution artwork, {@link #METADATA_KEY_ART_URI} should be used instead.
- *
- * @see Builder#putBitmap(String, Bitmap)
- * @see #getBitmap(String)
- */
- public static final String METADATA_KEY_ART = "android.media.metadata.ART";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about Uri of the artwork for the media.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
-
- /**
- * The metadata key for a {@link Bitmap} typed value to retrieve the information about the
- * artwork for the album of the media's original source.
- * The artwork should be relatively small and may be scaled down if it is too large.
- * For higher resolution artwork, {@link #METADATA_KEY_ALBUM_ART_URI} should be used instead.
- *
- * @see Builder#putBitmap(String, Bitmap)
- * @see #getBitmap(String)
- */
- public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the Uri of the artwork for the album of the media's original source.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
-
- /**
- * The metadata key for a {@link Rating2} typed value to retrieve the information about the
- * user's rating for the media.
- *
- * @see Builder#putRating(String, Rating2)
- * @see #getRating(String)
- */
- public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
-
- /**
- * The metadata key for a {@link Rating2} typed value to retrieve the information about the
- * overall rating for the media.
- *
- * @see Builder#putRating(String, Rating2)
- * @see #getRating(String)
- */
- public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the title that is suitable for display to the user.
- * It will generally be the same as {@link #METADATA_KEY_TITLE} but may differ for some formats.
- * When displaying media described by this metadata, this should be preferred if present.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the subtitle that is suitable for display to the user.
- * When displaying a second line for media described by this metadata, this should be preferred
- * to other fields if present.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_DISPLAY_SUBTITLE
- = "android.media.metadata.DISPLAY_SUBTITLE";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the description that is suitable for display to the user.
- * When displaying more information for media described by this metadata,
- * this should be preferred to other fields if present.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_DISPLAY_DESCRIPTION
- = "android.media.metadata.DISPLAY_DESCRIPTION";
-
- /**
- * The metadata key for a {@link Bitmap} typed value to retrieve the information about the icon
- * or thumbnail that is suitable for display to the user.
- * When displaying an icon for media described by this metadata, this should be preferred to
- * other fields if present.
- * <p>
- * The icon should be relatively small and may be scaled down if it is too large.
- * For higher resolution artwork, {@link #METADATA_KEY_DISPLAY_ICON_URI} should be used instead.
- *
- * @see Builder#putBitmap(String, Bitmap)
- * @see #getBitmap(String)
- */
- public static final String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the Uri of icon or thumbnail that is suitable for display to the user.
- * When displaying more information for media described by this metadata, the
- * display description should be preferred to other fields when present.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_DISPLAY_ICON_URI
- = "android.media.metadata.DISPLAY_ICON_URI";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the media ID of the content. This value is specific to the
- * service providing the content. If used, this should be a persistent
- * unique key for the underlying content. It may be used with
- * {@link MediaController2#playFromMediaId(String, Bundle)}
- * to initiate playback when provided by a {@link MediaBrowser2} connected to
- * the same app.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
-
- /**
- * The metadata key for a {@link CharSequence} or {@link String} typed value to retrieve the
- * information about the Uri of the content. This value is specific to the service providing the
- * content. It may be used with {@link MediaController2#playFromUri(Uri, Bundle)}
- * to initiate playback when provided by a {@link MediaBrowser2} connected to the same app.
- *
- * @see Builder#putText(String, CharSequence)
- * @see Builder#putString(String, String)
- * @see #getText(String)
- * @see #getString(String)
- */
- public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
-
- /**
- * The metadata key for a {@link Long} typed value to retrieve the information about the
- * bluetooth folder type of the media specified in the section 6.10.2.2 of the Bluetooth
- * AVRCP 1.5. It should be one of the following:
- * <ul>
- * <li>{@link #BT_FOLDER_TYPE_MIXED}</li>
- * <li>{@link #BT_FOLDER_TYPE_TITLES}</li>
- * <li>{@link #BT_FOLDER_TYPE_ALBUMS}</li>
- * <li>{@link #BT_FOLDER_TYPE_ARTISTS}</li>
- * <li>{@link #BT_FOLDER_TYPE_GENRES}</li>
- * <li>{@link #BT_FOLDER_TYPE_PLAYLISTS}</li>
- * <li>{@link #BT_FOLDER_TYPE_YEARS}</li>
- * </ul>
- *
- * @see Builder#putLong(String, long)
- * @see #getLong(String)
- */
- public static final String METADATA_KEY_BT_FOLDER_TYPE
- = "android.media.metadata.BT_FOLDER_TYPE";
-
- /**
- * The type of folder that is unknown or contains media elements of mixed types as specified in
- * the section 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_MIXED = 0;
-
- /**
- * The type of folder that contains media elements only as specified in the section 6.10.2.2 of
- * the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_TITLES = 1;
-
- /**
- * The type of folder that contains folders categorized by album as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_ALBUMS = 2;
-
- /**
- * The type of folder that contains folders categorized by artist as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_ARTISTS = 3;
-
- /**
- * The type of folder that contains folders categorized by genre as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_GENRES = 4;
-
- /**
- * The type of folder that contains folders categorized by playlist as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_PLAYLISTS = 5;
-
- /**
- * The type of folder that contains folders categorized by year as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_YEARS = 6;
-
- /**
- * The metadata key for a {@link Long} typed value to retrieve the information about whether
- * the media is an advertisement. A value of 0 indicates it is not an advertisement.
- * A value of 1 or non-zero indicates it is an advertisement.
- * If not specified, this value is set to 0 by default.
- *
- * @see Builder#putLong(String, long)
- * @see #getLong(String)
- */
- public static final String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT";
-
- /**
- * The metadata key for a {@link Long} typed value to retrieve the information about the
- * download status of the media which will be used for later offline playback. It should be
- * one of the following:
- *
- * <ul>
- * <li>{@link #STATUS_NOT_DOWNLOADED}</li>
- * <li>{@link #STATUS_DOWNLOADING}</li>
- * <li>{@link #STATUS_DOWNLOADED}</li>
- * </ul>
- *
- * @see Builder#putLong(String, long)
- * @see #getLong(String)
- */
- public static final String METADATA_KEY_DOWNLOAD_STATUS =
- "android.media.metadata.DOWNLOAD_STATUS";
-
- /**
- * The status value to indicate the media item is not downloaded.
- *
- * @see #METADATA_KEY_DOWNLOAD_STATUS
- */
- public static final long STATUS_NOT_DOWNLOADED = 0;
-
- /**
- * The status value to indicate the media item is being downloaded.
- *
- * @see #METADATA_KEY_DOWNLOAD_STATUS
- */
- public static final long STATUS_DOWNLOADING = 1;
-
- /**
- * The status value to indicate the media item is downloaded for later offline playback.
- *
- * @see #METADATA_KEY_DOWNLOAD_STATUS
- */
- public static final long STATUS_DOWNLOADED = 2;
-
- /**
- * A {@link Bundle} extra.
- */
- public static final String METADATA_KEY_EXTRAS = "android.media.metadata.EXTRAS";
-
- /**
- * @hide
- */
- @StringDef({METADATA_KEY_TITLE, METADATA_KEY_ARTIST, METADATA_KEY_ALBUM, METADATA_KEY_AUTHOR,
- METADATA_KEY_WRITER, METADATA_KEY_COMPOSER, METADATA_KEY_COMPILATION,
- METADATA_KEY_DATE, METADATA_KEY_GENRE, METADATA_KEY_ALBUM_ARTIST, METADATA_KEY_ART_URI,
- METADATA_KEY_ALBUM_ART_URI, METADATA_KEY_DISPLAY_TITLE, METADATA_KEY_DISPLAY_SUBTITLE,
- METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_KEY_DISPLAY_ICON_URI,
- METADATA_KEY_MEDIA_ID, METADATA_KEY_MEDIA_URI})
- @Retention(RetentionPolicy.SOURCE)
- public @interface TextKey {}
-
- /**
- * @hide
- */
- @StringDef({METADATA_KEY_DURATION, METADATA_KEY_YEAR, METADATA_KEY_TRACK_NUMBER,
- METADATA_KEY_NUM_TRACKS, METADATA_KEY_DISC_NUMBER, METADATA_KEY_BT_FOLDER_TYPE,
- METADATA_KEY_ADVERTISEMENT, METADATA_KEY_DOWNLOAD_STATUS})
- @Retention(RetentionPolicy.SOURCE)
- public @interface LongKey {}
-
- /**
- * @hide
- */
- @StringDef({METADATA_KEY_ART, METADATA_KEY_ALBUM_ART, METADATA_KEY_DISPLAY_ICON})
- @Retention(RetentionPolicy.SOURCE)
- public @interface BitmapKey {}
-
- /**
- * @hide
- */
- @StringDef({METADATA_KEY_USER_RATING, METADATA_KEY_RATING})
- @Retention(RetentionPolicy.SOURCE)
- public @interface RatingKey {}
-
- /**
- * @hide
- */
- // TODO(jaewan): Add predefined float key.
- @Retention(RetentionPolicy.SOURCE)
- public @interface FloatKey {}
-
- private final MediaMetadata2Provider mProvider;
-
- /**
- * @hide
- */
- public MediaMetadata2(MediaMetadata2Provider provider) {
- mProvider = provider;
- }
-
- /**
- * Returns true if the given key is contained in the metadata
- *
- * @param key a String key
- * @return true if the key exists in this metadata, false otherwise
- */
- public boolean containsKey(@NonNull String key) {
- return mProvider.containsKey_impl(key);
- }
-
- /**
- * Returns the value associated with the given key, or null if no mapping of
- * the desired type exists for the given key or a null value is explicitly
- * associated with the key.
- *
- * @param key The key the value is stored under
- * @return a CharSequence value, or null
- */
- public @Nullable CharSequence getText(@NonNull @TextKey String key) {
- return mProvider.getText_impl(key);
- }
-
- /**
- * Returns the media id, or {@code null} if the id doesn't exist.
- *<p>
- * This is equivalent to the {@link #getString(String)} with the {@link #METADATA_KEY_MEDIA_ID}.
- *
- * @return media id. Can be {@code null}
- * @see #METADATA_KEY_MEDIA_ID
- */
- public @Nullable String getMediaId() {
- return mProvider.getMediaId_impl();
- }
-
- /**
- * Returns the value associated with the given key, or null if no mapping of
- * the desired type exists for the given key or a null value is explicitly
- * associated with the key.
- *
- * @param key The key the value is stored under
- * @return a String value, or null
- */
- public @Nullable String getString(@NonNull @TextKey String key) {
- return mProvider.getString_impl(key);
- }
-
- /**
- * Returns the value associated with the given key, or 0L if no long exists
- * for the given key.
- *
- * @param key The key the value is stored under
- * @return a long value
- */
- public long getLong(@NonNull @LongKey String key) {
- return mProvider.getLong_impl(key);
- }
-
- /**
- * Return a {@link Rating2} for the given key or null if no rating exists for
- * the given key.
- * <p>
- * For the {@link #METADATA_KEY_USER_RATING}, A {@code null} return value means that user rating
- * cannot be set by {@link MediaController2}.
- *
- * @param key The key the value is stored under
- * @return A {@link Rating2} or {@code null}
- */
- public @Nullable Rating2 getRating(@NonNull @RatingKey String key) {
- return mProvider.getRating_impl(key);
- }
-
- /**
- * Return a {@link Bitmap} for the given key or null if no bitmap exists for
- * the given key.
- *
- * @param key The key the value is stored under
- * @return A {@link Bitmap} or null
- */
- public @Nullable Bitmap getBitmap(@NonNull @BitmapKey String key) {
- return mProvider.getBitmap_impl(key);
- }
-
- /**
- * Return the value associated with the given key, or 0.0f if no long exists
- * for the given key.
- *
- * @param key The key the value is stored under
- * @return a float value
- */
- public float getFloat(@NonNull @FloatKey String key) {
- return mProvider.getFloat_impl(key);
- }
-
- /**
- * Get the extra {@link Bundle} from the metadata object.
- *
- * @return A {@link Bundle} or {@code null}
- */
- public @Nullable Bundle getExtras() {
- return mProvider.getExtras_impl();
- }
-
- /**
- * Get the number of fields in this metadata.
- *
- * @return The number of fields in the metadata.
- */
- public int size() {
- return mProvider.size_impl();
- }
-
- /**
- * Returns a Set containing the Strings used as keys in this metadata.
- *
- * @return a Set of String keys
- */
- public @NonNull Set<String> keySet() {
- return mProvider.keySet_impl();
- }
-
- /**
- * Gets the bundle backing the metadata object. This is available to support
- * backwards compatibility. Apps should not modify the bundle directly.
- *
- * @return The Bundle backing this metadata.
- */
- public @NonNull Bundle toBundle() {
- return mProvider.toBundle_impl();
- }
-
- /**
- * Creates the {@link MediaMetadata2} from the bundle that previously returned by
- * {@link #toBundle()}.
- *
- * @param bundle bundle for the metadata
- * @return a new MediaMetadata2
- */
- public static @NonNull MediaMetadata2 fromBundle(@Nullable Bundle bundle) {
- return ApiLoader.getProvider().fromBundle_MediaMetadata2(bundle);
- }
-
- /**
- * Use to build MediaMetadata2 objects. The system defined metadata keys must
- * use the appropriate data type.
- */
- public static final class Builder {
- private final MediaMetadata2Provider.BuilderProvider mProvider;
-
- /**
- * Create an empty Builder. Any field that should be included in the
- * {@link MediaMetadata2} must be added.
- */
- public Builder() {
- mProvider = ApiLoader.getProvider().createMediaMetadata2Builder(this);
- }
-
- /**
- * Create a Builder using a {@link MediaMetadata2} instance to set the
- * initial values. All fields in the source metadata will be included in
- * the new metadata. Fields can be overwritten by adding the same key.
- *
- * @param source
- */
- public Builder(@NonNull MediaMetadata2 source) {
- mProvider = ApiLoader.getProvider().createMediaMetadata2Builder(this, source);
- }
-
- /**
- * @hide
- */
- public Builder(@NonNull MediaMetadata2Provider.BuilderProvider provider) {
- mProvider = provider;
- }
-
- /**
- * Put a CharSequence value into the metadata. Custom keys may be used,
- * but if the METADATA_KEYs defined in this class are used they may only
- * be one of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_TITLE}</li>
- * <li>{@link #METADATA_KEY_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ALBUM}</li>
- * <li>{@link #METADATA_KEY_AUTHOR}</li>
- * <li>{@link #METADATA_KEY_WRITER}</li>
- * <li>{@link #METADATA_KEY_COMPOSER}</li>
- * <li>{@link #METADATA_KEY_DATE}</li>
- * <li>{@link #METADATA_KEY_GENRE}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ART_URI}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
- * </ul>
- *
- * @param key The key for referencing this value
- * @param value The CharSequence value to store
- * @return The Builder to allow chaining
- */
- public @NonNull Builder putText(@NonNull @TextKey String key,
- @Nullable CharSequence value) {
- return mProvider.putText_impl(key, value);
- }
-
- /**
- * Put a String value into the metadata. Custom keys may be used, but if
- * the METADATA_KEYs defined in this class are used they may only be one
- * of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_TITLE}</li>
- * <li>{@link #METADATA_KEY_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ALBUM}</li>
- * <li>{@link #METADATA_KEY_AUTHOR}</li>
- * <li>{@link #METADATA_KEY_WRITER}</li>
- * <li>{@link #METADATA_KEY_COMPOSER}</li>
- * <li>{@link #METADATA_KEY_DATE}</li>
- * <li>{@link #METADATA_KEY_GENRE}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ART_URI}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
- * </ul>
- *
- * @param key The key for referencing this value
- * @param value The String value to store
- * @return The Builder to allow chaining
- */
- public @NonNull Builder putString(@NonNull @TextKey String key,
- @Nullable String value) {
- return mProvider.putString_impl(key, value);
- }
-
- /**
- * Put a long value into the metadata. Custom keys may be used, but if
- * the METADATA_KEYs defined in this class are used they may only be one
- * of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_DURATION}</li>
- * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li>
- * <li>{@link #METADATA_KEY_NUM_TRACKS}</li>
- * <li>{@link #METADATA_KEY_DISC_NUMBER}</li>
- * <li>{@link #METADATA_KEY_YEAR}</li>
- * <li>{@link #METADATA_KEY_BT_FOLDER_TYPE}</li>
- * <li>{@link #METADATA_KEY_ADVERTISEMENT}</li>
- * <li>{@link #METADATA_KEY_DOWNLOAD_STATUS}</li>
- * </ul>
- *
- * @param key The key for referencing this value
- * @param value The String value to store
- * @return The Builder to allow chaining
- */
- public @NonNull Builder putLong(@NonNull @LongKey String key, long value) {
- return mProvider.putLong_impl(key, value);
- }
-
- /**
- * Put a {@link Rating2} into the metadata. Custom keys may be used, but
- * if the METADATA_KEYs defined in this class are used they may only be
- * one of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_RATING}</li>
- * <li>{@link #METADATA_KEY_USER_RATING}</li>
- * </ul>
- *
- * @param key The key for referencing this value
- * @param value The String value to store
- * @return The Builder to allow chaining
- */
- public @NonNull Builder putRating(@NonNull @RatingKey String key, @Nullable Rating2 value) {
- return mProvider.putRating_impl(key, value);
- }
-
- /**
- * Put a {@link Bitmap} into the metadata. Custom keys may be used, but
- * if the METADATA_KEYs defined in this class are used they may only be
- * one of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_ART}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ART}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li>
- * </ul>
- * Large bitmaps may be scaled down by the system when
- * {@link android.media.session.MediaSession#setMetadata} is called.
- * To pass full resolution images {@link Uri Uris} should be used with
- * {@link #putString}.
- *
- * @param key The key for referencing this value
- * @param value The Bitmap to store
- * @return The Builder to allow chaining
- */
- public @NonNull Builder putBitmap(@NonNull @BitmapKey String key, @Nullable Bitmap value) {
- return mProvider.putBitmap_impl(key, value);
- }
-
- /**
- * Put a float value into the metadata. Custom keys may be used.
- *
- * @param key The key for referencing this value
- * @param value The float value to store
- * @return The Builder to allow chaining
- */
- public @NonNull Builder putFloat(@NonNull @LongKey String key, float value) {
- return mProvider.putFloat_impl(key, value);
- }
-
- /**
- * Set a bundle of extras.
- *
- * @param extras The extras to include with this description or null.
- * @return The Builder to allow chaining
- */
- public Builder setExtras(@Nullable Bundle extras) {
- return mProvider.setExtras_impl(extras);
- }
-
- /**
- * Creates a {@link MediaMetadata2} instance with the specified fields.
- *
- * @return The new MediaMetadata2 instance
- */
- public @NonNull MediaMetadata2 build() {
- return mProvider.build_impl();
- }
- }
-}
-
diff --git a/media/java/android/media/MediaPlaylistAgent.java b/media/java/android/media/MediaPlaylistAgent.java
deleted file mode 100644
index 88f37e7..0000000
--- a/media/java/android/media/MediaPlaylistAgent.java
+++ /dev/null
@@ -1,357 +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;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.media.update.ApiLoader;
-import android.media.update.MediaPlaylistAgentProvider;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * @hide
- * MediaPlaylistAgent is the abstract class an application needs to derive from to pass an object
- * to a MediaSession2 that will override default playlist handling behaviors. It contains a set of
- * notify methods to signal MediaSession2 that playlist-related state has changed.
- * <p>
- * Playlists are composed of one or multiple {@link MediaItem2} instances, which combine metadata
- * and data sources (as {@link DataSourceDesc})
- * Used by {@link MediaSession2} and {@link MediaController2}.
- */
-// This class only includes methods that contain {@link MediaItem2}.
-public abstract class MediaPlaylistAgent {
- /**
- * @hide
- */
- @IntDef({REPEAT_MODE_NONE, REPEAT_MODE_ONE, REPEAT_MODE_ALL,
- REPEAT_MODE_GROUP})
- @Retention(RetentionPolicy.SOURCE)
- public @interface RepeatMode {}
-
- /**
- * Playback will be stopped at the end of the playing media list.
- */
- public static final int REPEAT_MODE_NONE = 0;
-
- /**
- * Playback of the current playing media item will be repeated.
- */
- public static final int REPEAT_MODE_ONE = 1;
-
- /**
- * Playing media list will be repeated.
- */
- public static final int REPEAT_MODE_ALL = 2;
-
- /**
- * Playback of the playing media group will be repeated.
- * A group is a logical block of media items which is specified in the section 5.7 of the
- * Bluetooth AVRCP 1.6. An example of a group is the playlist.
- */
- public static final int REPEAT_MODE_GROUP = 3;
-
- /**
- * @hide
- */
- @IntDef({SHUFFLE_MODE_NONE, SHUFFLE_MODE_ALL, SHUFFLE_MODE_GROUP})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ShuffleMode {}
-
- /**
- * Media list will be played in order.
- */
- public static final int SHUFFLE_MODE_NONE = 0;
-
- /**
- * Media list will be played in shuffled order.
- */
- public static final int SHUFFLE_MODE_ALL = 1;
-
- /**
- * Media group will be played in shuffled order.
- * A group is a logical block of media items which is specified in the section 5.7 of the
- * Bluetooth AVRCP 1.6. An example of a group is the playlist.
- */
- public static final int SHUFFLE_MODE_GROUP = 2;
-
- private final MediaPlaylistAgentProvider mProvider;
-
- /**
- * A callback class to receive notifications for events on the media player. See
- * {@link MediaPlaylistAgent#registerPlaylistEventCallback(Executor, PlaylistEventCallback)}
- * to register this callback.
- */
- public static abstract class PlaylistEventCallback {
- /**
- * Called when a playlist is changed.
- *
- * @param playlistAgent playlist agent for this event
- * @param list new playlist
- * @param metadata new metadata
- */
- public void onPlaylistChanged(@NonNull MediaPlaylistAgent playlistAgent,
- @NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) { }
-
- /**
- * Called when a playlist metadata is changed.
- *
- * @param playlistAgent playlist agent for this event
- * @param metadata new metadata
- */
- public void onPlaylistMetadataChanged(@NonNull MediaPlaylistAgent playlistAgent,
- @Nullable MediaMetadata2 metadata) { }
-
- /**
- * Called when the shuffle mode is changed.
- *
- * @param playlistAgent playlist agent for this event
- * @param shuffleMode repeat mode
- * @see #SHUFFLE_MODE_NONE
- * @see #SHUFFLE_MODE_ALL
- * @see #SHUFFLE_MODE_GROUP
- */
- public void onShuffleModeChanged(@NonNull MediaPlaylistAgent playlistAgent,
- @ShuffleMode int shuffleMode) { }
-
- /**
- * Called when the repeat mode is changed.
- *
- * @param playlistAgent playlist agent for this event
- * @param repeatMode repeat mode
- * @see #REPEAT_MODE_NONE
- * @see #REPEAT_MODE_ONE
- * @see #REPEAT_MODE_ALL
- * @see #REPEAT_MODE_GROUP
- */
- public void onRepeatModeChanged(@NonNull MediaPlaylistAgent playlistAgent,
- @RepeatMode int repeatMode) { }
- }
-
- public MediaPlaylistAgent() {
- mProvider = ApiLoader.getProvider().createMediaPlaylistAgent(this);
- }
-
- /**
- * Register {@link PlaylistEventCallback} to listen changes in the underlying
- * {@link MediaPlaylistAgent}.
- *
- * @param executor a callback Executor
- * @param callback a PlaylistEventCallback
- * @throws IllegalArgumentException if executor or callback is {@code null}.
- */
- public final void registerPlaylistEventCallback(
- @NonNull @CallbackExecutor Executor executor, @NonNull PlaylistEventCallback callback) {
- mProvider.registerPlaylistEventCallback_impl(executor, callback);
- }
-
- /**
- * Unregister the previously registered {@link PlaylistEventCallback}.
- *
- * @param callback the callback to be removed
- * @throws IllegalArgumentException if the callback is {@code null}.
- */
- public final void unregisterPlaylistEventCallback(@NonNull PlaylistEventCallback callback) {
- mProvider.unregisterPlaylistEventCallback_impl(callback);
- }
-
- public final void notifyPlaylistChanged() {
- mProvider.notifyPlaylistChanged_impl();
- }
-
- public final void notifyPlaylistMetadataChanged() {
- mProvider.notifyPlaylistMetadataChanged_impl();
- }
-
- public final void notifyShuffleModeChanged() {
- mProvider.notifyShuffleModeChanged_impl();
- }
-
- public final void notifyRepeatModeChanged() {
- mProvider.notifyRepeatModeChanged_impl();
- }
-
- /**
- * Returns the playlist
- *
- * @return playlist, or null if none is set.
- */
- public @Nullable List<MediaItem2> getPlaylist() {
- return mProvider.getPlaylist_impl();
- }
-
- /**
- * Sets the playlist.
- *
- * @param list playlist
- * @param metadata metadata of the playlist
- */
- public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) {
- mProvider.setPlaylist_impl(list, metadata);
- }
-
- /**
- * Returns the playlist metadata
- *
- * @return metadata metadata of the playlist, or null if none is set
- */
- public @Nullable MediaMetadata2 getPlaylistMetadata() {
- return mProvider.getPlaylistMetadata_impl();
- }
-
- /**
- * Updates the playlist metadata
- *
- * @param metadata metadata of the playlist
- */
- public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) {
- mProvider.updatePlaylistMetadata_impl(metadata);
- }
-
- /**
- * Adds the media item to the playlist at position index. Index equals or greater than
- * the current playlist size will add the item at the end of the playlist.
- * <p>
- * This will not change the currently playing media item.
- * If index is less than or equal to the current index of the playlist,
- * the current index of the playlist will be incremented correspondingly.
- *
- * @param index the index you want to add
- * @param item the media item you want to add
- */
- public void addPlaylistItem(int index, @NonNull MediaItem2 item) {
- mProvider.addPlaylistItem_impl(index, item);
- }
-
- /**
- * Removes the media item from the playlist
- *
- * @param item media item to remove
- */
- public void removePlaylistItem(@NonNull MediaItem2 item) {
- mProvider.removePlaylistItem_impl(item);
- }
-
- /**
- * Replace the media item at index in the playlist. This can be also used to update metadata of
- * an item.
- *
- * @param index the index of the item to replace
- * @param item the new item
- */
- public void replacePlaylistItem(int index, @NonNull MediaItem2 item) {
- mProvider.replacePlaylistItem_impl(index, item);
- }
-
- /**
- * Skips to the the media item, and plays from it.
- *
- * @param item media item to start playing from
- */
- public void skipToPlaylistItem(@NonNull MediaItem2 item) {
- mProvider.skipToPlaylistItem_impl(item);
- }
-
- /**
- * Skips to the previous item in the playlist.
- */
- public void skipToPreviousItem() {
- mProvider.skipToPreviousItem_impl();
- }
-
- /**
- * Skips to the next item in the playlist.
- */
- public void skipToNextItem() {
- mProvider.skipToNextItem_impl();
- }
-
- /**
- * Gets the repeat mode
- *
- * @return repeat mode
- * @see #REPEAT_MODE_NONE
- * @see #REPEAT_MODE_ONE
- * @see #REPEAT_MODE_ALL
- * @see #REPEAT_MODE_GROUP
- */
- public @RepeatMode int getRepeatMode() {
- return mProvider.getRepeatMode_impl();
- }
-
- /**
- * Sets the repeat mode
- *
- * @param repeatMode repeat mode
- * @see #REPEAT_MODE_NONE
- * @see #REPEAT_MODE_ONE
- * @see #REPEAT_MODE_ALL
- * @see #REPEAT_MODE_GROUP
- */
- public void setRepeatMode(@RepeatMode int repeatMode) {
- mProvider.setRepeatMode_impl(repeatMode);
- }
-
- /**
- * Gets the shuffle mode
- *
- * @return The shuffle mode
- * @see #SHUFFLE_MODE_NONE
- * @see #SHUFFLE_MODE_ALL
- * @see #SHUFFLE_MODE_GROUP
- */
- public @ShuffleMode int getShuffleMode() {
- return mProvider.getShuffleMode_impl();
- }
-
- /**
- * Sets the shuffle mode
- *
- * @param shuffleMode The shuffle mode
- * @see #SHUFFLE_MODE_NONE
- * @see #SHUFFLE_MODE_ALL
- * @see #SHUFFLE_MODE_GROUP
- */
- public void setShuffleMode(@ShuffleMode int shuffleMode) {
- mProvider.setShuffleMode_impl(shuffleMode);
- }
-
- /**
- * Called by {@link MediaSession2} when it wants to translate {@link DataSourceDesc} from the
- * {@link MediaPlayerBase.PlayerEventCallback} to the {@link MediaItem2}. Override this method
- * if you want to create {@link DataSourceDesc}s dynamically, instead of specifying them with
- * {@link #setPlaylist(List, MediaMetadata2)}.
- * <p>
- * Session would throw an exception if this returns {@code null} for {@param dsd} from the
- * {@link MediaPlayerBase.PlayerEventCallback}.
- * <p>
- * Default implementation calls the {@link #getPlaylist()} and searches the {@link MediaItem2}
- * with the {@param dsd}.
- *
- * @param dsd The dsd to query.
- * @return A {@link MediaItem2} object in the playlist that matches given {@code dsd}.
- * @throws IllegalArgumentException if {@code dsd} is null
- */
- public @Nullable MediaItem2 getMediaItem(@NonNull DataSourceDesc dsd) {
- return mProvider.getMediaItem_impl(dsd);
- }
-}
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
deleted file mode 100644
index 9e97125..0000000
--- a/media/java/android/media/MediaSession2.java
+++ /dev/null
@@ -1,1388 +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;
-
-import static android.media.MediaPlayerBase.BUFFERING_STATE_UNKNOWN;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.media.MediaPlayerBase.BuffState;
-import android.media.MediaPlayerBase.PlayerState;
-import android.media.MediaPlaylistAgent.RepeatMode;
-import android.media.MediaPlaylistAgent.ShuffleMode;
-import android.media.update.ApiLoader;
-import android.media.update.MediaSession2Provider;
-import android.media.update.MediaSession2Provider.BuilderBaseProvider;
-import android.media.update.MediaSession2Provider.CommandButtonProvider;
-import android.media.update.MediaSession2Provider.ControllerInfoProvider;
-import android.media.update.ProviderCreator;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IInterface;
-import android.os.ResultReceiver;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * @hide
- * Allows a media app to expose its transport controls and playback information in a process to
- * other processes including the Android framework and other apps. Common use cases are as follows.
- * <ul>
- * <li>Bluetooth/wired headset key events support</li>
- * <li>Android Auto/Wearable support</li>
- * <li>Separating UI process and playback process</li>
- * </ul>
- * <p>
- * A MediaSession2 should be created when an app wants to publish media playback information or
- * handle media keys. In general an app only needs one session for all playback, though multiple
- * sessions can be created to provide finer grain controls of media.
- * <p>
- * A session can be obtained by {@link Builder}. The owner of the session may pass its session token
- * to other processes to allow them to create a {@link MediaController2} to interact with the
- * session.
- * <p>
- * When a session receive transport control commands, the session sends the commands directly to
- * the the underlying media player set by {@link Builder} or
- * {@link #updatePlayer}.
- * <p>
- * When an app is finished performing playback it must call {@link #close()} to clean up the session
- * and notify any controllers.
- * <p>
- * {@link MediaSession2} objects should be used on the thread on the looper.
- */
-public class MediaSession2 implements AutoCloseable {
- private final MediaSession2Provider mProvider;
-
- /**
- * @hide
- */
- @IntDef({ERROR_CODE_UNKNOWN_ERROR, ERROR_CODE_APP_ERROR, ERROR_CODE_NOT_SUPPORTED,
- ERROR_CODE_AUTHENTICATION_EXPIRED, ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED,
- ERROR_CODE_CONCURRENT_STREAM_LIMIT, ERROR_CODE_PARENTAL_CONTROL_RESTRICTED,
- ERROR_CODE_NOT_AVAILABLE_IN_REGION, ERROR_CODE_CONTENT_ALREADY_PLAYING,
- ERROR_CODE_SKIP_LIMIT_REACHED, ERROR_CODE_ACTION_ABORTED, ERROR_CODE_END_OF_QUEUE,
- ERROR_CODE_SETUP_REQUIRED})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ErrorCode {}
-
- /**
- * This is the default error code and indicates that none of the other error codes applies.
- */
- public static final int ERROR_CODE_UNKNOWN_ERROR = 0;
-
- /**
- * Error code when the application state is invalid to fulfill the request.
- */
- public static final int ERROR_CODE_APP_ERROR = 1;
-
- /**
- * Error code when the request is not supported by the application.
- */
- public static final int ERROR_CODE_NOT_SUPPORTED = 2;
-
- /**
- * Error code when the request cannot be performed because authentication has expired.
- */
- public static final int ERROR_CODE_AUTHENTICATION_EXPIRED = 3;
-
- /**
- * Error code when a premium account is required for the request to succeed.
- */
- public static final int ERROR_CODE_PREMIUM_ACCOUNT_REQUIRED = 4;
-
- /**
- * Error code when too many concurrent streams are detected.
- */
- public static final int ERROR_CODE_CONCURRENT_STREAM_LIMIT = 5;
-
- /**
- * Error code when the content is blocked due to parental controls.
- */
- public static final int ERROR_CODE_PARENTAL_CONTROL_RESTRICTED = 6;
-
- /**
- * Error code when the content is blocked due to being regionally unavailable.
- */
- public static final int ERROR_CODE_NOT_AVAILABLE_IN_REGION = 7;
-
- /**
- * Error code when the requested content is already playing.
- */
- public static final int ERROR_CODE_CONTENT_ALREADY_PLAYING = 8;
-
- /**
- * Error code when the application cannot skip any more songs because skip limit is reached.
- */
- public static final int ERROR_CODE_SKIP_LIMIT_REACHED = 9;
-
- /**
- * Error code when the action is interrupted due to some external event.
- */
- public static final int ERROR_CODE_ACTION_ABORTED = 10;
-
- /**
- * Error code when the playback navigation (previous, next) is not possible because the queue
- * was exhausted.
- */
- public static final int ERROR_CODE_END_OF_QUEUE = 11;
-
- /**
- * Error code when the session needs user's manual intervention.
- */
- public static final int ERROR_CODE_SETUP_REQUIRED = 12;
-
- /**
- * Interface definition of a callback to be invoked when a {@link MediaItem2} in the playlist
- * didn't have a {@link DataSourceDesc} but it's needed now for preparing or playing it.
- *
- * #see #setOnDataSourceMissingHelper
- */
- public interface OnDataSourceMissingHelper {
- /**
- * Called when a {@link MediaItem2} in the playlist didn't have a {@link DataSourceDesc}
- * but it's needed now for preparing or playing it. Returned data source descriptor will be
- * sent to the player directly to prepare or play the contents.
- * <p>
- * An exception may be thrown if the returned {@link DataSourceDesc} is duplicated in the
- * playlist, so items cannot be differentiated.
- *
- * @param session the session for this event
- * @param item media item from the controller
- * @return a data source descriptor if the media item. Can be {@code null} if the content
- * isn't available.
- */
- @Nullable DataSourceDesc onDataSourceMissing(@NonNull MediaSession2 session,
- @NonNull MediaItem2 item);
- }
-
- /**
- * Callback to be called for all incoming commands from {@link MediaController2}s.
- * <p>
- * If it's not set, the session will accept all controllers and all incoming commands by
- * default.
- */
- // TODO(jaewan): Move this to updatable for default implementation (b/74091963)
- public static abstract class SessionCallback {
- /**
- * Called when a controller is created for this session. Return allowed commands for
- * controller. By default it allows all connection requests and commands.
- * <p>
- * You can reject the connection by return {@code null}. In that case, controller receives
- * {@link MediaController2.ControllerCallback#onDisconnected(MediaController2)} and cannot
- * be usable.
- *
- * @param session the session for this event
- * @param controller controller information.
- * @return allowed commands. Can be {@code null} to reject connection.
- */
- public @Nullable SessionCommandGroup2 onConnect(@NonNull MediaSession2 session,
- @NonNull ControllerInfo controller) {
- SessionCommandGroup2 commands = new SessionCommandGroup2();
- commands.addAllPredefinedCommands();
- return commands;
- }
-
- /**
- * Called when a controller is disconnected
- *
- * @param session the session for this event
- * @param controller controller information
- */
- public void onDisconnected(@NonNull MediaSession2 session,
- @NonNull ControllerInfo controller) { }
-
- /**
- * Called when a controller sent a command that will be sent directly to the player. Return
- * {@code false} here to reject the request and stop sending command to the player.
- *
- * @param session the session for this event
- * @param controller controller information.
- * @param command a command. This method will be called for every single command.
- * @return {@code true} if you want to accept incoming command. {@code false} otherwise.
- * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PLAY
- * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PAUSE
- * @see SessionCommand2#COMMAND_CODE_PLAYBACK_STOP
- * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM
- * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM
- * @see SessionCommand2#COMMAND_CODE_PLAYBACK_PREPARE
- * @see SessionCommand2#COMMAND_CODE_SESSION_FAST_FORWARD
- * @see SessionCommand2#COMMAND_CODE_SESSION_REWIND
- * @see SessionCommand2#COMMAND_CODE_PLAYBACK_SEEK_TO
- * @see SessionCommand2#COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM
- * @see SessionCommand2#COMMAND_CODE_PLAYLIST_ADD_ITEM
- * @see SessionCommand2#COMMAND_CODE_PLAYLIST_REMOVE_ITEM
- * @see SessionCommand2#COMMAND_CODE_PLAYLIST_GET_LIST
- * @see SessionCommand2#COMMAND_CODE_SET_VOLUME
- */
- public boolean onCommandRequest(@NonNull MediaSession2 session,
- @NonNull ControllerInfo controller, @NonNull SessionCommand2 command) {
- return true;
- }
-
- /**
- * Called when a controller set rating of a media item through
- * {@link MediaController2#setRating(String, Rating2)}.
- * <p>
- * To allow setting user rating for a {@link MediaItem2}, the media item's metadata
- * should have {@link Rating2} with the key {@link MediaMetadata#METADATA_KEY_USER_RATING},
- * in order to provide possible rating style for controller. Controller will follow the
- * rating style.
- *
- * @param session the session for this event
- * @param controller controller information
- * @param mediaId media id from the controller
- * @param rating new rating from the controller
- */
- public void onSetRating(@NonNull MediaSession2 session, @NonNull ControllerInfo controller,
- @NonNull String mediaId, @NonNull Rating2 rating) { }
-
- /**
- * Called when a controller sent a custom command through
- * {@link MediaController2#sendCustomCommand(SessionCommand2, Bundle, ResultReceiver)}.
- *
- * @param session the session for this event
- * @param controller controller information
- * @param customCommand custom command.
- * @param args optional arguments
- * @param cb optional result receiver
- */
- public void onCustomCommand(@NonNull MediaSession2 session,
- @NonNull ControllerInfo controller, @NonNull SessionCommand2 customCommand,
- @Nullable Bundle args, @Nullable ResultReceiver cb) { }
-
- /**
- * Called when a controller requested to play a specific mediaId through
- * {@link MediaController2#playFromMediaId(String, Bundle)}.
- *
- * @param session the session for this event
- * @param controller controller information
- * @param mediaId media id
- * @param extras optional extra bundle
- * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID
- */
- public void onPlayFromMediaId(@NonNull MediaSession2 session,
- @NonNull ControllerInfo controller, @NonNull String mediaId,
- @Nullable Bundle extras) { }
-
- /**
- * Called when a controller requested to begin playback from a search query through
- * {@link MediaController2#playFromSearch(String, Bundle)}
- * <p>
- * An empty query indicates that the app may play any music. The implementation should
- * attempt to make a smart choice about what to play.
- *
- * @param session the session for this event
- * @param controller controller information
- * @param query query string. Can be empty to indicate any suggested media
- * @param extras optional extra bundle
- * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_SEARCH
- */
- public void onPlayFromSearch(@NonNull MediaSession2 session,
- @NonNull ControllerInfo controller, @NonNull String query,
- @Nullable Bundle extras) { }
-
- /**
- * Called when a controller requested to play a specific media item represented by a URI
- * through {@link MediaController2#playFromUri(Uri, Bundle)}
- *
- * @param session the session for this event
- * @param controller controller information
- * @param uri uri
- * @param extras optional extra bundle
- * @see SessionCommand2#COMMAND_CODE_SESSION_PLAY_FROM_URI
- */
- public void onPlayFromUri(@NonNull MediaSession2 session,
- @NonNull ControllerInfo controller, @NonNull Uri uri,
- @Nullable Bundle extras) { }
-
- /**
- * Called when a controller requested to prepare for playing a specific mediaId through
- * {@link MediaController2#prepareFromMediaId(String, Bundle)}.
- * <p>
- * During the preparation, a session should not hold audio focus in order to allow other
- * sessions play seamlessly. The state of playback should be updated to
- * {@link MediaPlayerBase#PLAYER_STATE_PAUSED} after the preparation is done.
- * <p>
- * The playback of the prepared content should start in the later calls of
- * {@link MediaSession2#play()}.
- * <p>
- * Override {@link #onPlayFromMediaId} to handle requests for starting
- * playback without preparation.
- *
- * @param session the session for this event
- * @param controller controller information
- * @param mediaId media id to prepare
- * @param extras optional extra bundle
- * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID
- */
- public void onPrepareFromMediaId(@NonNull MediaSession2 session,
- @NonNull ControllerInfo controller, @NonNull String mediaId,
- @Nullable Bundle extras) { }
-
- /**
- * Called when a controller requested to prepare playback from a search query through
- * {@link MediaController2#prepareFromSearch(String, Bundle)}.
- * <p>
- * An empty query indicates that the app may prepare any music. The implementation should
- * attempt to make a smart choice about what to play.
- * <p>
- * The state of playback should be updated to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}
- * after the preparation is done. The playback of the prepared content should start in the
- * later calls of {@link MediaSession2#play()}.
- * <p>
- * Override {@link #onPlayFromSearch} to handle requests for starting playback without
- * preparation.
- *
- * @param session the session for this event
- * @param controller controller information
- * @param query query string. Can be empty to indicate any suggested media
- * @param extras optional extra bundle
- * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH
- */
- public void onPrepareFromSearch(@NonNull MediaSession2 session,
- @NonNull ControllerInfo controller, @NonNull String query,
- @Nullable Bundle extras) { }
-
- /**
- * Called when a controller requested to prepare a specific media item represented by a URI
- * through {@link MediaController2#prepareFromUri(Uri, Bundle)}.
- * <p>
- * During the preparation, a session should not hold audio focus in order to allow
- * other sessions play seamlessly. The state of playback should be updated to
- * {@link MediaPlayerBase#PLAYER_STATE_PAUSED} after the preparation is done.
- * <p>
- * The playback of the prepared content should start in the later calls of
- * {@link MediaSession2#play()}.
- * <p>
- * Override {@link #onPlayFromUri} to handle requests for starting playback without
- * preparation.
- *
- * @param session the session for this event
- * @param controller controller information
- * @param uri uri
- * @param extras optional extra bundle
- * @see SessionCommand2#COMMAND_CODE_SESSION_PREPARE_FROM_URI
- */
- public void onPrepareFromUri(@NonNull MediaSession2 session,
- @NonNull ControllerInfo controller, @NonNull Uri uri, @Nullable Bundle extras) { }
-
- /**
- * Called when a controller called {@link MediaController2#fastForward()}
- *
- * @param session the session for this event
- */
- public void onFastForward(@NonNull MediaSession2 session) { }
-
- /**
- * Called when a controller called {@link MediaController2#rewind()}
- *
- * @param session the session for this event
- */
- public void onRewind(@NonNull MediaSession2 session) { }
-
- /**
- * Called when the player's current playing item is changed
- * <p>
- * When it's called, you should invalidate previous playback information and wait for later
- * callbacks.
- *
- * @param session the controller for this event
- * @param player the player for this event
- * @param item new item
- */
- // TODO(jaewan): Use this (b/74316764)
- public void onCurrentMediaItemChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlayerBase player, @NonNull MediaItem2 item) { }
-
- /**
- * Called when the player is <i>prepared</i>, i.e. it is ready to play the content
- * referenced by the given data source.
- * @param session the session for this event
- * @param player the player for this event
- * @param item the media item for which buffering is happening
- */
- public void onMediaPrepared(@NonNull MediaSession2 session, @NonNull MediaPlayerBase player,
- @NonNull MediaItem2 item) { }
-
- /**
- * Called to indicate that the state of the player has changed.
- * See {@link MediaPlayerBase#getPlayerState()} for polling the player state.
- * @param session the session for this event
- * @param player the player for this event
- * @param state the new state of the player.
- */
- public void onPlayerStateChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlayerBase player, @PlayerState int state) { }
-
- /**
- * Called to report buffering events for a data source.
- *
- * @param session the session for this event
- * @param player the player for this event
- * @param item the media item for which buffering is happening.
- * @param state the new buffering state.
- */
- public void onBufferingStateChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlayerBase player, @NonNull MediaItem2 item, @BuffState int state) { }
-
- /**
- * Called to indicate that the playback speed has changed.
- * @param session the session for this event
- * @param player the player for this event
- * @param speed the new playback speed.
- */
- public void onPlaybackSpeedChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlayerBase player, float speed) { }
-
- /**
- * Called to indicate that {@link #seekTo(long)} is completed.
- *
- * @param session the session for this event.
- * @param mpb the player that has completed seeking.
- * @param position the previous seeking request.
- * @see #seekTo(long)
- */
- public void onSeekCompleted(@NonNull MediaSession2 session, @NonNull MediaPlayerBase mpb,
- long position) { }
-
- /**
- * Called when a playlist is changed from the {@link MediaPlaylistAgent}.
- * <p>
- * This is called when the underlying agent has called
- * {@link MediaPlaylistAgent.PlaylistEventCallback#onPlaylistChanged(MediaPlaylistAgent,
- * List, MediaMetadata2)}.
- *
- * @param session the session for this event
- * @param playlistAgent playlist agent for this event
- * @param list new playlist
- * @param metadata new metadata
- */
- public void onPlaylistChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlaylistAgent playlistAgent, @NonNull List<MediaItem2> list,
- @Nullable MediaMetadata2 metadata) { }
-
- /**
- * Called when a playlist metadata is changed.
- *
- * @param session the session for this event
- * @param playlistAgent playlist agent for this event
- * @param metadata new metadata
- */
- public void onPlaylistMetadataChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlaylistAgent playlistAgent, @Nullable MediaMetadata2 metadata) { }
-
- /**
- * Called when the shuffle mode is changed.
- *
- * @param session the session for this event
- * @param playlistAgent playlist agent for this event
- * @param shuffleMode repeat mode
- * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE
- * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL
- * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP
- */
- public void onShuffleModeChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlaylistAgent playlistAgent,
- @MediaPlaylistAgent.ShuffleMode int shuffleMode) { }
-
- /**
- * Called when the repeat mode is changed.
- *
- * @param session the session for this event
- * @param playlistAgent playlist agent for this event
- * @param repeatMode repeat mode
- * @see MediaPlaylistAgent#REPEAT_MODE_NONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ALL
- * @see MediaPlaylistAgent#REPEAT_MODE_GROUP
- */
- public void onRepeatModeChanged(@NonNull MediaSession2 session,
- @NonNull MediaPlaylistAgent playlistAgent,
- @MediaPlaylistAgent.RepeatMode int repeatMode) { }
- }
-
- /**
- * Base builder class for MediaSession2 and its subclass. Any change in this class should be
- * also applied to the subclasses {@link MediaSession2.Builder} and
- * {@link MediaLibraryService2.MediaLibrarySession.Builder}.
- * <p>
- * APIs here should be package private, but should have documentations for developers.
- * Otherwise, javadoc will generate documentation with the generic types such as follows.
- * <pre>U extends BuilderBase<T, U, C> setSessionCallback(Executor executor, C callback)</pre>
- * <p>
- * This class is hidden to prevent from generating test stub, which fails with
- * 'unexpected bound' because it tries to auto generate stub class as follows.
- * <pre>abstract static class BuilderBase<
- * T extends android.media.MediaSession2,
- * U extends android.media.MediaSession2.BuilderBase<
- * T, U, C extends android.media.MediaSession2.SessionCallback>, C></pre>
- * @hide
- */
- static abstract class BuilderBase
- <T extends MediaSession2, U extends BuilderBase<T, U, C>, C extends SessionCallback> {
- private final BuilderBaseProvider<T, C> mProvider;
-
- BuilderBase(ProviderCreator<BuilderBase<T, U, C>, BuilderBaseProvider<T, C>> creator) {
- mProvider = creator.createProvider(this);
- }
-
- /**
- * Sets the underlying {@link MediaPlayerBase} for this session to dispatch incoming event
- * to.
- *
- * @param player a {@link MediaPlayerBase} that handles actual media playback in your app.
- */
- @NonNull U setPlayer(@NonNull MediaPlayerBase player) {
- mProvider.setPlayer_impl(player);
- return (U) this;
- }
-
- /**
- * Sets the {@link MediaPlaylistAgent} for this session to manages playlist of the
- * underlying {@link MediaPlayerBase}. The playlist agent should manage
- * {@link MediaPlayerBase} for calling {@link MediaPlayerBase#setNextDataSources(List)}.
- * <p>
- * If the {@link MediaPlaylistAgent} isn't set, session will create the default playlist
- * agent.
- *
- * @param playlistAgent a {@link MediaPlaylistAgent} that manages playlist of the
- * {@code player}
- */
- U setPlaylistAgent(@NonNull MediaPlaylistAgent playlistAgent) {
- mProvider.setPlaylistAgent_impl(playlistAgent);
- return (U) this;
- }
-
- /**
- * Sets the {@link VolumeProvider2} for this session to handle volume events. If not set,
- * system will adjust the appropriate stream volume for this session's player.
- *
- * @param volumeProvider The provider that will receive volume button events.
- */
- @NonNull U setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) {
- mProvider.setVolumeProvider_impl(volumeProvider);
- return (U) this;
- }
-
- /**
- * Set an intent for launching UI for this Session. This can be used as a
- * quick link to an ongoing media screen. The intent should be for an
- * activity that may be started using {@link Context#startActivity(Intent)}.
- *
- * @param pi The intent to launch to show UI for this session.
- */
- @NonNull U setSessionActivity(@Nullable PendingIntent pi) {
- mProvider.setSessionActivity_impl(pi);
- return (U) this;
- }
-
- /**
- * Set ID of the session. If it's not set, an empty string with used to create a session.
- * <p>
- * Use this if and only if your app supports multiple playback at the same time and also
- * wants to provide external apps to have finer controls of them.
- *
- * @param id id of the session. Must be unique per package.
- * @throws IllegalArgumentException if id is {@code null}
- * @return
- */
- @NonNull U setId(@NonNull String id) {
- mProvider.setId_impl(id);
- return (U) this;
- }
-
- /**
- * Set callback for the session.
- *
- * @param executor callback executor
- * @param callback session callback.
- * @return
- */
- @NonNull U setSessionCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull C callback) {
- mProvider.setSessionCallback_impl(executor, callback);
- return (U) this;
- }
-
- /**
- * Build {@link MediaSession2}.
- *
- * @return a new session
- * @throws IllegalStateException if the session with the same id is already exists for the
- * package.
- */
- @NonNull T build() {
- return mProvider.build_impl();
- }
- }
-
- /**
- * Builder for {@link MediaSession2}.
- * <p>
- * Any incoming event from the {@link MediaController2} will be handled on the thread
- * that created session with the {@link Builder#build()}.
- */
- // Override all methods just to show them with the type instead of generics in Javadoc.
- // This workarounds javadoc issue described in the MediaSession2.BuilderBase.
- public static final class Builder extends BuilderBase<MediaSession2, Builder, SessionCallback> {
- public Builder(Context context) {
- super((instance) -> ApiLoader.getProvider().createMediaSession2Builder(
- context, (Builder) instance));
- }
-
- @Override
- public @NonNull Builder setPlayer(@NonNull MediaPlayerBase player) {
- return super.setPlayer(player);
- }
-
- @Override
- public Builder setPlaylistAgent(@NonNull MediaPlaylistAgent playlistAgent) {
- return super.setPlaylistAgent(playlistAgent);
- }
-
- @Override
- public @NonNull Builder setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) {
- return super.setVolumeProvider(volumeProvider);
- }
-
- @Override
- public @NonNull Builder setSessionActivity(@Nullable PendingIntent pi) {
- return super.setSessionActivity(pi);
- }
-
- @Override
- public @NonNull Builder setId(@NonNull String id) {
- return super.setId(id);
- }
-
- @Override
- public @NonNull Builder setSessionCallback(@NonNull Executor executor,
- @Nullable SessionCallback callback) {
- return super.setSessionCallback(executor, callback);
- }
-
- @Override
- public @NonNull MediaSession2 build() {
- return super.build();
- }
- }
-
- /**
- * Information of a controller.
- */
- public static final class ControllerInfo {
- private final ControllerInfoProvider mProvider;
-
- /**
- * @hide
- */
- public ControllerInfo(@NonNull Context context, int uid, int pid,
- @NonNull String packageName, @NonNull IInterface callback) {
- mProvider = ApiLoader.getProvider().createMediaSession2ControllerInfo(
- context, this, uid, pid, packageName, callback);
- }
-
- /**
- * @return package name of the controller
- */
- public @NonNull String getPackageName() {
- return mProvider.getPackageName_impl();
- }
-
- /**
- * @return uid of the controller
- */
- public int getUid() {
- return mProvider.getUid_impl();
- }
-
- /**
- * Return if the controller has granted {@code android.permission.MEDIA_CONTENT_CONTROL} or
- * has a enabled notification listener so can be trusted to accept connection and incoming
- * command request.
- *
- * @return {@code true} if the controller is trusted.
- */
- public boolean isTrusted() {
- return mProvider.isTrusted_impl();
- }
-
- /**
- * @hide
- */
- public @NonNull ControllerInfoProvider getProvider() {
- return mProvider;
- }
-
- @Override
- public int hashCode() {
- return mProvider.hashCode_impl();
- }
-
- @Override
- public boolean equals(Object obj) {
- return mProvider.equals_impl(obj);
- }
-
- @Override
- public String toString() {
- return mProvider.toString_impl();
- }
- }
-
- /**
- * Button for a {@link SessionCommand2} that will be shown by the controller.
- * <p>
- * It's up to the controller's decision to respect or ignore this customization request.
- */
- public static final class CommandButton {
- private final CommandButtonProvider mProvider;
-
- /**
- * @hide
- */
- public CommandButton(CommandButtonProvider provider) {
- mProvider = provider;
- }
-
- /**
- * Get command associated with this button. Can be {@code null} if the button isn't enabled
- * and only providing placeholder.
- *
- * @return command or {@code null}
- */
- public @Nullable
- SessionCommand2 getCommand() {
- return mProvider.getCommand_impl();
- }
-
- /**
- * Resource id of the button in this package. Can be {@code 0} if the command is predefined
- * and custom icon isn't needed.
- *
- * @return resource id of the icon. Can be {@code 0}.
- */
- public int getIconResId() {
- return mProvider.getIconResId_impl();
- }
-
- /**
- * Display name of the button. Can be {@code null} or empty if the command is predefined
- * and custom name isn't needed.
- *
- * @return custom display name. Can be {@code null} or empty.
- */
- public @Nullable String getDisplayName() {
- return mProvider.getDisplayName_impl();
- }
-
- /**
- * Extra information of the button. It's private information between session and controller.
- *
- * @return
- */
- public @Nullable Bundle getExtras() {
- return mProvider.getExtras_impl();
- }
-
- /**
- * Return whether it's enabled
- *
- * @return {@code true} if enabled. {@code false} otherwise.
- */
- public boolean isEnabled() {
- return mProvider.isEnabled_impl();
- }
-
- /**
- * @hide
- */
- public @NonNull CommandButtonProvider getProvider() {
- return mProvider;
- }
-
- /**
- * Builder for {@link CommandButton}.
- */
- public static final class Builder {
- private final CommandButtonProvider.BuilderProvider mProvider;
-
- public Builder() {
- mProvider = ApiLoader.getProvider().createMediaSession2CommandButtonBuilder(this);
- }
-
- public @NonNull Builder setCommand(@Nullable SessionCommand2 command) {
- return mProvider.setCommand_impl(command);
- }
-
- public @NonNull Builder setIconResId(int resId) {
- return mProvider.setIconResId_impl(resId);
- }
-
- public @NonNull Builder setDisplayName(@Nullable String displayName) {
- return mProvider.setDisplayName_impl(displayName);
- }
-
- public @NonNull Builder setEnabled(boolean enabled) {
- return mProvider.setEnabled_impl(enabled);
- }
-
- public @NonNull Builder setExtras(@Nullable Bundle extras) {
- return mProvider.setExtras_impl(extras);
- }
-
- public @NonNull CommandButton build() {
- return mProvider.build_impl();
- }
- }
- }
-
- /**
- * Constructor is hidden and apps can only instantiate indirectly through {@link Builder}.
- * <p>
- * This intended behavior and here's the reasons.
- * 1. Prevent multiple sessions with the same tag in a media app.
- * Whenever it happens only one session was properly setup and others were all dummies.
- * Android framework couldn't find the right session to dispatch media key event.
- * 2. Simplify session's lifecycle.
- * {@link android.media.session.MediaSession} is available after all of
- * {@link android.media.session.MediaSession#setFlags(int)},
- * {@link android.media.session.MediaSession#setCallback(
- * android.media.session.MediaSession.Callback)},
- * and {@link android.media.session.MediaSession#setActive(boolean)}.
- * It was common for an app to omit one, so framework had to add heuristics to figure out
- * which should be the highest priority for handling media key event.
- * @hide
- */
- public MediaSession2(MediaSession2Provider provider) {
- super();
- mProvider = provider;
- }
-
- /**
- * @hide
- */
- public @NonNull MediaSession2Provider getProvider() {
- return mProvider;
- }
-
- /**
- * Sets the underlying {@link MediaPlayerBase} and {@link MediaPlaylistAgent} for this session
- * to dispatch incoming event to.
- * <p>
- * When a {@link MediaPlaylistAgent} is specified here, the playlist agent should manage
- * {@link MediaPlayerBase} for calling {@link MediaPlayerBase#setNextDataSources(List)}.
- * <p>
- * If the {@link MediaPlaylistAgent} isn't set, session will recreate the default playlist
- * agent.
- *
- * @param player a {@link MediaPlayerBase} that handles actual media playback in your app
- * @param playlistAgent a {@link MediaPlaylistAgent} that manages playlist of the {@code player}
- * @param volumeProvider a {@link VolumeProvider2}. If {@code null}, system will adjust the
- * appropriate stream volume for this session's player.
- */
- public void updatePlayer(@NonNull MediaPlayerBase player,
- @Nullable MediaPlaylistAgent playlistAgent, @Nullable VolumeProvider2 volumeProvider) {
- mProvider.updatePlayer_impl(player, playlistAgent, volumeProvider);
- }
-
- @Override
- public void close() {
- mProvider.close_impl();
- }
-
- /**
- * @return player
- */
- public @NonNull MediaPlayerBase getPlayer() {
- return mProvider.getPlayer_impl();
- }
-
- /**
- * @return playlist agent
- */
- public @NonNull MediaPlaylistAgent getPlaylistAgent() {
- return mProvider.getPlaylistAgent_impl();
- }
-
- /**
- * @return volume provider
- */
- public @Nullable VolumeProvider2 getVolumeProvider() {
- return mProvider.getVolumeProvider_impl();
- }
-
- /**
- * Returns the {@link SessionToken2} for creating {@link MediaController2}.
- */
- public @NonNull
- SessionToken2 getToken() {
- return mProvider.getToken_impl();
- }
-
- public @NonNull List<ControllerInfo> getConnectedControllers() {
- return mProvider.getConnectedControllers_impl();
- }
-
- /**
- * Set the {@link AudioFocusRequest} to obtain the audio focus
- *
- * @param afr the full request parameters
- */
- public void setAudioFocusRequest(@Nullable AudioFocusRequest afr) {
- // TODO(jaewan): implement this (b/72529899)
- // mProvider.setAudioFocusRequest_impl(focusGain);
- }
-
- /**
- * Sets ordered list of {@link CommandButton} for controllers to build UI with it.
- * <p>
- * It's up to controller's decision how to represent the layout in its own UI.
- * Here's the same way
- * (layout[i] means a CommandButton at index i in the given list)
- * For 5 icons row
- * layout[3] layout[1] layout[0] layout[2] layout[4]
- * For 3 icons row
- * layout[1] layout[0] layout[2]
- * For 5 icons row with overflow icon (can show +5 extra buttons with overflow button)
- * expanded row: layout[5] layout[6] layout[7] layout[8] layout[9]
- * main row: layout[3] layout[1] layout[0] layout[2] layout[4]
- * <p>
- * This API can be called in the {@link SessionCallback#onConnect(
- * MediaSession2, ControllerInfo)}.
- *
- * @param controller controller to specify layout.
- * @param layout ordered list of layout.
- */
- public void setCustomLayout(@NonNull ControllerInfo controller,
- @NonNull List<CommandButton> layout) {
- mProvider.setCustomLayout_impl(controller, layout);
- }
-
- /**
- * Set the new allowed command group for the controller
- *
- * @param controller controller to change allowed commands
- * @param commands new allowed commands
- */
- public void setAllowedCommands(@NonNull ControllerInfo controller,
- @NonNull SessionCommandGroup2 commands) {
- mProvider.setAllowedCommands_impl(controller, commands);
- }
-
- /**
- * Send custom command to all connected controllers.
- *
- * @param command a command
- * @param args optional argument
- */
- public void sendCustomCommand(@NonNull SessionCommand2 command, @Nullable Bundle args) {
- mProvider.sendCustomCommand_impl(command, args);
- }
-
- /**
- * Send custom command to a specific controller.
- *
- * @param command a command
- * @param args optional argument
- * @param receiver result receiver for the session
- */
- public void sendCustomCommand(@NonNull ControllerInfo controller,
- @NonNull SessionCommand2 command, @Nullable Bundle args,
- @Nullable ResultReceiver receiver) {
- // Equivalent to the MediaController.sendCustomCommand(Action action, ResultReceiver r);
- mProvider.sendCustomCommand_impl(controller, command, args, receiver);
- }
-
- /**
- * Play playback
- * <p>
- * This calls {@link MediaPlayerBase#play()}.
- */
- public void play() {
- mProvider.play_impl();
- }
-
- /**
- * Pause playback.
- * <p>
- * This calls {@link MediaPlayerBase#pause()}.
- */
- public void pause() {
- mProvider.pause_impl();
- }
-
- /**
- * Stop playback, and reset the player to the initial state.
- * <p>
- * This calls {@link MediaPlayerBase#reset()}.
- */
- public void stop() {
- mProvider.stop_impl();
- }
-
- /**
- * Request that the player prepare its playback. In other words, other sessions can continue
- * to play during the preparation of this session. This method can be used to speed up the
- * start of the playback. Once the preparation is done, the session will change its playback
- * state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards, {@link #play} can be called
- * to start playback.
- * <p>
- * This calls {@link MediaPlayerBase#reset()}.
- */
- public void prepare() {
- mProvider.prepare_impl();
- }
-
- /**
- * Move to a new location in the media stream.
- *
- * @param pos Position to move to, in milliseconds.
- */
- public void seekTo(long pos) {
- mProvider.seekTo_impl(pos);
- }
-
- /**
- * @hide
- */
- public void skipForward() {
- // To match with KEYCODE_MEDIA_SKIP_FORWARD
- }
-
- /**
- * @hide
- */
- public void skipBackward() {
- // To match with KEYCODE_MEDIA_SKIP_BACKWARD
- }
-
- /**
- * Notify errors to the connected controllers
- *
- * @param errorCode error code
- * @param extras extras
- */
- public void notifyError(@ErrorCode int errorCode, @Nullable Bundle extras) {
- mProvider.notifyError_impl(errorCode, extras);
- }
-
- /**
- * Gets the current player state.
- *
- * @return the current player state
- */
- public @PlayerState int getPlayerState() {
- return mProvider.getPlayerState_impl();
- }
-
- /**
- * Gets the current position.
- *
- * @return the current playback position in ms, or {@link MediaPlayerBase#UNKNOWN_TIME} if
- * unknown.
- */
- public long getCurrentPosition() {
- return mProvider.getCurrentPosition_impl();
- }
-
- /**
- * Gets the buffered position, or {@link MediaPlayerBase#UNKNOWN_TIME} if unknown.
- *
- * @return the buffered position in ms, or {@link MediaPlayerBase#UNKNOWN_TIME}.
- */
- public long getBufferedPosition() {
- return mProvider.getBufferedPosition_impl();
- }
-
- /**
- * Gets the current buffering state of the player.
- * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already
- * buffered.
- *
- * @return the buffering state.
- */
- public @BuffState int getBufferingState() {
- // TODO(jaewan): Implement this
- return BUFFERING_STATE_UNKNOWN;
- }
-
- /**
- * Get the playback speed.
- *
- * @return speed
- */
- public float getPlaybackSpeed() {
- // TODO(jaewan): implement this (b/74093080)
- return -1;
- }
-
- /**
- * Set the playback speed.
- */
- public void setPlaybackSpeed(float speed) {
- // TODO(jaewan): implement this (b/74093080)
- }
-
- /**
- * Sets the data source missing helper. Helper will be used to provide default implementation of
- * {@link MediaPlaylistAgent} when it isn't set by developer.
- * <p>
- * Default implementation of the {@link MediaPlaylistAgent} will call helper when a
- * {@link MediaItem2} in the playlist doesn't have a {@link DataSourceDesc}. This may happen
- * when
- * <ul>
- * <li>{@link MediaItem2} specified by {@link #setPlaylist(List, MediaMetadata2)} doesn't
- * have {@link DataSourceDesc}</li>
- * <li>{@link MediaController2#addPlaylistItem(int, MediaItem2)} is called and accepted
- * by {@link SessionCallback#onCommandRequest(
- * MediaSession2, ControllerInfo, SessionCommand2)}.
- * In that case, an item would be added automatically without the data source.</li>
- * </ul>
- * <p>
- * If it's not set, playback wouldn't happen for the item without data source descriptor.
- * <p>
- * The helper will be run on the executor that was specified by
- * {@link Builder#setSessionCallback(Executor, SessionCallback)}.
- *
- * @param helper a data source missing helper.
- * @throws IllegalStateException when the helper is set when the playlist agent is set
- * @see #setPlaylist(List, MediaMetadata2)
- * @see SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)
- * @see SessionCommand2#COMMAND_CODE_PLAYLIST_ADD_ITEM
- * @see SessionCommand2#COMMAND_CODE_PLAYLIST_REPLACE_ITEM
- */
- public void setOnDataSourceMissingHelper(@NonNull OnDataSourceMissingHelper helper) {
- mProvider.setOnDataSourceMissingHelper_impl(helper);
- }
-
- /**
- * Clears the data source missing helper.
- *
- * @see #setOnDataSourceMissingHelper(OnDataSourceMissingHelper)
- */
- public void clearOnDataSourceMissingHelper() {
- mProvider.clearOnDataSourceMissingHelper_impl();
- }
-
- /**
- * Returns the playlist from the {@link MediaPlaylistAgent}.
- * <p>
- * This list may differ with the list that was specified with
- * {@link #setPlaylist(List, MediaMetadata2)} depending on the {@link MediaPlaylistAgent}
- * implementation. Use media items returned here for other playlist agent APIs such as
- * {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)}.
- *
- * @return playlist
- * @see MediaPlaylistAgent#getPlaylist()
- * @see SessionCallback#onPlaylistChanged(
- * MediaSession2, MediaPlaylistAgent, List, MediaMetadata2)
- */
- public List<MediaItem2> getPlaylist() {
- return mProvider.getPlaylist_impl();
- }
-
- /**
- * Sets a list of {@link MediaItem2} to the {@link MediaPlaylistAgent}. Ensure uniqueness of
- * each {@link MediaItem2} in the playlist so the session can uniquely identity individual
- * items.
- * <p>
- * This may be an asynchronous call, and {@link MediaPlaylistAgent} may keep the copy of the
- * list. Wait for {@link SessionCallback#onPlaylistChanged(MediaSession2, MediaPlaylistAgent,
- * List, MediaMetadata2)} to know the operation finishes.
- * <p>
- * You may specify a {@link MediaItem2} without {@link DataSourceDesc}. In that case,
- * {@link MediaPlaylistAgent} has responsibility to dynamically query {@link DataSourceDesc}
- * when such media item is ready for preparation or play. Default implementation needs
- * {@link OnDataSourceMissingHelper} for such case.
- *
- * @param list A list of {@link MediaItem2} objects to set as a play list.
- * @throws IllegalArgumentException if given list is {@code null}, or has duplicated media
- * items.
- * @see MediaPlaylistAgent#setPlaylist(List, MediaMetadata2)
- * @see SessionCallback#onPlaylistChanged(
- * MediaSession2, MediaPlaylistAgent, List, MediaMetadata2)
- * @see #setOnDataSourceMissingHelper
- */
- public void setPlaylist(@NonNull List<MediaItem2> list, @Nullable MediaMetadata2 metadata) {
- mProvider.setPlaylist_impl(list, metadata);
- }
-
- /**
- * Skips to the item in the playlist.
- * <p>
- * This calls {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)} and the behavior depends
- * on the playlist agent implementation, especially with the shuffle/repeat mode.
- *
- * @param item The item in the playlist you want to play
- * @see #getShuffleMode()
- * @see #getRepeatMode()
- */
- public void skipToPlaylistItem(@NonNull MediaItem2 item) {
- mProvider.skipToPlaylistItem_impl(item);
- }
-
- /**
- * Skips to the previous item.
- * <p>
- * This calls {@link MediaPlaylistAgent#skipToPreviousItem()} and the behavior depends on the
- * playlist agent implementation, especially with the shuffle/repeat mode.
- *
- * @see #getShuffleMode()
- * @see #getRepeatMode()
- **/
- public void skipToPreviousItem() {
- mProvider.skipToPreviousItem_impl();
- }
-
- /**
- * Skips to the next item.
- * <p>
- * This calls {@link MediaPlaylistAgent#skipToNextItem()} and the behavior depends on the
- * playlist agent implementation, especially with the shuffle/repeat mode.
- *
- * @see #getShuffleMode()
- * @see #getRepeatMode()
- */
- public void skipToNextItem() {
- mProvider.skipToNextItem_impl();
- }
-
- /**
- * Gets the playlist metadata from the {@link MediaPlaylistAgent}.
- *
- * @return the playlist metadata
- */
- public MediaMetadata2 getPlaylistMetadata() {
- return mProvider.getPlaylistMetadata_impl();
- }
-
- /**
- * Adds the media item to the playlist at position index. Index equals or greater than
- * the current playlist size will add the item at the end of the playlist.
- * <p>
- * This will not change the currently playing media item.
- * If index is less than or equal to the current index of the play list,
- * the current index of the play list will be incremented correspondingly.
- *
- * @param index the index you want to add
- * @param item the media item you want to add
- */
- public void addPlaylistItem(int index, @NonNull MediaItem2 item) {
- mProvider.addPlaylistItem_impl(index, item);
- }
-
- /**
- * Removes the media item in the playlist.
- * <p>
- * If the item is the currently playing item of the playlist, current playback
- * will be stopped and playback moves to next source in the list.
- *
- * @param item the media item you want to add
- */
- public void removePlaylistItem(@NonNull MediaItem2 item) {
- mProvider.removePlaylistItem_impl(item);
- }
-
- /**
- * Replaces the media item at index in the playlist. This can be also used to update metadata of
- * an item.
- *
- * @param index the index of the item to replace
- * @param item the new item
- */
- public void replacePlaylistItem(int index, @NonNull MediaItem2 item) {
- mProvider.replacePlaylistItem_impl(index, item);
- }
-
- /**
- * Return currently playing media item.
- *
- * @return currently playing media item
- */
- public MediaItem2 getCurrentMediaItem() {
- // TODO(jaewan): Rename provider, and implement (b/74316764)
- return mProvider.getCurrentPlaylistItem_impl();
- }
-
- /**
- * Updates the playlist metadata to the {@link MediaPlaylistAgent}.
- *
- * @param metadata metadata of the playlist
- */
- public void updatePlaylistMetadata(@Nullable MediaMetadata2 metadata) {
- mProvider.updatePlaylistMetadata_impl(metadata);
- }
-
- /**
- * Gets the repeat mode from the {@link MediaPlaylistAgent}.
- *
- * @return repeat mode
- * @see MediaPlaylistAgent#REPEAT_MODE_NONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ALL
- * @see MediaPlaylistAgent#REPEAT_MODE_GROUP
- */
- public @RepeatMode int getRepeatMode() {
- return mProvider.getRepeatMode_impl();
- }
-
- /**
- * Sets the repeat mode to the {@link MediaPlaylistAgent}.
- *
- * @param repeatMode repeat mode
- * @see MediaPlaylistAgent#REPEAT_MODE_NONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ONE
- * @see MediaPlaylistAgent#REPEAT_MODE_ALL
- * @see MediaPlaylistAgent#REPEAT_MODE_GROUP
- */
- public void setRepeatMode(@RepeatMode int repeatMode) {
- mProvider.setRepeatMode_impl(repeatMode);
- }
-
- /**
- * Gets the shuffle mode from the {@link MediaPlaylistAgent}.
- *
- * @return The shuffle mode
- * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE
- * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL
- * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP
- */
- public @ShuffleMode int getShuffleMode() {
- return mProvider.getShuffleMode_impl();
- }
-
- /**
- * Sets the shuffle mode to the {@link MediaPlaylistAgent}.
- *
- * @param shuffleMode The shuffle mode
- * @see MediaPlaylistAgent#SHUFFLE_MODE_NONE
- * @see MediaPlaylistAgent#SHUFFLE_MODE_ALL
- * @see MediaPlaylistAgent#SHUFFLE_MODE_GROUP
- */
- public void setShuffleMode(@ShuffleMode int shuffleMode) {
- mProvider.setShuffleMode_impl(shuffleMode);
- }
-}
diff --git a/media/java/android/media/Rating2.java b/media/java/android/media/Rating2.java
deleted file mode 100644
index 9213190..0000000
--- a/media/java/android/media/Rating2.java
+++ /dev/null
@@ -1,260 +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;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.IntDef;
-import android.media.update.ApiLoader;
-import android.media.update.Rating2Provider;
-import android.os.Bundle;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * @hide
- * A class to encapsulate rating information used as content metadata.
- * A rating is defined by its rating style (see {@link #RATING_HEART},
- * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
- * {@link #RATING_5_STARS} or {@link #RATING_PERCENTAGE}) and the actual rating value (which may
- * be defined as "unrated"), both of which are defined when the rating instance is constructed
- * through one of the factory methods.
- */
-// New version of Rating with following change
-// - Don't implement Parcelable for updatable support.
-public final class Rating2 {
- /**
- * @hide
- */
- @IntDef({RATING_NONE, RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS,
- RATING_5_STARS, RATING_PERCENTAGE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface Style {}
-
- /**
- * @hide
- */
- @IntDef({RATING_3_STARS, RATING_4_STARS, RATING_5_STARS})
- @Retention(RetentionPolicy.SOURCE)
- public @interface StarStyle {}
-
- /**
- * Indicates a rating style is not supported. A Rating2 will never have this
- * type, but can be used by other classes to indicate they do not support
- * Rating2.
- */
- public final static int RATING_NONE = 0;
-
- /**
- * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
- * indicate the content referred to is a favorite (or not).
- */
- public final static int RATING_HEART = 1;
-
- /**
- * A rating style for "thumb up" vs "thumb down".
- */
- public final static int RATING_THUMB_UP_DOWN = 2;
-
- /**
- * A rating style with 0 to 3 stars.
- */
- public final static int RATING_3_STARS = 3;
-
- /**
- * A rating style with 0 to 4 stars.
- */
- public final static int RATING_4_STARS = 4;
-
- /**
- * A rating style with 0 to 5 stars.
- */
- public final static int RATING_5_STARS = 5;
-
- /**
- * A rating style expressed as a percentage.
- */
- public final static int RATING_PERCENTAGE = 6;
-
- private final Rating2Provider mProvider;
-
- /**
- * @hide
- */
- public Rating2(@NonNull Rating2Provider provider) {
- mProvider = provider;
- }
-
- @Override
- public String toString() {
- return mProvider.toString_impl();
- }
-
- /**
- * @hide
- */
- public Rating2Provider getProvider() {
- return mProvider;
- }
-
- @Override
- public boolean equals(Object obj) {
- return mProvider.equals_impl(obj);
- }
-
- @Override
- public int hashCode() {
- return mProvider.hashCode_impl();
- }
-
- /**
- * Create an instance from bundle object, previoulsy created by {@link #toBundle()}
- *
- * @param bundle bundle
- * @return new Rating2 instance or {@code null} for error
- */
- public static Rating2 fromBundle(@Nullable Bundle bundle) {
- return ApiLoader.getProvider().fromBundle_Rating2(bundle);
- }
-
- /**
- * Return bundle for this object to share across the process.
- * @return bundle of this object
- */
- public Bundle toBundle() {
- return mProvider.toBundle_impl();
- }
-
- /**
- * Return a Rating2 instance with no rating.
- * Create and return a new Rating2 instance with no rating known for the given
- * rating style.
- * @param ratingStyle one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
- * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
- * or {@link #RATING_PERCENTAGE}.
- * @return null if an invalid rating style is passed, a new Rating2 instance otherwise.
- */
- public static @Nullable Rating2 newUnratedRating(@Style int ratingStyle) {
- return ApiLoader.getProvider().newUnratedRating_Rating2(ratingStyle);
- }
-
- /**
- * Return a Rating2 instance with a heart-based rating.
- * Create and return a new Rating2 instance with a rating style of {@link #RATING_HEART},
- * and a heart-based rating.
- * @param hasHeart true for a "heart selected" rating, false for "heart unselected".
- * @return a new Rating2 instance.
- */
- public static @Nullable Rating2 newHeartRating(boolean hasHeart) {
- return ApiLoader.getProvider().newHeartRating_Rating2(hasHeart);
- }
-
- /**
- * Return a Rating2 instance with a thumb-based rating.
- * Create and return a new Rating2 instance with a {@link #RATING_THUMB_UP_DOWN}
- * rating style, and a "thumb up" or "thumb down" rating.
- * @param thumbIsUp true for a "thumb up" rating, false for "thumb down".
- * @return a new Rating2 instance.
- */
- public static @Nullable Rating2 newThumbRating(boolean thumbIsUp) {
- return ApiLoader.getProvider().newThumbRating_Rating2(thumbIsUp);
- }
-
- /**
- * Return a Rating2 instance with a star-based rating.
- * Create and return a new Rating2 instance with one of the star-base rating styles
- * and the given integer or fractional number of stars. Non integer values can for instance
- * be used to represent an average rating value, which might not be an integer number of stars.
- * @param starRatingStyle one of {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
- * {@link #RATING_5_STARS}.
- * @param starRating a number ranging from 0.0f to 3.0f, 4.0f or 5.0f according to
- * the rating style.
- * @return null if the rating style is invalid, or the rating is out of range,
- * a new Rating2 instance otherwise.
- */
- public static @Nullable Rating2 newStarRating(
- @StarStyle int starRatingStyle, float starRating) {
- return ApiLoader.getProvider().newStarRating_Rating2(starRatingStyle, starRating);
- }
-
- /**
- * Return a Rating2 instance with a percentage-based rating.
- * Create and return a new Rating2 instance with a {@link #RATING_PERCENTAGE}
- * rating style, and a rating of the given percentage.
- * @param percent the value of the rating
- * @return null if the rating is out of range, a new Rating2 instance otherwise.
- */
- public static @Nullable Rating2 newPercentageRating(float percent) {
- return ApiLoader.getProvider().newPercentageRating_Rating2(percent);
- }
-
- /**
- * Return whether there is a rating value available.
- * @return true if the instance was not created with {@link #newUnratedRating(int)}.
- */
- public boolean isRated() {
- return mProvider.isRated_impl();
- }
-
- /**
- * Return the rating style.
- * @return one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
- * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
- * or {@link #RATING_PERCENTAGE}.
- */
- public @Style int getRatingStyle() {
- return mProvider.getRatingStyle_impl();
- }
-
- /**
- * Return whether the rating is "heart selected".
- * @return true if the rating is "heart selected", false if the rating is "heart unselected",
- * if the rating style is not {@link #RATING_HEART} or if it is unrated.
- */
- public boolean hasHeart() {
- return mProvider.hasHeart_impl();
- }
-
- /**
- * Return whether the rating is "thumb up".
- * @return true if the rating is "thumb up", false if the rating is "thumb down",
- * if the rating style is not {@link #RATING_THUMB_UP_DOWN} or if it is unrated.
- */
- public boolean isThumbUp() {
- return mProvider.isThumbUp_impl();
- }
-
- /**
- * Return the star-based rating value.
- * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
- * not star-based, or if it is unrated.
- */
- public float getStarRating() {
- return mProvider.getStarRating_impl();
- }
-
- /**
- * Return the percentage-based rating value.
- * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
- * not percentage-based, or if it is unrated.
- */
- public float getPercentRating() {
- return mProvider.getPercentRating_impl();
- }
-}
diff --git a/media/java/android/media/SessionCommand2.java b/media/java/android/media/SessionCommand2.java
deleted file mode 100644
index fe86a3a..0000000
--- a/media/java/android/media/SessionCommand2.java
+++ /dev/null
@@ -1,336 +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;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.media.update.ApiLoader;
-import android.media.update.MediaSession2Provider;
-import android.media.MediaSession2.ControllerInfo;
-import android.media.MediaSession2.SessionCallback;
-import android.net.Uri;
-import android.os.Bundle;
-
-import java.util.List;
-
-/**
- * @hide
- * Define a command that a {@link MediaController2} can send to a {@link MediaSession2}.
- * <p>
- * If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command.
- * If {@link #getCommandCode()} is {@link #COMMAND_CODE_CUSTOM}), it's custom command and
- * {@link #getCustomCommand()} shouldn't be {@code null}.
- */
-public final class SessionCommand2 {
- /**
- * Command code for the custom command which can be defined by string action in the
- * {@link SessionCommand2}.
- */
- public static final int COMMAND_CODE_CUSTOM = 0;
-
- /**
- * Command code for {@link MediaController2#play()}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo,
- * SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYBACK_PLAY = 1;
-
- /**
- * Command code for {@link MediaController2#pause()}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo,
- * SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYBACK_PAUSE = 2;
-
- /**
- * Command code for {@link MediaController2#stop()}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo,
- * SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYBACK_STOP = 3;
-
- /**
- * Command code for {@link MediaController2#skipToNextItem()}.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the {@link SessionCallback#onCommandRequest(
- * MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_SKIP_NEXT_ITEM = 4;
-
- /**
- * Command code for {@link MediaController2#skipToPreviousItem()}.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the {@link SessionCallback#onCommandRequest(
- * MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_SKIP_PREV_ITEM = 5;
-
- /**
- * Command code for {@link MediaController2#prepare()}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo,
- * SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYBACK_PREPARE = 6;
-
- /**
- * Command code for {@link MediaController2#fastForward()}.
- */
- public static final int COMMAND_CODE_SESSION_FAST_FORWARD = 7;
-
- /**
- * Command code for {@link MediaController2#rewind()}.
- */
- public static final int COMMAND_CODE_SESSION_REWIND = 8;
-
- /**
- * Command code for {@link MediaController2#seekTo(long)}.
- * <p>
- * Command would be sent directly to the player if the session doesn't reject the request
- * through the {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo,
- * SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYBACK_SEEK_TO = 9;
-
- /**
- * Command code for both {@link MediaController2#setVolumeTo(int, int)}.
- * <p>
- * Command would set the device volume or send to the volume provider directly if the session
- * doesn't reject the request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_SET_VOLUME = 10;
-
- /**
- * Command code for both {@link MediaController2#adjustVolume(int, int)}.
- * <p>
- * Command would adjust the device volume or send to the volume provider directly if the session
- * doesn't reject the request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_ADJUST_VOLUME = 11;
-
- /**
- * Command code for {@link MediaController2#skipToPlaylistItem(MediaItem2)}.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_SKIP_TO_PLAYLIST_ITEM = 12;
-
- /**
- * Command code for {@link MediaController2#setShuffleMode(int)}.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE = 13;
-
- /**
- * Command code for {@link MediaController2#setRepeatMode(int)}.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE = 14;
-
- /**
- * Command code for {@link MediaController2#addPlaylistItem(int, MediaItem2)}.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_ADD_ITEM = 15;
-
- /**
- * Command code for {@link MediaController2#addPlaylistItem(int, MediaItem2)}.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_REMOVE_ITEM = 16;
-
- /**
- * Command code for {@link MediaController2#replacePlaylistItem(int, MediaItem2)}.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_REPLACE_ITEM = 17;
-
- /**
- * Command code for {@link MediaController2#getPlaylist()}. This will expose metadata
- * information to the controller.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_GET_LIST = 18;
-
- /**
- * Command code for {@link MediaController2#setPlaylist(List, MediaMetadata2)}.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_SET_LIST = 19;
-
- /**
- * Command code for {@link MediaController2#getPlaylistMetadata()}. This will expose
- * metadata information to the controller.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_GET_LIST_METADATA = 20;
-
- /**
- * Command code for {@link MediaController2#updatePlaylistMetadata(MediaMetadata2)}.
- * <p>
- * Command would be sent directly to the playlist agent if the session doesn't reject the
- * request through the
- * {@link SessionCallback#onCommandRequest(MediaSession2, ControllerInfo, SessionCommand2)}.
- */
- public static final int COMMAND_CODE_PLAYLIST_SET_LIST_METADATA = 21;
-
- /**
- * Command code for {@link MediaController2#playFromMediaId(String, Bundle)}.
- */
- public static final int COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID = 22;
-
- /**
- * Command code for {@link MediaController2#playFromUri(Uri, Bundle)}.
- */
- public static final int COMMAND_CODE_SESSION_PLAY_FROM_URI = 23;
-
- /**
- * Command code for {@link MediaController2#playFromSearch(String, Bundle)}.
- */
- public static final int COMMAND_CODE_SESSION_PLAY_FROM_SEARCH = 24;
-
- /**
- * Command code for {@link MediaController2#prepareFromMediaId(String, Bundle)}.
- */
- public static final int COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID = 25;
-
- /**
- * Command code for {@link MediaController2#prepareFromUri(Uri, Bundle)}.
- */
- public static final int COMMAND_CODE_SESSION_PREPARE_FROM_URI = 26;
-
- /**
- * Command code for {@link MediaController2#prepareFromSearch(String, Bundle)}.
- */
- public static final int COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH = 27;
-
- /**
- * Command code for {@link MediaController2#setRating(String, Rating2)}.
- */
- public static final int COMMAND_CODE_SESSION_SET_RATING = 28;
-
- // TODO(jaewan): Add javadoc
- public static final int COMMAND_CODE_LIBRARY_GET_CHILDREN = 29;
- public static final int COMMAND_CODE_LIBRARY_GET_ITEM = 30;
- public static final int COMMAND_CODE_LIBRARY_GET_LIBRARY_ROOT = 31;
- public static final int COMMAND_CODE_LIBRARY_GET_SEARCH_RESULT = 32;
- public static final int COMMAND_CODE_LIBRARY_SEARCH = 33;
- public static final int COMMAND_CODE_LIBRARY_SUBSCRIBE = 34;
- public static final int COMMAND_CODE_LIBRARY_UNSUBSCRIBE = 35;
-
- // TODO(jaewan): Rename and move provider
- private final MediaSession2Provider.CommandProvider mProvider;
-
- public SessionCommand2(int commandCode) {
- mProvider = ApiLoader.getProvider().createMediaSession2Command(
- this, commandCode, null, null);
- }
-
- public SessionCommand2(@NonNull String action, @Nullable Bundle extras) {
- if (action == null) {
- throw new IllegalArgumentException("action shouldn't be null");
- }
- mProvider = ApiLoader.getProvider().createMediaSession2Command(
- this, COMMAND_CODE_CUSTOM, action, extras);
- }
-
- /**
- * @hide
- */
- public MediaSession2Provider.CommandProvider getProvider() {
- return mProvider;
- }
-
- public int getCommandCode() {
- return mProvider.getCommandCode_impl();
- }
-
- public @Nullable String getCustomCommand() {
- return mProvider.getCustomCommand_impl();
- }
-
- public @Nullable Bundle getExtras() {
- return mProvider.getExtras_impl();
- }
-
- /**
- * @return a new Bundle instance from the Command
- * @hide
- */
- public Bundle toBundle() {
- return mProvider.toBundle_impl();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (!(obj instanceof SessionCommand2)) {
- return false;
- }
- return mProvider.equals_impl(((SessionCommand2) obj).mProvider);
- }
-
- @Override
- public int hashCode() {
- return mProvider.hashCode_impl();
- }
-
- /**
- * @return a new Command instance from the Bundle
- * @hide
- */
- public static SessionCommand2 fromBundle(@NonNull Bundle command) {
- return ApiLoader.getProvider().fromBundle_MediaSession2Command(command);
- }
-}
diff --git a/media/java/android/media/SessionCommandGroup2.java b/media/java/android/media/SessionCommandGroup2.java
deleted file mode 100644
index 399765e..0000000
--- a/media/java/android/media/SessionCommandGroup2.java
+++ /dev/null
@@ -1,106 +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;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.media.update.ApiLoader;
-import android.media.update.MediaSession2Provider;
-import android.os.Bundle;
-
-import java.util.Set;
-
-/**
- * @hide
- * Represent set of {@link SessionCommand2}.
- */
-public final class SessionCommandGroup2 {
- // TODO(jaewan): Rename and move provider
- private final MediaSession2Provider.CommandGroupProvider mProvider;
-
- public SessionCommandGroup2() {
- mProvider = ApiLoader.getProvider().createMediaSession2CommandGroup(this, null);
- }
-
- public SessionCommandGroup2(@Nullable SessionCommandGroup2 others) {
- mProvider = ApiLoader.getProvider().createMediaSession2CommandGroup(this, others);
- }
-
- /**
- * @hide
- */
- public SessionCommandGroup2(@NonNull MediaSession2Provider.CommandGroupProvider provider) {
- mProvider = provider;
- }
-
- public void addCommand(@NonNull SessionCommand2 command) {
- mProvider.addCommand_impl(command);
- }
-
- public void addCommand(int commandCode) {
- // TODO(jaewna): Implement
- }
-
- public void addAllPredefinedCommands() {
- mProvider.addAllPredefinedCommands_impl();
- }
-
- public void removeCommand(@NonNull SessionCommand2 command) {
- mProvider.removeCommand_impl(command);
- }
-
- public void removeCommand(int commandCode) {
- // TODO(jaewan): Implement.
- }
-
- public boolean hasCommand(@NonNull SessionCommand2 command) {
- return mProvider.hasCommand_impl(command);
- }
-
- public boolean hasCommand(int code) {
- return mProvider.hasCommand_impl(code);
- }
-
- public @NonNull
- Set<SessionCommand2> getCommands() {
- return mProvider.getCommands_impl();
- }
-
- /**
- * @hide
- */
- public @NonNull MediaSession2Provider.CommandGroupProvider getProvider() {
- return mProvider;
- }
-
- /**
- * @return new bundle from the CommandGroup
- * @hide
- */
- public @NonNull Bundle toBundle() {
- return mProvider.toBundle_impl();
- }
-
- /**
- * @return new instance of CommandGroup from the bundle
- * @hide
- */
- public static @Nullable SessionCommandGroup2 fromBundle(Bundle commands) {
- return ApiLoader.getProvider().fromBundle_MediaSession2CommandGroup(commands);
- }
-}
diff --git a/media/java/android/media/SessionToken2.java b/media/java/android/media/SessionToken2.java
deleted file mode 100644
index f7d54f2..0000000
--- a/media/java/android/media/SessionToken2.java
+++ /dev/null
@@ -1,164 +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;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.content.Context;
-import android.media.session.MediaSessionManager;
-import android.media.update.ApiLoader;
-import android.media.update.SessionToken2Provider;
-import android.os.Bundle;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * @hide
- * Represents an ongoing {@link MediaSession2}.
- * If it's representing a session service, it may not be ongoing.
- * <p>
- * This may be passed to apps by the session owner to allow them to create a
- * {@link MediaController2} to communicate with the session.
- * <p>
- * It can be also obtained by {@link MediaSessionManager}.
- */
-// New version of MediaSession.Token for following reasons
-// - Stop implementing Parcelable for updatable support
-// - Represent session and library service (formerly browser service) in one class.
-// Previously MediaSession.Token was for session and ComponentName was for service.
-public final class SessionToken2 {
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {TYPE_SESSION, TYPE_SESSION_SERVICE, TYPE_LIBRARY_SERVICE})
- public @interface TokenType {
- }
-
- public static final int TYPE_SESSION = 0;
- public static final int TYPE_SESSION_SERVICE = 1;
- public static final int TYPE_LIBRARY_SERVICE = 2;
-
- private final SessionToken2Provider mProvider;
-
- // From the return value of android.os.Process.getUidForName(String) when error
- private static final int UID_UNKNOWN = -1;
-
- /**
- * Constructor for the token. You can only create token for session service or library service
- * to use by {@link MediaController2} or {@link MediaBrowser2}.
- *
- * @param context context
- * @param packageName package name
- * @param serviceName name of service. Can be {@code null} if it's not an service.
- */
- public SessionToken2(@NonNull Context context, @NonNull String packageName,
- @NonNull String serviceName) {
- this(context, packageName, serviceName, UID_UNKNOWN);
- }
-
- /**
- * Constructor for the token. You can only create token for session service or library service
- * to use by {@link MediaController2} or {@link MediaBrowser2}.
- *
- * @param context context
- * @param packageName package name
- * @param serviceName name of service. Can be {@code null} if it's not an service.
- * @param uid uid of the app.
- * @hide
- */
- public SessionToken2(@NonNull Context context, @NonNull String packageName,
- @NonNull String serviceName, int uid) {
- mProvider = ApiLoader.getProvider().createSessionToken2(
- context, this, packageName, serviceName, uid);
- }
-
- /**
- * Constructor for the token.
- * @hide
- */
- public SessionToken2(@NonNull SessionToken2Provider provider) {
- mProvider = provider;
- }
-
- @Override
- public int hashCode() {
- return mProvider.hashCode_impl();
- }
-
- @Override
- public boolean equals(Object obj) {
- return mProvider.equals_impl(obj);
- }
-
- @Override
- public String toString() {
- return mProvider.toString_impl();
- }
-
- /**
- * @hide
- */
- public SessionToken2Provider getProvider() {
- return mProvider;
- }
-
- /**
- * @return uid of the session
- */
- public int getUid() {
- return mProvider.getUid_impl();
- }
-
- /**
- * @return package name
- */
- public String getPackageName() {
- return mProvider.getPackageName_impl();
- }
-
- /**
- * @return id
- */
- public String getId() {
- return mProvider.getId_imp();
- }
-
- /**
- * @return type of the token
- * @see #TYPE_SESSION
- * @see #TYPE_SESSION_SERVICE
- */
- public @TokenType int getType() {
- return mProvider.getType_impl();
- }
-
- /**
- * Create a token from the bundle, exported by {@link #toBundle()}.
- * @param bundle
- * @return
- */
- public static SessionToken2 fromBundle(@NonNull Bundle bundle) {
- return ApiLoader.getProvider().fromBundle_SessionToken2(bundle);
- }
-
- /**
- * Create a {@link Bundle} from this token to share it across processes.
- * @return Bundle
- */
- public Bundle toBundle() {
- return mProvider.toBundle_impl();
- }
-}
diff --git a/media/java/android/media/VolumeProvider2.java b/media/java/android/media/VolumeProvider2.java
deleted file mode 100644
index 1a4608f..0000000
--- a/media/java/android/media/VolumeProvider2.java
+++ /dev/null
@@ -1,147 +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;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.media.update.ApiLoader;
-import android.media.update.VolumeProvider2Provider;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * @hide
- * Handles requests to adjust or set the volume on a session. This is also used
- * to push volume updates back to the session. The provider must call
- * {@link #setCurrentVolume(int)} each time the volume being provided changes.
- * <p>
- * You can set a volume provider on a session by calling
- * {@link MediaSession2#updatePlayer}.
- */
-// New version of VolumeProvider with following changes
-// - Don't implement Parcelable for updatable support.
-public abstract class VolumeProvider2 {
- /**
- * @hide
- */
- @IntDef({VOLUME_CONTROL_FIXED, VOLUME_CONTROL_RELATIVE, VOLUME_CONTROL_ABSOLUTE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ControlType {}
-
- /**
- * The volume is fixed and can not be modified. Requests to change volume
- * should be ignored.
- */
- public static final int VOLUME_CONTROL_FIXED = 0;
-
- /**
- * The volume control uses relative adjustment via
- * {@link #onAdjustVolume(int)}. Attempts to set the volume to a specific
- * value should be ignored.
- */
- public static final int VOLUME_CONTROL_RELATIVE = 1;
-
- /**
- * The volume control uses an absolute value. It may be adjusted using
- * {@link #onAdjustVolume(int)} or set directly using
- * {@link #onSetVolumeTo(int)}.
- */
- public static final int VOLUME_CONTROL_ABSOLUTE = 2;
-
- private final VolumeProvider2Provider mProvider;
-
- /**
- * Create a new volume provider for handling volume events. You must specify
- * the type of volume control, the maximum volume that can be used, and the
- * current volume on the output.
- *
- * @param controlType The method for controlling volume that is used by this provider.
- * @param maxVolume The maximum allowed volume.
- * @param currentVolume The current volume on the output.
- */
- public VolumeProvider2(@ControlType int controlType, int maxVolume, int currentVolume) {
- mProvider = ApiLoader.getProvider().createVolumeProvider2(
- this, controlType, maxVolume, currentVolume);
- }
-
- /**
- * @hide
- */
- public VolumeProvider2Provider getProvider() {
- return mProvider;
- }
-
- /**
- * Get the volume control type that this volume provider uses.
- *
- * @return The volume control type for this volume provider
- */
- @ControlType
- public final int getControlType() {
- return mProvider.getControlType_impl();
- }
-
- /**
- * Get the maximum volume this provider allows.
- *
- * @return The max allowed volume.
- */
- public final int getMaxVolume() {
- return mProvider.getMaxVolume_impl();
- }
-
- /**
- * Gets the current volume. This will be the last value set by
- * {@link #setCurrentVolume(int)}.
- *
- * @return The current volume.
- */
- public final int getCurrentVolume() {
- return mProvider.getCurrentVolume_impl();
- }
-
- /**
- * Notify the system that the current volume has been changed. This must be
- * called every time the volume changes to ensure it is displayed properly.
- *
- * @param currentVolume The current volume on the output.
- */
- public final void setCurrentVolume(int currentVolume) {
- mProvider.setCurrentVolume_impl(currentVolume);
- }
-
- /**
- * Override to handle requests to set the volume of the current output.
- * After the volume has been modified {@link #setCurrentVolume} must be
- * called to notify the system.
- *
- * @param volume The volume to set the output to.
- */
- public void onSetVolumeTo(int volume) { }
-
- /**
- * Override to handle requests to adjust the volume of the current output.
- * Direction will be one of {@link AudioManager#ADJUST_LOWER},
- * {@link AudioManager#ADJUST_RAISE}, {@link AudioManager#ADJUST_SAME}.
- * After the volume has been modified {@link #setCurrentVolume} must be
- * called to notify the system.
- *
- * @param direction The direction to change the volume in.
- */
- public void onAdjustVolume(int direction) { }
-}
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 3578c16..4ced7be 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -17,7 +17,6 @@
import android.content.ComponentName;
import android.media.IRemoteVolumeController;
-import android.media.ISessionTokensListener;
import android.media.session.IActiveSessionsListener;
import android.media.session.ICallback;
import android.media.session.IOnMediaKeyListener;
@@ -55,12 +54,4 @@
// MediaSession2
boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
- boolean createSession2(in Bundle sessionToken);
- void destroySession2(in Bundle sessionToken);
- List<Bundle> getSessionTokens(boolean activeSessionOnly, boolean sessionServiceOnly,
- String packageName);
-
- void addSessionTokensListener(in ISessionTokensListener listener, int userId,
- String packageName);
- void removeSessionTokensListener(in ISessionTokensListener listener, String packageName);
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 98f3fb2..8215779 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -26,11 +26,7 @@
import android.content.Context;
import android.media.AudioManager;
import android.media.IRemoteVolumeController;
-import android.media.ISessionTokensListener;
-import android.media.MediaSession2;
-import android.media.SessionToken2;
import android.media.browse.MediaBrowser;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
@@ -44,10 +40,8 @@
import android.view.KeyEvent;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
-import java.util.concurrent.Executor;
/**
* Provides support for interacting with {@link MediaSession media sessions}
@@ -75,8 +69,6 @@
private final ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper> mListeners
= new ArrayMap<OnActiveSessionsChangedListener, SessionsChangedWrapper>();
- private final ArrayMap<OnSessionTokensChangedListener, SessionTokensChangedWrapper>
- mSessionTokensListener = new ArrayMap<>();
private final Object mLock = new Object();
private final ISessionManager mService;
@@ -413,73 +405,6 @@
}
/**
- * Called when a {@link MediaSession2} is created.
- * @hide
- */
- public boolean createSession2(@NonNull SessionToken2 token) {
- if (token == null) {
- return false;
- }
- try {
- return mService.createSession2(token.toBundle());
- } catch (RemoteException e) {
- Log.wtf(TAG, "Cannot communicate with the service.", e);
- }
- return false;
- }
-
- /**
- * Called when a {@link MediaSession2} is destroyed.
- * @hide
- */
- public void destroySession2(@NonNull SessionToken2 token) {
- if (token == null) {
- return;
- }
- try {
- mService.destroySession2(token.toBundle());
- } catch (RemoteException e) {
- Log.wtf(TAG, "Cannot communicate with the service.", e);
- }
- }
-
- /**
- * @hide
- * Get {@link List} of {@link SessionToken2} whose sessions are active now. This list represents
- * active sessions regardless of whether they're {@link MediaSession2}.
- * <p>
- * This requires the android.Manifest.permission.MEDIA_CONTENT_CONTROL permission be held by the
- * calling app. You may also retrieve this list if your app is an enabled notification listener
- * using the {@link NotificationListenerService} APIs.
- *
- * @return list of tokens
- */
- public List<SessionToken2> getActiveSessionTokens() {
- try {
- List<Bundle> bundles = mService.getSessionTokens(
- /* activeSessionOnly */ true, /* sessionServiceOnly */ false,
- mContext.getOpPackageName());
- return toTokenList(bundles);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Cannot communicate with the service.", e);
- return Collections.emptyList();
- }
- }
-
- private static List<SessionToken2> toTokenList(List<Bundle> bundles) {
- List<SessionToken2> tokens = new ArrayList<>();
- if (bundles != null) {
- for (int i = 0; i < bundles.size(); i++) {
- SessionToken2 token = SessionToken2.fromBundle(bundles.get(i));
- if (token != null) {
- tokens.add(token);
- }
- }
- }
- return tokens;
- }
-
- /**
* Check if the global priority session is currently active. This can be
* used to decide if media keys should be sent to the session or to the app.
*
@@ -601,15 +526,6 @@
}
/**
- * @hide
- * Listens for changes to the {@link #getAllSessionTokens()}. This can be added
- * using {@link #addOnActiveSessionsChangedListener}.
- */
- public interface OnSessionTokensChangedListener {
- void onSessionTokensChanged(@NonNull List<SessionToken2> tokens);
- }
-
- /**
* Listens the volume key long-presses.
* @hide
*/
@@ -815,41 +731,6 @@
}
}
- private static final class SessionTokensChangedWrapper {
- private Context mContext;
- private Executor mExecutor;
- private OnSessionTokensChangedListener mListener;
-
- public SessionTokensChangedWrapper(Context context, Executor executor,
- OnSessionTokensChangedListener listener) {
- mContext = context;
- mExecutor = executor;
- mListener = listener;
- }
-
- private final ISessionTokensListener.Stub mStub = new ISessionTokensListener.Stub() {
- @Override
- public void onSessionTokensChanged(final List<Bundle> bundles) {
- final Executor executor = mExecutor;
- if (executor != null) {
- executor.execute(() -> {
- final Context context = mContext;
- final OnSessionTokensChangedListener listener = mListener;
- if (context != null && listener != null) {
- listener.onSessionTokensChanged(toTokenList(bundles));
- }
- });
- }
- }
- };
-
- private void release() {
- mListener = null;
- mContext = null;
- mExecutor = null;
- }
- }
-
private static final class OnVolumeKeyLongPressListenerImpl
extends IOnVolumeKeyLongPressListener.Stub {
private OnVolumeKeyLongPressListener mListener;
diff --git a/media/java/android/media/update/ApiLoader.java b/media/java/android/media/update/ApiLoader.java
deleted file mode 100644
index 0c1d1a2..0000000
--- a/media/java/android/media/update/ApiLoader.java
+++ /dev/null
@@ -1,79 +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 android.media.update;
-
-import android.app.ActivityManager;
-import android.app.AppGlobals;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Build;
-import android.os.RemoteException;
-import android.os.UserHandle;
-
-import com.android.internal.annotations.GuardedBy;
-
-import dalvik.system.PathClassLoader;
-
-import java.io.File;
-
-/**
- * @hide
- */
-public final class ApiLoader {
- @GuardedBy("this")
- private static StaticProvider sMediaUpdatable;
-
- private static final String UPDATE_PACKAGE = "com.android.media.update";
- private static final String UPDATE_CLASS = "com.android.media.update.ApiFactory";
- private static final String UPDATE_METHOD = "initialize";
- private static final boolean REGISTER_UPDATE_DEPENDENCY = true;
-
- private ApiLoader() { }
-
- public static StaticProvider getProvider() {
- try {
- return getMediaUpdatable();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- } catch (NameNotFoundException | ReflectiveOperationException e) {
- throw new RuntimeException(e);
- }
- }
-
- // TODO This method may do I/O; Ensure it does not violate (emit warnings in) strict mode.
- private static synchronized StaticProvider getMediaUpdatable()
- throws NameNotFoundException, ReflectiveOperationException, RemoteException {
- if (sMediaUpdatable != null) return sMediaUpdatable;
-
- // TODO Figure out when to use which package (query media update service)
- int flags = Build.IS_DEBUGGABLE ? 0 : PackageManager.MATCH_SYSTEM_ONLY;
- ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo(
- UPDATE_PACKAGE, flags, UserHandle.myUserId());
-
- if (REGISTER_UPDATE_DEPENDENCY) {
- // Register a dependency to the updatable in order to be killed during updates
- ActivityManager.getService().addPackageDependency(ai.packageName);
- }
-
- ClassLoader classLoader = new PathClassLoader(ai.sourceDir,
- ai.nativeLibraryDir + File.pathSeparator + System.getProperty("java.library.path"),
- ClassLoader.getSystemClassLoader().getParent());
- return sMediaUpdatable = (StaticProvider) classLoader.loadClass(UPDATE_CLASS)
- .getMethod(UPDATE_METHOD, ApplicationInfo.class).invoke(null, ai);
- }
-}
diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java
deleted file mode 100644
index 7234f7b..0000000
--- a/media/java/android/media/update/MediaController2Provider.java
+++ /dev/null
@@ -1,82 +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.app.PendingIntent;
-import android.media.AudioAttributes;
-import android.media.MediaController2.PlaybackInfo;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.SessionCommand2;
-import android.media.Rating2;
-import android.media.SessionToken2;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-import java.util.List;
-
-/**
- * @hide
- */
-public interface MediaController2Provider extends TransportControlProvider {
- void initialize();
-
- void close_impl();
- SessionToken2 getSessionToken_impl();
- boolean isConnected_impl();
-
- PendingIntent getSessionActivity_impl();
-
- void setVolumeTo_impl(int value, int flags);
- void adjustVolume_impl(int direction, int flags);
- PlaybackInfo getPlaybackInfo_impl();
-
- void prepareFromUri_impl(Uri uri, Bundle extras);
- void prepareFromSearch_impl(String query, Bundle extras);
- void prepareFromMediaId_impl(String mediaId, Bundle extras);
- void playFromSearch_impl(String query, Bundle extras);
- void playFromUri_impl(Uri uri, Bundle extras);
- void playFromMediaId_impl(String mediaId, Bundle extras);
- void fastForward_impl();
- void rewind_impl();
-
- void setRating_impl(String mediaId, Rating2 rating);
- void sendCustomCommand_impl(SessionCommand2 command, Bundle args, ResultReceiver cb);
- List<MediaItem2> getPlaylist_impl();
- void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata);
- MediaMetadata2 getPlaylistMetadata_impl();
- void updatePlaylistMetadata_impl(MediaMetadata2 metadata);
-
- void addPlaylistItem_impl(int index, MediaItem2 item);
- void replacePlaylistItem_impl(int index, MediaItem2 item);
- void removePlaylistItem_impl(MediaItem2 item);
-
- int getPlayerState_impl();
- long getCurrentPosition_impl();
- float getPlaybackSpeed_impl();
- long getBufferedPosition_impl();
- MediaItem2 getCurrentMediaItem_impl();
-
- interface PlaybackInfoProvider {
- int getPlaybackType_impl();
- AudioAttributes getAudioAttributes_impl();
- int getControlType_impl();
- int getMaxVolume_impl();
- int getCurrentVolume_impl();
- }
-}
diff --git a/media/java/android/media/update/MediaItem2Provider.java b/media/java/android/media/update/MediaItem2Provider.java
deleted file mode 100644
index 47db22f..0000000
--- a/media/java/android/media/update/MediaItem2Provider.java
+++ /dev/null
@@ -1,46 +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.media.DataSourceDesc;
-import android.media.MediaItem2;
-import android.media.MediaItem2.Builder;
-import android.media.MediaMetadata2;
-import android.os.Bundle;
-
-/**
- * @hide
- */
-public interface MediaItem2Provider {
- Bundle toBundle_impl();
- String toString_impl();
- int getFlags_impl();
- boolean isBrowsable_impl();
- boolean isPlayable_impl();
- void setMetadata_impl(MediaMetadata2 metadata);
- MediaMetadata2 getMetadata_impl();
- String getMediaId_impl();
- DataSourceDesc getDataSourceDesc_impl();
- boolean equals_impl(Object obj);
-
- interface BuilderProvider {
- Builder setMediaId_impl(String mediaId);
- Builder setMetadata_impl(MediaMetadata2 metadata);
- Builder setDataSourceDesc_impl(DataSourceDesc dataSourceDesc);
- MediaItem2 build_impl();
- }
-}
diff --git a/media/java/android/media/update/MediaMetadata2Provider.java b/media/java/android/media/update/MediaMetadata2Provider.java
deleted file mode 100644
index 22463e9..0000000
--- a/media/java/android/media/update/MediaMetadata2Provider.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package android.media.update;
-
-import android.graphics.Bitmap;
-import android.media.MediaMetadata2;
-import android.media.MediaMetadata2.Builder;
-import android.media.Rating2;
-import android.os.Bundle;
-
-import java.util.Set;
-
-/**
- * @hide
- */
-public interface MediaMetadata2Provider {
- boolean containsKey_impl(String key);
- CharSequence getText_impl(String key);
- String getMediaId_impl();
- String getString_impl(String key);
- long getLong_impl(String key);
- Rating2 getRating_impl(String key);
- Bundle toBundle_impl();
- Set<String> keySet_impl();
- int size_impl();
- Bitmap getBitmap_impl(String key);
- float getFloat_impl(String key);
- Bundle getExtras_impl();
-
- interface BuilderProvider {
- Builder putText_impl(String key, CharSequence value);
- Builder putString_impl(String key, String value);
- Builder putLong_impl(String key, long value);
- Builder putRating_impl(String key, Rating2 value);
- Builder putBitmap_impl(String key, Bitmap value);
- Builder putFloat_impl(String key, float value);
- Builder setExtras_impl(Bundle bundle);
- MediaMetadata2 build_impl();
- }
-}
diff --git a/media/java/android/media/update/MediaPlaylistAgentProvider.java b/media/java/android/media/update/MediaPlaylistAgentProvider.java
deleted file mode 100644
index e1522cf..0000000
--- a/media/java/android/media/update/MediaPlaylistAgentProvider.java
+++ /dev/null
@@ -1,55 +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.media.DataSourceDesc;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaPlaylistAgent.PlaylistEventCallback;
-
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * @hide
- */
-public interface MediaPlaylistAgentProvider {
- // final methods of MediaPlaylistAgent
- void registerPlaylistEventCallback_impl(Executor executor, PlaylistEventCallback callback);
- void unregisterPlaylistEventCallback_impl(PlaylistEventCallback callback);
- void notifyPlaylistChanged_impl();
- void notifyPlaylistMetadataChanged_impl();
- void notifyShuffleModeChanged_impl();
- void notifyRepeatModeChanged_impl();
-
- // public methods of MediaPlaylistAgent
- List<MediaItem2> getPlaylist_impl();
- void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata);
- MediaMetadata2 getPlaylistMetadata_impl();
- void updatePlaylistMetadata_impl(MediaMetadata2 metadata);
- void addPlaylistItem_impl(int index, MediaItem2 item);
- void removePlaylistItem_impl(MediaItem2 item);
- void replacePlaylistItem_impl(int index, MediaItem2 item);
- void skipToPlaylistItem_impl(MediaItem2 item);
- void skipToPreviousItem_impl();
- void skipToNextItem_impl();
- int getRepeatMode_impl();
- void setRepeatMode_impl(int repeatMode);
- int getShuffleMode_impl();
- void setShuffleMode_impl(int shuffleMode);
- MediaItem2 getMediaItem_impl(DataSourceDesc dsd);
-}
diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java
deleted file mode 100644
index 4751348..0000000
--- a/media/java/android/media/update/MediaSession2Provider.java
+++ /dev/null
@@ -1,132 +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.app.PendingIntent;
-import android.media.AudioFocusRequest;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaPlayerBase;
-import android.media.MediaPlaylistAgent;
-import android.media.MediaSession2;
-import android.media.SessionCommand2;
-import android.media.MediaSession2.CommandButton;
-import android.media.MediaSession2.CommandButton.Builder;
-import android.media.SessionCommandGroup2;
-import android.media.MediaSession2.ControllerInfo;
-import android.media.MediaSession2.OnDataSourceMissingHelper;
-import android.media.MediaSession2.SessionCallback;
-import android.media.SessionToken2;
-import android.media.VolumeProvider2;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Executor;
-
-/**
- * @hide
- */
-public interface MediaSession2Provider extends TransportControlProvider {
- void close_impl();
- void updatePlayer_impl(MediaPlayerBase player, MediaPlaylistAgent playlistAgent,
- VolumeProvider2 volumeProvider);
- MediaPlayerBase getPlayer_impl();
- MediaMetadata2 getPlaylistMetadata_impl();
- void updatePlaylistMetadata_impl(MediaMetadata2 metadata);
- MediaPlaylistAgent getPlaylistAgent_impl();
- VolumeProvider2 getVolumeProvider_impl();
- SessionToken2 getToken_impl();
- List<ControllerInfo> getConnectedControllers_impl();
- void setCustomLayout_impl(ControllerInfo controller, List<CommandButton> layout);
- void setAudioFocusRequest_impl(AudioFocusRequest afr);
- void setAllowedCommands_impl(ControllerInfo controller, SessionCommandGroup2 commands);
- void sendCustomCommand_impl(ControllerInfo controller, SessionCommand2 command, Bundle args,
- ResultReceiver receiver);
- void sendCustomCommand_impl(SessionCommand2 command, Bundle args);
- void addPlaylistItem_impl(int index, MediaItem2 item);
- void removePlaylistItem_impl(MediaItem2 item);
- void replacePlaylistItem_impl(int index, MediaItem2 item);
- List<MediaItem2> getPlaylist_impl();
- void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata);
- MediaItem2 getCurrentPlaylistItem_impl();
- void notifyError_impl(int errorCode, Bundle extras);
- int getPlayerState_impl();
- long getCurrentPosition_impl();
- long getBufferedPosition_impl();
- void setOnDataSourceMissingHelper_impl(OnDataSourceMissingHelper helper);
- void clearOnDataSourceMissingHelper_impl();
-
- // TODO(jaewan): Rename and move provider
- interface CommandProvider {
- int getCommandCode_impl();
- String getCustomCommand_impl();
- Bundle getExtras_impl();
- Bundle toBundle_impl();
-
- boolean equals_impl(Object ob);
- int hashCode_impl();
- }
-
- // TODO(jaewan): Rename and move provider
- interface CommandGroupProvider {
- void addCommand_impl(SessionCommand2 command);
- void addAllPredefinedCommands_impl();
- void removeCommand_impl(SessionCommand2 command);
- boolean hasCommand_impl(SessionCommand2 command);
- boolean hasCommand_impl(int code);
- Set<SessionCommand2> getCommands_impl();
- Bundle toBundle_impl();
- }
-
- interface CommandButtonProvider {
- SessionCommand2 getCommand_impl();
- int getIconResId_impl();
- String getDisplayName_impl();
- Bundle getExtras_impl();
- boolean isEnabled_impl();
-
- interface BuilderProvider {
- Builder setCommand_impl(SessionCommand2 command);
- Builder setIconResId_impl(int resId);
- Builder setDisplayName_impl(String displayName);
- Builder setEnabled_impl(boolean enabled);
- Builder setExtras_impl(Bundle extras);
- CommandButton build_impl();
- }
- }
-
- interface ControllerInfoProvider {
- String getPackageName_impl();
- int getUid_impl();
- boolean isTrusted_impl();
- int hashCode_impl();
- boolean equals_impl(Object obj);
- String toString_impl();
- }
-
- interface BuilderBaseProvider<T extends MediaSession2, C extends SessionCallback> {
- void setPlayer_impl(MediaPlayerBase player);
- void setPlaylistAgent_impl(MediaPlaylistAgent playlistAgent);
- void setVolumeProvider_impl(VolumeProvider2 volumeProvider);
- void setSessionActivity_impl(PendingIntent pi);
- void setId_impl(String id);
- void setSessionCallback_impl(Executor executor, C callback);
- T build_impl();
- }
-}
diff --git a/media/java/android/media/update/Rating2Provider.java b/media/java/android/media/update/Rating2Provider.java
deleted file mode 100644
index 28ad273..0000000
--- a/media/java/android/media/update/Rating2Provider.java
+++ /dev/null
@@ -1,36 +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.annotation.SystemApi;
-import android.os.Bundle;
-
-/**
- * @hide
- */
-public interface Rating2Provider {
- String toString_impl();
- boolean equals_impl(Object obj);
- int hashCode_impl();
- Bundle toBundle_impl();
- boolean isRated_impl();
- int getRatingStyle_impl();
- boolean hasHeart_impl();
- boolean isThumbUp_impl();
- float getStarRating_impl();
- float getPercentRating_impl();
-}
diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java
deleted file mode 100644
index ccb8c02..0000000
--- a/media/java/android/media/update/StaticProvider.java
+++ /dev/null
@@ -1,92 +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 android.media.update;
-
-import android.content.Context;
-import android.media.MediaController2;
-import android.media.MediaController2.ControllerCallback;
-import android.media.MediaItem2;
-import android.media.MediaMetadata2;
-import android.media.MediaPlaylistAgent;
-import android.media.MediaSession2;
-import android.media.MediaSession2.SessionCallback;
-import android.media.Rating2;
-import android.media.SessionCommand2;
-import android.media.SessionCommandGroup2;
-import android.media.SessionToken2;
-import android.media.VolumeProvider2;
-import android.media.update.MediaSession2Provider.BuilderBaseProvider;
-import android.media.update.MediaSession2Provider.CommandButtonProvider;
-import android.media.update.MediaSession2Provider.CommandGroupProvider;
-import android.media.update.MediaSession2Provider.CommandProvider;
-import android.media.update.MediaSession2Provider.ControllerInfoProvider;
-import android.os.Bundle;
-import android.os.IInterface;
-
-import java.util.concurrent.Executor;
-
-/**
- * Interface for connecting the public API to an updatable implementation.
- *
- * This interface provides access to constructors and static methods that are otherwise not directly
- * accessible via an implementation object.
- * @hide
- */
-public interface StaticProvider {
- CommandProvider createMediaSession2Command(SessionCommand2 instance,
- int commandCode, String action, Bundle extra);
- SessionCommand2 fromBundle_MediaSession2Command(Bundle bundle);
- CommandGroupProvider createMediaSession2CommandGroup(SessionCommandGroup2 instance,
- SessionCommandGroup2 others);
- SessionCommandGroup2 fromBundle_MediaSession2CommandGroup(Bundle bundle);
- ControllerInfoProvider createMediaSession2ControllerInfo(Context context,
- MediaSession2.ControllerInfo instance, int uid, int pid,
- String packageName, IInterface callback);
- CommandButtonProvider.BuilderProvider createMediaSession2CommandButtonBuilder(
- MediaSession2.CommandButton.Builder instance);
- BuilderBaseProvider<MediaSession2, SessionCallback> createMediaSession2Builder(
- Context context, MediaSession2.Builder instance);
-
- MediaController2Provider createMediaController2(Context context, MediaController2 instance,
- SessionToken2 token, Executor executor, ControllerCallback callback);
-
- SessionToken2Provider createSessionToken2(Context context, SessionToken2 instance,
- String packageName, String serviceName, int uid);
- SessionToken2 fromBundle_SessionToken2(Bundle bundle);
-
- MediaItem2Provider.BuilderProvider createMediaItem2Builder(MediaItem2.Builder instance,
- int flags);
- MediaItem2 fromBundle_MediaItem2(Bundle bundle);
-
- VolumeProvider2Provider createVolumeProvider2(VolumeProvider2 instance, int controlType,
- int maxVolume, int currentVolume);
-
- MediaMetadata2 fromBundle_MediaMetadata2(Bundle bundle);
- MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
- MediaMetadata2.Builder instance);
- MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder(
- MediaMetadata2.Builder instance, MediaMetadata2 source);
-
- Rating2 newUnratedRating_Rating2(int ratingStyle);
- Rating2 fromBundle_Rating2(Bundle bundle);
- Rating2 newHeartRating_Rating2(boolean hasHeart);
- Rating2 newThumbRating_Rating2(boolean thumbIsUp);
- Rating2 newStarRating_Rating2(int starRatingStyle, float starRating);
- Rating2 newPercentageRating_Rating2(float percent);
-
- MediaPlaylistAgentProvider createMediaPlaylistAgent(MediaPlaylistAgent instance);
-}
diff --git a/media/java/android/media/update/TransportControlProvider.java b/media/java/android/media/update/TransportControlProvider.java
deleted file mode 100644
index d89a88a..0000000
--- a/media/java/android/media/update/TransportControlProvider.java
+++ /dev/null
@@ -1,39 +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.media.MediaItem2;
-
-/**
- * @hide
- */
-public interface TransportControlProvider {
- void play_impl();
- void pause_impl();
- void stop_impl();
- void skipToPreviousItem_impl();
- void skipToNextItem_impl();
-
- void prepare_impl();
- void seekTo_impl(long pos);
- void skipToPlaylistItem_impl(MediaItem2 item);
-
- int getRepeatMode_impl();
- void setRepeatMode_impl(int repeatMode);
- int getShuffleMode_impl();
- void setShuffleMode_impl(int shuffleMode);
-}
diff --git a/media/java/android/media/update/VolumeProvider2Provider.java b/media/java/android/media/update/VolumeProvider2Provider.java
deleted file mode 100644
index 5b5cfd3..0000000
--- a/media/java/android/media/update/VolumeProvider2Provider.java
+++ /dev/null
@@ -1,26 +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;
-
-/**
- * @hide
- */
-public interface VolumeProvider2Provider {
- int getControlType_impl();
- int getMaxVolume_impl();
- int getCurrentVolume_impl();
- void setCurrentVolume_impl(int currentVolume);
-}
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 8fac3fd..99d48d3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -34,7 +34,7 @@
import com.android.settingslib.R;
-import libcore.util.TimeZoneFinder;
+import libcore.timezone.TimeZoneFinder;
import org.xmlpull.v1.XmlPullParserException;
diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS
index 75c0391..6ba1fcb 100644
--- a/packages/Shell/OWNERS
+++ b/packages/Shell/OWNERS
@@ -1,10 +1,12 @@
+set noparent
+
+jsharkey@android.com
+felipeal@google.com
+nandana@google.com
svetoslavganov@google.com
hackbod@google.com
yamasani@google.com
moltmann@google.com
toddke@google.com
-jsharkey@google.com
cbrubaker@google.com
omakoto@google.com
-nandana@google.com
-felipeal@google.com
diff --git a/packages/SystemUI/res/layout/smart_action_button.xml b/packages/SystemUI/res/layout/smart_action_button.xml
new file mode 100644
index 0000000..2716034
--- /dev/null
+++ b/packages/SystemUI/res/layout/smart_action_button.xml
@@ -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
+ -->
+
+<!-- android:paddingHorizontal is set dynamically in SmartReplyView. -->
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@android:style/Widget.Material.Button"
+ android:stateListAnimator="@null"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:minWidth="0dp"
+ android:minHeight="@dimen/smart_reply_button_min_height"
+ android:paddingVertical="@dimen/smart_reply_button_padding_vertical"
+ android:background="@drawable/smart_reply_button_background"
+ android:gravity="center"
+ android:fontFamily="roboto-medium"
+ android:textSize="@dimen/smart_reply_button_font_size"
+ android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
+ android:textColor="@color/smart_reply_button_text"
+ android:drawablePadding="@dimen/smart_action_button_icon_padding"
+ android:textStyle="normal"
+ android:ellipsize="none"/>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 07628c6..0997c5b1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -881,6 +881,7 @@
<dimen name="smart_reply_button_stroke_width">1dp</dimen>
<dimen name="smart_reply_button_font_size">14sp</dimen>
<dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
+ <dimen name="smart_action_button_icon_padding">10dp</dimen>
<!-- A reasonable upper bound for the height of the smart reply button. The measuring code
needs to start with a guess for the maximum size. Currently two-line smart reply buttons
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index c7910f9..46ed715b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -54,7 +54,6 @@
import android.util.Log;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
-
import android.view.RemoteAnimationTarget;
import com.android.internal.app.IVoiceInteractionManagerService;
@@ -480,4 +479,16 @@
return false;
}
}
+
+ /**
+ * Returns true if the system supports freeform multi-window.
+ */
+ public boolean supportsFreeformMultiWindow(Context context) {
+ final boolean freeformDevOption = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
+ return ActivityTaskManager.supportsMultiWindow(context)
+ && (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT)
+ || freeformDevOption);
+ }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
index 7154f53..a6b66e7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityOptionsCompat.java
@@ -18,6 +18,7 @@
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import android.app.ActivityOptions;
@@ -41,6 +42,15 @@
return options;
}
+ /**
+ * @return ActivityOptions for starting a task in freeform.
+ */
+ public static ActivityOptions makeFreeformOptions() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ return options;
+ }
+
public static ActivityOptions makeRemoteAnimation(
RemoteAnimationAdapterCompat remoteAnimationAdapter) {
return ActivityOptions.makeRemoteAnimation(remoteAnimationAdapter.getWrapped());
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/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 35ae899..5d33ffd 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -90,7 +90,7 @@
private float[] mRecentTemps = new float[MAX_RECENT_TEMPS];
private int mNumTemps;
private long mNextLogTime;
- private IThermalService mThermalService;
+ @VisibleForTesting IThermalService mThermalService;
@VisibleForTesting int mBatteryLevel = 100;
@VisibleForTesting int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
@@ -394,7 +394,7 @@
// Enable push notifications of throttling from vendor thermal
// management subsystem via thermalservice, in addition to our
// usual polling, to react to temperature jumps more quickly.
- IBinder b = ServiceManager.getService("thermalservice");
+ IBinder b = ServiceManager.getService(Context.THERMAL_SERVICE);
if (b != null) {
mThermalService = IThermalService.Stub.asInterface(b);
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 fa3fa5b..bb9a341 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,8 @@
import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.SmartReplyView;
+import java.util.List;
+
/**
* A frame layout containing the actual payload of the notification, including the contracted,
* expanded and heads up layout. This class is responsible for clipping the content and and
@@ -1285,38 +1287,88 @@
return;
}
- Notification notification = entry.notification.getNotification();
+ SmartRepliesAndActions smartRepliesAndActions = chooseSmartRepliesAndActions(
+ mSmartReplyConstants, entry);
- Pair<RemoteInput, Notification.Action> remoteInputActionPair =
- entry.notification.getNotification().findRemoteInputActionPair(false /*freeform */);
- Pair<RemoteInput, Notification.Action> freeformRemoteInputActionPair =
- notification.findRemoteInputActionPair(true /*freeform */);
+ applyRemoteInput(entry, smartRepliesAndActions.freeformRemoteInputActionPair != null);
+ applySmartReplyView(smartRepliesAndActions, entry);
+ }
- boolean enableAppGeneratedSmartReplies = (mSmartReplyConstants.isEnabled()
- && (!mSmartReplyConstants.requiresTargetingP()
+ /**
+ * Chose what smart replies and smart actions to display. App generated suggestions take
+ * precedence. So if the app provides any smart replies, we don't show any
+ * replies or actions generated by the NotificationAssistantService (NAS), and if the app
+ * provides any smart actions we also don't show any NAS-generated replies or actions.
+ */
+ @VisibleForTesting
+ static SmartRepliesAndActions chooseSmartRepliesAndActions(
+ SmartReplyConstants smartReplyConstants,
+ final NotificationData.Entry entry) {
+ boolean enableAppGeneratedSmartReplies = (smartReplyConstants.isEnabled()
+ && (!smartReplyConstants.requiresTargetingP()
|| entry.targetSdk >= Build.VERSION_CODES.P));
- RemoteInput remoteInputWithChoices = null;
- PendingIntent pendingIntentWithChoices= null;
- CharSequence[] choices = null;
- if (enableAppGeneratedSmartReplies
- && remoteInputActionPair != null
- && !ArrayUtils.isEmpty(remoteInputActionPair.first.getChoices())) {
- // app generated smart replies
- remoteInputWithChoices = remoteInputActionPair.first;
- pendingIntentWithChoices = remoteInputActionPair.second.actionIntent;
- choices = remoteInputActionPair.first.getChoices();
+ Notification notification = entry.notification.getNotification();
+ Pair<RemoteInput, Notification.Action> remoteInputActionPair =
+ notification.findRemoteInputActionPair(false /* freeform */);
+ Pair<RemoteInput, Notification.Action> freeformRemoteInputActionPair =
+ notification.findRemoteInputActionPair(true /* freeform */);
+
+ boolean appGeneratedSmartRepliesExist =
+ enableAppGeneratedSmartReplies
+ && remoteInputActionPair != null
+ && !ArrayUtils.isEmpty(remoteInputActionPair.first.getChoices());
+
+ List<Notification.Action> appGeneratedSmartActions = notification.getContextualActions();
+ boolean appGeneratedSmartActionsExist = !appGeneratedSmartActions.isEmpty();
+
+ if (appGeneratedSmartRepliesExist) {
+ return new SmartRepliesAndActions(remoteInputActionPair.first,
+ remoteInputActionPair.second.actionIntent,
+ remoteInputActionPair.first.getChoices(),
+ appGeneratedSmartActions,
+ freeformRemoteInputActionPair);
+ } else if (appGeneratedSmartActionsExist) {
+ return new SmartRepliesAndActions(null, null, null, appGeneratedSmartActions,
+ freeformRemoteInputActionPair);
} else if (!ArrayUtils.isEmpty(entry.smartReplies)
&& freeformRemoteInputActionPair != null
&& freeformRemoteInputActionPair.second.getAllowGeneratedReplies()) {
- // system generated smart replies
- remoteInputWithChoices = freeformRemoteInputActionPair.first;
- pendingIntentWithChoices = freeformRemoteInputActionPair.second.actionIntent;
- choices = entry.smartReplies;
+ // App didn't generate anything, use NAS-generated replies and actions
+ return new SmartRepliesAndActions(freeformRemoteInputActionPair.first,
+ freeformRemoteInputActionPair.second.actionIntent,
+ entry.smartReplies,
+ entry.systemGeneratedSmartActions,
+ freeformRemoteInputActionPair);
+ }
+ // App didn't generate anything, and there are no NAS-generated smart replies.
+ return new SmartRepliesAndActions(null, null, null, entry.systemGeneratedSmartActions,
+ freeformRemoteInputActionPair);
+ }
+
+ @VisibleForTesting
+ static class SmartRepliesAndActions {
+ public final RemoteInput remoteInputWithChoices;
+ public final PendingIntent pendingIntentForSmartReplies;
+ public final CharSequence[] smartReplies;
+ public final List<Notification.Action> smartActions;
+ public final Pair<RemoteInput, Notification.Action> freeformRemoteInputActionPair;
+
+ SmartRepliesAndActions(RemoteInput remoteInput, PendingIntent pendingIntent,
+ CharSequence[] choices, List<Notification.Action> smartActions,
+ Pair<RemoteInput, Notification.Action> freeformRemoteInputActionPair) {
+ this.remoteInputWithChoices = remoteInput;
+ this.pendingIntentForSmartReplies = pendingIntent;
+ this.smartReplies = choices;
+ this.smartActions = smartActions;
+ this.freeformRemoteInputActionPair = freeformRemoteInputActionPair;
}
- applyRemoteInput(entry, freeformRemoteInputActionPair != null);
- applySmartReplyView(remoteInputWithChoices, pendingIntentWithChoices, entry, choices);
+ boolean smartRepliesExist() {
+ return remoteInputWithChoices != null
+ && pendingIntentForSmartReplies != null
+ && !ArrayUtils.isEmpty(smartReplies);
+ }
}
private void applyRemoteInput(NotificationData.Entry entry, boolean hasFreeformRemoteInput) {
@@ -1418,28 +1470,32 @@
return null;
}
- private void applySmartReplyView(RemoteInput remoteInput, PendingIntent pendingIntent,
- NotificationData.Entry entry, CharSequence[] choices) {
+ private void applySmartReplyView(SmartRepliesAndActions smartRepliesAndActions,
+ NotificationData.Entry entry) {
if (mExpandedChild != null) {
mExpandedSmartReplyView =
- applySmartReplyView(mExpandedChild, remoteInput, pendingIntent, entry, choices);
- if (mExpandedSmartReplyView != null && remoteInput != null
- && choices != null && choices.length > 0) {
- mSmartReplyController.smartRepliesAdded(entry, choices.length);
+ applySmartReplyView(mExpandedChild, smartRepliesAndActions, entry);
+ if (mExpandedSmartReplyView != null
+ && smartRepliesAndActions.remoteInputWithChoices != null
+ && smartRepliesAndActions.smartReplies != null
+ && smartRepliesAndActions.smartReplies.length > 0) {
+ mSmartReplyController.smartRepliesAdded(entry,
+ smartRepliesAndActions.smartReplies.length);
}
}
}
- private SmartReplyView applySmartReplyView(
- View view, RemoteInput remoteInput, PendingIntent pendingIntent,
- NotificationData.Entry entry, CharSequence[] choices) {
+ private SmartReplyView applySmartReplyView(View view,
+ SmartRepliesAndActions smartRepliesAndActions, NotificationData.Entry entry) {
View smartReplyContainerCandidate = view.findViewById(
com.android.internal.R.id.smart_reply_container);
if (!(smartReplyContainerCandidate instanceof LinearLayout)) {
return null;
}
LinearLayout smartReplyContainer = (LinearLayout) smartReplyContainerCandidate;
- if (remoteInput == null || pendingIntent == null) {
+ // If there are no smart replies and no smart actions - early out.
+ if (!smartRepliesAndActions.smartRepliesExist()
+ && smartRepliesAndActions.smartActions.isEmpty()) {
smartReplyContainer.setVisibility(View.GONE);
return null;
}
@@ -1468,9 +1524,11 @@
}
}
if (smartReplyView != null) {
- smartReplyView.setRepliesFromRemoteInput(remoteInput, pendingIntent,
- mSmartReplyController, entry, smartReplyContainer, choices
- );
+ smartReplyView.resetSmartSuggestions(smartReplyContainer);
+ smartReplyView.addRepliesFromRemoteInput(smartRepliesAndActions.remoteInputWithChoices,
+ smartRepliesAndActions.pendingIntentForSmartReplies, mSmartReplyController,
+ entry, smartRepliesAndActions.smartReplies);
+ smartReplyView.addSmartActions(smartRepliesAndActions.smartActions);
smartReplyContainer.setVisibility(View.VISIBLE);
}
return smartReplyView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
index c16b28f..b6ff6fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationMenuRow.java
@@ -367,6 +367,9 @@
public void onSnapOpen() {
mMenuSnapped = true;
mMenuSnappedOnLeft = isMenuOnLeft();
+ if (mAlpha == 0f && mParent != null) {
+ fadeInMenu(mParent.getWidth());
+ }
if (mMenuListener != null) {
mMenuListener.onMenuShown(getParent());
}
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/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 42f1378..0186683 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -1,6 +1,7 @@
package com.android.systemui.statusbar.policy;
import android.annotation.ColorInt;
+import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
@@ -19,6 +20,7 @@
import android.text.method.TransformationMethod;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Size;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -30,6 +32,7 @@
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.NotificationData;
@@ -38,14 +41,15 @@
import java.text.BreakIterator;
import java.util.Comparator;
+import java.util.List;
import java.util.PriorityQueue;
-/** View which displays smart reply buttons in notifications. */
+/** View which displays smart reply and smart actions buttons in notifications. */
public class SmartReplyView extends ViewGroup {
private static final String TAG = "SmartReplyView";
- private static final int MEASURE_SPEC_ANY_WIDTH =
+ private static final int MEASURE_SPEC_ANY_LENGTH =
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
private static final Comparator<View> DECREASING_MEASURED_WIDTH_WITHOUT_PADDING_COMPARATOR =
@@ -98,6 +102,8 @@
private final int mStrokeWidth;
private final double mMinStrokeContrast;
+ private ActivityStarter mActivityStarter;
+
public SmartReplyView(Context context, AttributeSet attrs) {
super(context, attrs);
mConstants = Dependency.get(SmartReplyConstants.class);
@@ -168,13 +174,24 @@
Math.max(getChildCount(), 1), DECREASING_MEASURED_WIDTH_WITHOUT_PADDING_COMPARATOR);
}
- public void setRepliesFromRemoteInput(
- RemoteInput remoteInput, PendingIntent pendingIntent,
- SmartReplyController smartReplyController, NotificationData.Entry entry,
- View smartReplyContainer, CharSequence[] choices) {
- mSmartReplyContainer = smartReplyContainer;
+ /**
+ * Reset the smart suggestions view to allow adding new replies and actions.
+ */
+ public void resetSmartSuggestions(View newSmartReplyContainer) {
+ mSmartReplyContainer = newSmartReplyContainer;
removeAllViews();
mCurrentBackgroundColor = mDefaultBackgroundColor;
+ }
+
+ /**
+ * Add smart replies to this view, using the provided {@link RemoteInput} and
+ * {@link PendingIntent} to respond when the user taps a smart reply. Only the replies that fit
+ * into the notification are shown.
+ */
+ public void addRepliesFromRemoteInput(
+ RemoteInput remoteInput, PendingIntent pendingIntent,
+ SmartReplyController smartReplyController, NotificationData.Entry entry,
+ CharSequence[] choices) {
if (remoteInput != null && pendingIntent != null) {
if (choices != null) {
for (int i = 0; i < choices.length; ++i) {
@@ -188,6 +205,22 @@
reallocateCandidateButtonQueueForSqueezing();
}
+ /**
+ * Add smart actions to be shown next to smart replies. Only the actions that fit into the
+ * notification are shown.
+ */
+ public void addSmartActions(List<Notification.Action> smartActions) {
+ int numSmartActions = smartActions.size();
+ for (int n = 0; n < numSmartActions; n++) {
+ Notification.Action action = smartActions.get(n);
+ if (action.actionIntent != null) {
+ Button actionButton = inflateActionButton(getContext(), this, action);
+ addView(actionButton);
+ }
+ }
+ reallocateCandidateButtonQueueForSqueezing();
+ }
+
public static SmartReplyView inflate(Context context, ViewGroup root) {
return (SmartReplyView)
LayoutInflater.from(context).inflate(R.layout.smart_reply_view, root, false);
@@ -234,6 +267,48 @@
return b;
}
+ @VisibleForTesting
+ Button inflateActionButton(Context context, ViewGroup root, Notification.Action action) {
+ Button button = (Button) LayoutInflater.from(context).inflate(
+ R.layout.smart_action_button, root, false);
+ button.setText(action.title);
+
+ Drawable iconDrawable = action.getIcon().loadDrawable(context);
+ // Add the action icon to the Smart Action button.
+ Size newIconSize = calculateIconSizeFromSingleLineButton(context, root,
+ new Size(iconDrawable.getIntrinsicWidth(), iconDrawable.getIntrinsicHeight()));
+ iconDrawable.setBounds(0, 0, newIconSize.getWidth(), newIconSize.getHeight());
+ button.setCompoundDrawables(iconDrawable, null, null, null);
+
+ button.setOnClickListener(view ->
+ getActivityStarter().startPendingIntentDismissingKeyguard(action.actionIntent));
+
+ // TODO(b/119010281): handle accessibility
+
+ return button;
+ }
+
+ private static Size calculateIconSizeFromSingleLineButton(Context context, ViewGroup root,
+ Size originalIconSize) {
+ Button button = (Button) LayoutInflater.from(context).inflate(
+ R.layout.smart_action_button, root, false);
+ // Add simple text here to ensure the button displays one line of text.
+ button.setText("a");
+ return calculateIconSizeFromButtonHeight(button, originalIconSize);
+ }
+
+ // Given a button with text on a single line - we want to add an icon to that button. This
+ // method calculates the icon height to use to avoid making the button grow in height.
+ private static Size calculateIconSizeFromButtonHeight(Button button, Size originalIconSize) {
+ // A completely permissive measure spec should make the button text single-line.
+ button.measure(MEASURE_SPEC_ANY_LENGTH, MEASURE_SPEC_ANY_LENGTH);
+ int buttonHeight = button.getMeasuredHeight();
+ int newIconHeight = buttonHeight / 2;
+ int newIconWidth = (int) (originalIconSize.getWidth()
+ * ((double) newIconHeight) / originalIconSize.getHeight());
+ return new Size(newIconWidth, newIconHeight);
+ }
+
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(mContext, attrs);
@@ -277,7 +352,7 @@
child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(),
buttonPaddingHorizontal, child.getPaddingBottom());
- child.measure(MEASURE_SPEC_ANY_WIDTH, heightMeasureSpec);
+ child.measure(MEASURE_SPEC_ANY_LENGTH, heightMeasureSpec);
final int lineCount = ((Button) child).getLineCount();
if (lineCount < 1 || lineCount > 2) {
@@ -437,6 +512,18 @@
return (int) Math.ceil(optimalTextWidth);
}
+ /**
+ * Returns the combined width of the left drawable (the action icon) and the padding between the
+ * drawable and the button text.
+ */
+ private int getLeftCompoundDrawableWidthWithPadding(Button button) {
+ Drawable[] drawables = button.getCompoundDrawables();
+ Drawable leftDrawable = drawables[0];
+ if (leftDrawable == null) return 0;
+
+ return leftDrawable.getBounds().width() + button.getCompoundDrawablePadding();
+ }
+
private int squeezeButtonToTextWidth(Button button, int heightMeasureSpec, int textWidth) {
int oldWidth = button.getMeasuredWidth();
if (button.getPaddingLeft() != mDoubleLineButtonPaddingHorizontal) {
@@ -449,7 +536,8 @@
button.setPadding(mDoubleLineButtonPaddingHorizontal, button.getPaddingTop(),
mDoubleLineButtonPaddingHorizontal, button.getPaddingBottom());
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
- 2 * mDoubleLineButtonPaddingHorizontal + textWidth, MeasureSpec.AT_MOST);
+ 2 * mDoubleLineButtonPaddingHorizontal + textWidth
+ + getLeftCompoundDrawableWidthWithPadding(button), MeasureSpec.AT_MOST);
button.measure(widthMeasureSpec, heightMeasureSpec);
final int newWidth = button.getMeasuredWidth();
@@ -607,6 +695,13 @@
button.setTextColor(textColor);
}
+ private ActivityStarter getActivityStarter() {
+ if (mActivityStarter == null) {
+ mActivityStarter = Dependency.get(ActivityStarter.class);
+ }
+ return mActivityStarter;
+ }
+
@VisibleForTesting
static class LayoutParams extends ViewGroup.LayoutParams {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index b44630a..221cbe9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -32,12 +32,13 @@
import android.content.Intent;
import android.os.BatteryManager;
import android.os.HardwarePropertiesManager;
+import android.os.IThermalService;
import android.os.PowerManager;
import android.provider.Settings;
+import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.testing.TestableResources;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.settingslib.utils.ThreadUtils;
import com.android.systemui.R;
@@ -45,15 +46,16 @@
import com.android.systemui.power.PowerUI.WarningsUI;
import com.android.systemui.statusbar.phone.StatusBar;
-import java.time.Duration;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.time.Duration;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
@@ -76,6 +78,7 @@
private PowerUI mPowerUI;
private EnhancedEstimates mEnhancedEstimates;
@Mock private PowerManager mPowerManager;
+ @Mock private IThermalService mThermalServiceMock;
@Before
public void setup() {
@@ -541,5 +544,6 @@
mPowerUI = new PowerUI();
mPowerUI.mContext = mContext;
mPowerUI.mComponents = mContext.getComponents();
+ mPowerUI.mThermalService = mThermalServiceMock;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
index f59bfae..b3b45eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationDataTest.java
@@ -39,6 +39,7 @@
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.PendingIntent;
+import android.app.Person;
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
@@ -421,6 +422,33 @@
assertEquals(snoozeCriterions, entry.snoozeCriteria);
}
+ @Test
+ public void notificationDataEntry_testIsLastMessageFromReply() {
+ Person.Builder person = new Person.Builder()
+ .setName("name")
+ .setKey("abc")
+ .setUri("uri")
+ .setBot(true);
+
+ // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build());
+ Bundle[] messagesBundle = new Bundle[]{ new Notification.MessagingStyle.Message(
+ "text", 0, person.build()).toBundle() };
+ bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
+
+ Notification notification = new Notification.Builder(mContext, "test")
+ .addExtras(bundle)
+ .build();
+ StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+ notification, mContext.getUser(), "", 0);
+
+ NotificationData.Entry entry = new NotificationData.Entry(sbn);
+ entry.setHasSentReply();
+
+ assertTrue(entry.isLastMessageFromReply());
+ }
+
private void initStatusBarNotification(boolean allowDuringSetup) {
Bundle bundle = new Bundle();
bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
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 c189c95..a6725b8 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
@@ -16,6 +16,11 @@
package com.android.systemui.statusbar.notification.row;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.Mockito.doNothing;
@@ -28,29 +33,62 @@
import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.RemoteInput;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.service.notification.StatusBarNotification;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArraySet;
+import android.util.Pair;
import android.view.NotificationHeaderView;
import android.view.View;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class NotificationContentViewTest extends SysuiTestCase {
+ private static final String TEST_ACTION = "com.android.SMART_REPLY_VIEW_ACTION";
+
NotificationContentView mView;
+ @Mock
+ SmartReplyConstants mSmartReplyConstants;
+ @Mock
+ StatusBarNotification mStatusBarNotification;
+ @Mock
+ Notification mNotification;
+ NotificationData.Entry mEntry;
+ @Mock
+ RemoteInput mRemoteInput;
+ @Mock
+ RemoteInput mFreeFormRemoteInput;
+
+ private Icon mActionIcon;
+
+
@Before
@UiThreadTest
public void setup() {
+ MockitoAnnotations.initMocks(this);
+
mView = new NotificationContentView(mContext, null);
ExpandableNotificationRow row = new ExpandableNotificationRow(mContext, null);
ExpandableNotificationRow mockRow = spy(row);
@@ -67,6 +105,12 @@
mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
+
+ // Smart replies
+ when(mStatusBarNotification.getNotification()).thenReturn(mNotification);
+ mEntry = new NotificationData.Entry(mStatusBarNotification);
+ when(mSmartReplyConstants.isEnabled()).thenReturn(true);
+ mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
}
private View createViewWithHeight(int height) {
@@ -82,7 +126,7 @@
mView.setDark(true, false, 0);
mView.setDark(false, true, 0);
mView.setHeadsUpAnimatingAway(true);
- Assert.assertFalse(mView.isAnimatingVisibleType());
+ assertFalse(mView.isAnimatingVisibleType());
}
@Test
@@ -115,4 +159,161 @@
verify(mockAmbient, never()).showAppOpsIcons(ops);
verify(mockHeadsUp, times(1)).showAppOpsIcons(any());
}
+
+ private void setupAppGeneratedReplies(CharSequence[] smartReplyTitles) {
+ Notification.Action freeFormAction =
+ new Notification.Action.Builder(null, "Freeform Test Action", null).build();
+ setupAppGeneratedReplies(smartReplyTitles, freeFormAction);
+ }
+
+ private void setupAppGeneratedReplies(
+ CharSequence[] smartReplyTitles,
+ Notification.Action freeFormRemoteInputAction) {
+ Notification.Action action =
+ new Notification.Action.Builder(null, "Test Action", null).build();
+ when(mRemoteInput.getChoices()).thenReturn(smartReplyTitles);
+ Pair<RemoteInput, Notification.Action> remoteInputActionPair =
+ Pair.create(mRemoteInput, action);
+ when(mNotification.findRemoteInputActionPair(false)).thenReturn(remoteInputActionPair);
+
+ Pair<RemoteInput, Notification.Action> freeFormRemoteInputActionPair =
+ Pair.create(mFreeFormRemoteInput, freeFormRemoteInputAction);
+ when(mNotification.findRemoteInputActionPair(true)).thenReturn(
+ freeFormRemoteInputActionPair);
+ }
+
+ @Test
+ public void chooseSmartRepliesAndActions_smartRepliesOff_noAppGeneratedSmartReplies() {
+ setupAppGeneratedReplies(new String[] {"Reply1", "Reply2"});
+ when(mSmartReplyConstants.isEnabled()).thenReturn(false);
+
+ NotificationContentView.SmartRepliesAndActions repliesAndActions =
+ NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+
+ assertFalse(repliesAndActions.smartRepliesExist());
+ }
+
+ @Test
+ public void chooseSmartRepliesAndActions_appGeneratedSmartReplies() {
+ CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
+ setupAppGeneratedReplies(smartReplies);
+ when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
+
+ NotificationContentView.SmartRepliesAndActions repliesAndActions =
+ NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+
+ assertThat(repliesAndActions.smartReplies, equalTo(smartReplies));
+ }
+
+ @Test
+ public void chooseSmartRepliesAndActions_appGeneratedSmartRepliesAndActions() {
+ CharSequence[] smartReplies = new String[] {"Reply1", "Reply2"};
+ setupAppGeneratedReplies(smartReplies);
+ when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
+
+ List<Notification.Action> smartActions =
+ createActions(new String[] {"Test Action 1", "Test Action 2"});
+ when(mNotification.getContextualActions()).thenReturn(smartActions);
+
+ NotificationContentView.SmartRepliesAndActions repliesAndActions =
+ NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+
+ assertThat(repliesAndActions.smartReplies, equalTo(smartReplies));
+ assertThat(repliesAndActions.smartActions, equalTo(smartActions));
+ }
+
+ @Test
+ public void chooseSmartRepliesAndActions_sysGeneratedSmartReplies() {
+ Notification.Action freeFormAction = createActionBuilder("Freeform Action")
+ .setAllowGeneratedReplies(true)
+ .build();
+ // Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
+ // replies.
+ setupAppGeneratedReplies(null, freeFormAction);
+
+ mEntry.smartReplies =
+ new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
+ NotificationContentView.SmartRepliesAndActions repliesAndActions =
+ NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+
+ assertThat(repliesAndActions.smartReplies, equalTo(mEntry.smartReplies));
+ assertThat(repliesAndActions.smartActions, is(empty()));
+ }
+
+ @Test
+ public void chooseSmartRepliesAndActions_noSysGeneratedSmartRepliesIfNotAllowed() {
+ Notification.Action freeFormAction = createActionBuilder("Freeform Action")
+ .setAllowGeneratedReplies(false)
+ .build();
+ // Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
+ // replies.
+ setupAppGeneratedReplies(null, freeFormAction);
+
+ mEntry.smartReplies =
+ new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
+ NotificationContentView.SmartRepliesAndActions repliesAndActions =
+ NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+
+ assertThat(repliesAndActions.smartReplies, equalTo(null));
+ assertThat(repliesAndActions.smartActions, is(empty()));
+ }
+
+ @Test
+ public void chooseSmartRepliesAndActions_sysGeneratedSmartActions() {
+ // Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
+ // actions.
+ setupAppGeneratedReplies(null);
+
+ 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, equalTo(mEntry.systemGeneratedSmartActions));
+ }
+
+ @Test
+ public void chooseSmartRepliesAndActions_appGenPreferredOverSysGen() {
+ Notification.Action freeFormAction = createActionBuilder("Freeform Action")
+ .setAllowGeneratedReplies(true)
+ .build();
+ CharSequence[] appGenSmartReplies = new String[] {"Reply1", "Reply2"};
+ // Pass a null-array as app-generated smart replies, so that we use NAS-generated smart
+ // replies.
+ setupAppGeneratedReplies(appGenSmartReplies, freeFormAction);
+ when(mSmartReplyConstants.requiresTargetingP()).thenReturn(false);
+
+ List<Notification.Action> appGenSmartActions =
+ createActions(new String[] {"Test Action 1", "Test Action 2"});
+ when(mNotification.getContextualActions()).thenReturn(appGenSmartActions);
+
+ mEntry.smartReplies = new String[] {"Sys Smart Reply 1", "Sys Smart Reply 2"};
+ mEntry.systemGeneratedSmartActions =
+ createActions(new String[] {"Sys Smart Action 1", "Sys Smart Action 2"});
+
+ NotificationContentView.SmartRepliesAndActions repliesAndActions =
+ NotificationContentView.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+
+ assertThat(repliesAndActions.smartReplies, equalTo(appGenSmartReplies));
+ assertThat(repliesAndActions.smartActions, equalTo(appGenSmartActions));
+ }
+
+ private Notification.Action.Builder createActionBuilder(String actionTitle) {
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
+ new Intent(TEST_ACTION), 0);
+ return new Notification.Action.Builder(mActionIcon, actionTitle, pendingIntent);
+ }
+
+ private Notification.Action createAction(String actionTitle) {
+ return createActionBuilder(actionTitle).build();
+ }
+
+ private List<Notification.Action> createActions(String[] actionTitles) {
+ List<Notification.Action> actions = new ArrayList<>();
+ for (String title : actionTitles) {
+ actions.add(createAction(title));
+ }
+ return actions;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 4534ebe..9e659c8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -22,7 +22,9 @@
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -32,6 +34,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.service.notification.StatusBarNotification;
import android.support.test.filters.SmallTest;
import android.testing.AndroidTestingRunner;
@@ -41,14 +45,14 @@
import android.widget.Button;
import android.widget.LinearLayout;
-import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.statusbar.SmartReplyController;
+import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
-
-import java.util.concurrent.atomic.AtomicReference;
+import com.android.systemui.statusbar.phone.ShadeController;
import org.junit.After;
import org.junit.Before;
@@ -57,6 +61,10 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
@@ -67,6 +75,10 @@
private static final String[] TEST_CHOICES = new String[]{"Hello", "What's up?", "I'm here"};
private static final String TEST_NOTIFICATION_KEY = "akey";
+ private static final String[] TEST_ACTION_TITLES = new String[]{
+ "First action", "Open something", "Action"
+ };
+
private static final int WIDTH_SPEC = MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY);
private static final int HEIGHT_SPEC = MeasureSpec.makeMeasureSpec(400, MeasureSpec.AT_MOST);
@@ -74,6 +86,8 @@
private SmartReplyView mView;
private View mContainer;
+ private Icon mActionIcon;
+
private int mSingleLinePaddingHorizontal;
private int mDoubleLinePaddingHorizontal;
private int mSpacing;
@@ -82,12 +96,16 @@
private NotificationData.Entry mEntry;
private Notification mNotification;
+ @Mock ActivityStarter mActivityStarter;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mReceiver = new BlockingQueueIntentReceiver();
mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION));
mDependency.get(KeyguardDismissUtil.class).setDismissHandler(action -> action.onDismiss());
+ mDependency.injectMockDependency(ShadeController.class);
+ mDependency.injectTestDependency(ActivityStarter.class, mActivityStarter);
mContainer = new View(mContext, null);
mView = SmartReplyView.inflate(mContext, null);
@@ -108,6 +126,8 @@
when(sbn.getNotification()).thenReturn(mNotification);
when(sbn.getKey()).thenReturn(TEST_NOTIFICATION_KEY);
mEntry = new NotificationData.Entry(sbn);
+
+ mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
}
@After
@@ -117,7 +137,7 @@
@Test
public void testSendSmartReply_intentContainsResultsAndSource() throws InterruptedException {
- setRepliesFromRemoteInput(TEST_CHOICES);
+ setSmartReplies(TEST_CHOICES);
mView.getChildAt(2).performClick();
@@ -130,7 +150,7 @@
@Test
public void testSendSmartReply_keyguardCancelled() throws InterruptedException {
mDependency.get(KeyguardDismissUtil.class).setDismissHandler(action -> {});
- setRepliesFromRemoteInput(TEST_CHOICES);
+ setSmartReplies(TEST_CHOICES);
mView.getChildAt(2).performClick();
@@ -141,7 +161,7 @@
public void testSendSmartReply_waitsForKeyguard() throws InterruptedException {
AtomicReference<OnDismissAction> actionRef = new AtomicReference<>();
mDependency.get(KeyguardDismissUtil.class).setDismissHandler(actionRef::set);
- setRepliesFromRemoteInput(TEST_CHOICES);
+ setSmartReplies(TEST_CHOICES);
mView.getChildAt(2).performClick();
@@ -159,7 +179,7 @@
@Test
public void testSendSmartReply_controllerCalled() {
- setRepliesFromRemoteInput(TEST_CHOICES);
+ setSmartReplies(TEST_CHOICES);
mView.getChildAt(2).performClick();
verify(mLogger).smartReplySent(mEntry, 2, TEST_CHOICES[2]);
}
@@ -167,7 +187,7 @@
@Test
public void testSendSmartReply_hidesContainer() {
mContainer.setVisibility(View.VISIBLE);
- setRepliesFromRemoteInput(TEST_CHOICES);
+ setSmartReplies(TEST_CHOICES);
mView.getChildAt(0).performClick();
assertEquals(View.GONE, mContainer.getVisibility());
}
@@ -198,7 +218,7 @@
ViewGroup expectedView = buildExpectedView(choices, 1);
expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- setRepliesFromRemoteInput(choices);
+ setSmartReplies(choices);
mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
assertEqualMeasures(expectedView, mView);
@@ -217,7 +237,7 @@
expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
10 + expectedView.getMeasuredHeight());
- setRepliesFromRemoteInput(choices);
+ setSmartReplies(choices);
mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
@@ -235,7 +255,7 @@
ViewGroup expectedView = buildExpectedView(choices, 2);
expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- setRepliesFromRemoteInput(choices);
+ setSmartReplies(choices);
mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
assertEqualMeasures(expectedView, mView);
@@ -254,7 +274,7 @@
expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
10 + expectedView.getMeasuredHeight());
- setRepliesFromRemoteInput(choices);
+ setSmartReplies(choices);
mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
@@ -273,7 +293,7 @@
ViewGroup expectedView = buildExpectedView(new CharSequence[]{"Hi", "Bye"}, 1);
expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- setRepliesFromRemoteInput(choices);
+ setSmartReplies(choices);
mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
assertEqualMeasures(expectedView, mView);
@@ -293,7 +313,7 @@
expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
10 + expectedView.getMeasuredHeight());
- setRepliesFromRemoteInput(choices);
+ setSmartReplies(choices);
mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
@@ -313,7 +333,7 @@
new CharSequence[]{"Short", "Short", "Looooooong \nreplyyyyy"}, 2);
expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- setRepliesFromRemoteInput(choices);
+ setSmartReplies(choices);
mView.measure(
MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
MeasureSpec.UNSPECIFIED);
@@ -335,7 +355,7 @@
expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
10 + expectedView.getMeasuredHeight());
- setRepliesFromRemoteInput(choices);
+ setSmartReplies(choices);
mView.measure(
MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
MeasureSpec.UNSPECIFIED);
@@ -359,7 +379,7 @@
expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
10 + expectedView.getMeasuredHeight());
- setRepliesFromRemoteInput(choices);
+ setSmartReplies(choices);
mView.measure(
MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
MeasureSpec.UNSPECIFIED);
@@ -371,15 +391,45 @@
assertReplyButtonHidden(mView.getChildAt(2));
}
- private void setRepliesFromRemoteInput(CharSequence[] choices) {
+ private void setSmartReplies(CharSequence[] choices) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
new Intent(TEST_ACTION), 0);
RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).setChoices(choices).build();
- mView.setRepliesFromRemoteInput(input, pendingIntent, mLogger, mEntry, mContainer, choices);
+ mView.resetSmartSuggestions(mContainer);
+ mView.addRepliesFromRemoteInput(input, pendingIntent, mLogger, mEntry, choices);
+ }
+
+ private Notification.Action createAction(String actionTitle) {
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
+ new Intent(TEST_ACTION), 0);
+ return new Notification.Action.Builder(mActionIcon, actionTitle, pendingIntent).build();
+ }
+
+ private List<Notification.Action> createActions(String[] actionTitles) {
+ List<Notification.Action> actions = new ArrayList<>();
+ for (String title : actionTitles) {
+ actions.add(createAction(title));
+ }
+ return actions;
+ }
+
+ private void setSmartActions(String[] actionTitles) {
+ mView.resetSmartSuggestions(mContainer);
+ mView.addSmartActions(createActions(actionTitles));
+ }
+
+ private void setSmartRepliesAndActions(CharSequence[] choices, String[] actionTitles) {
+ setSmartReplies(choices);
+ mView.addSmartActions(createActions(actionTitles));
+ }
+
+ private ViewGroup buildExpectedView(CharSequence[] choices, int lineCount) {
+ return buildExpectedView(choices, lineCount, new ArrayList<>());
}
/** Builds a {@link ViewGroup} whose measures and layout mirror a {@link SmartReplyView}. */
- private ViewGroup buildExpectedView(CharSequence[] choices, int lineCount) {
+ private ViewGroup buildExpectedView(
+ CharSequence[] choices, int lineCount, List<Notification.Action> actions) {
LinearLayout layout = new LinearLayout(mContext);
layout.setOrientation(LinearLayout.HORIZONTAL);
@@ -401,6 +451,7 @@
return null;
}
+ // Add smart replies
Button previous = null;
for (int i = 0; i < choices.length; ++i) {
Button current = mView.inflateReplyButton(mContext, mView, i, choices[i],
@@ -420,6 +471,24 @@
previous = current;
}
+ // Add smart actions
+ for (int i = 0; i < actions.size(); ++i) {
+ Button current = inflateActionButton(actions.get(i));
+ current.setPadding(paddingHorizontal, current.getPaddingTop(), paddingHorizontal,
+ current.getPaddingBottom());
+ if (previous != null) {
+ ViewGroup.MarginLayoutParams lp =
+ (ViewGroup.MarginLayoutParams) previous.getLayoutParams();
+ if (isRtl) {
+ lp.leftMargin = mSpacing;
+ } else {
+ lp.rightMargin = mSpacing;
+ }
+ }
+ layout.addView(current);
+ previous = current;
+ }
+
return layout;
}
@@ -455,4 +524,255 @@
assertEquals(expected.getPaddingRight(), actual.getPaddingRight());
assertEquals(expected.getPaddingBottom(), actual.getPaddingBottom());
}
+
+
+ // =============================================================================================
+ // ============================= Smart Action tests ============================================
+ // =============================================================================================
+
+ @Test
+ public void testTapSmartAction_waitsForKeyguard() throws InterruptedException {
+ setSmartActions(TEST_ACTION_TITLES);
+
+ mView.getChildAt(2).performClick();
+
+ verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any());
+ }
+
+ @Test
+ public void testMeasure_shortSmartActions() {
+ String[] actions = new String[] {"Hi", "Hello", "Bye"};
+ // All choices should be displayed as SINGLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(new CharSequence[0], 1, createActions(actions));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setSmartActions(actions);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ assertEqualMeasures(expectedView, mView);
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testLayout_shortSmartActions() {
+ String[] actions = new String[] {"Hi", "Hello", "Bye"};
+ // All choices should be displayed as SINGLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(new CharSequence[0], 1, createActions(actions));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
+ 10 + expectedView.getMeasuredHeight());
+
+ setSmartActions(actions);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
+
+ assertEqualLayouts(expectedView, mView);
+ assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertEqualLayouts(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testMeasure_smartActionWithTwoLines() {
+ String[] actions = new String[] {"Hi", "Hello\neveryone", "Bye"};
+
+ // All actions should be displayed as DOUBLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(new CharSequence[0], 2, createActions(actions));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setSmartActions(actions);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ assertEqualMeasures(expectedView, mView);
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testLayout_smartActionWithTwoLines() {
+ String[] actions = new String[] {"Hi", "Hello\neveryone", "Bye"};
+
+ // All actions should be displayed as DOUBLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(new CharSequence[0], 2, createActions(actions));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
+ 10 + expectedView.getMeasuredHeight());
+
+ setSmartActions(actions);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
+
+ assertEqualLayouts(expectedView, mView);
+ assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertEqualLayouts(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testMeasure_smartActionWithThreeLines() {
+ String[] actions = new String[] {"Hi", "Hello\nevery\nbody", "Bye"};
+
+ // The action with three lines should NOT be displayed. All other actions should be
+ // displayed as SINGLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(new CharSequence[0], 1,
+ createActions(new String[]{"Hi", "Bye"}));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setSmartActions(actions);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ assertEqualMeasures(expectedView, mView);
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonHidden(mView.getChildAt(1));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testLayout_smartActionWithThreeLines() {
+ String[] actions = new String[] {"Hi", "Hello\nevery\nbody", "Bye"};
+
+ // The action with three lines should NOT be displayed. All other actions should be
+ // displayed as SINGLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(new CharSequence[0], 1,
+ createActions(new String[]{"Hi", "Bye"}));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
+ 10 + expectedView.getMeasuredHeight());
+
+ setSmartActions(actions);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
+
+ assertEqualLayouts(expectedView, mView);
+ assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0));
+ // We don't care about mView.getChildAt(1)'s layout because it's hidden (see
+ // testMeasure_smartActionWithThreeLines).
+ assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testMeasure_squeezeLongestSmartAction() {
+ String[] actions = new String[] {"Short", "Short", "Looooooong replyyyyy"};
+
+ // All actions should be displayed as DOUBLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(new CharSequence[0], 2,
+ createActions(new String[] {"Short", "Short", "Looooooong \nreplyyyyy"}));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setSmartActions(actions);
+ mView.measure(
+ MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.UNSPECIFIED);
+
+ assertEqualMeasures(expectedView, mView);
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testLayout_squeezeLongestSmartAction() {
+ String[] actions = new String[] {"Short", "Short", "Looooooong replyyyyy"};
+
+ // All actions should be displayed as DOUBLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(new CharSequence[0], 2,
+ createActions(new String[] {"Short", "Short", "Looooooong \nreplyyyyy"}));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
+ 10 + expectedView.getMeasuredHeight());
+
+ setSmartActions(actions);
+ mView.measure(
+ MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.UNSPECIFIED);
+ mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
+
+ assertEqualLayouts(expectedView, mView);
+ assertEqualLayouts(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertEqualLayouts(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertEqualLayouts(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testMeasure_dropLongestSmartAction() {
+ String[] actions = new String[] {"Short", "Short", "LooooooongUnbreakableReplyyyyy"};
+
+ // Short actions should be shown as single line views
+ ViewGroup expectedView = buildExpectedView(
+ new CharSequence[0], 1, createActions(new String[] {"Short", "Short"}));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ expectedView.layout(10, 10, 10 + expectedView.getMeasuredWidth(),
+ 10 + expectedView.getMeasuredHeight());
+
+ setSmartActions(actions);
+ mView.measure(
+ MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.UNSPECIFIED);
+ mView.layout(10, 10, 10 + mView.getMeasuredWidth(), 10 + mView.getMeasuredHeight());
+
+ assertEqualLayouts(expectedView, mView);
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertReplyButtonHidden(mView.getChildAt(2));
+ }
+
+ private Button inflateActionButton(Notification.Action action) {
+ return mView.inflateActionButton(getContext(), mView, action);
+ }
+
+ @Test
+ public void testInflateActionButton_smartActionIconSingleLineSizeForTwoLineButton() {
+ // Ensure smart action icons are the same size regardless of the number of text rows in the
+ // button.
+ Button singleLineButton = inflateActionButton(createAction("One line"));
+ Button doubleLineButton = inflateActionButton(createAction("Two\nlines"));
+ Drawable singleLineDrawable = singleLineButton.getCompoundDrawables()[0]; // left drawable
+ Drawable doubleLineDrawable = doubleLineButton.getCompoundDrawables()[0]; // left drawable
+ assertEquals(singleLineDrawable.getBounds().width(),
+ doubleLineDrawable.getBounds().width());
+ assertEquals(singleLineDrawable.getBounds().height(),
+ doubleLineDrawable.getBounds().height());
+ }
+
+ @Test
+ public void testMeasure_shortChoicesAndActions() {
+ CharSequence[] choices = new String[] {"Hi", "Hello"};
+ String[] actions = new String[] {"Bye"};
+ // All choices should be displayed as SINGLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(choices, 1, createActions(actions));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setSmartRepliesAndActions(choices, actions);
+ mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ assertEqualMeasures(expectedView, mView);
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
+
+ @Test
+ public void testMeasure_choicesAndActionsSqueezeLongestAction() {
+ CharSequence[] choices = new String[] {"Short", "Short"};
+ String[] actions = new String[] {"Looooooong replyyyyy"};
+
+ // All actions should be displayed as DOUBLE-line smart action buttons.
+ ViewGroup expectedView = buildExpectedView(choices, 2,
+ createActions(new String[] {"Looooooong \nreplyyyyy"}));
+ expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+ setSmartRepliesAndActions(choices, actions);
+ mView.measure(
+ MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
+ MeasureSpec.UNSPECIFIED);
+
+ assertEqualMeasures(expectedView, mView);
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1));
+ assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2));
+ }
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 7621ada..e4b4bc5 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1388,6 +1388,7 @@
app = mPackageManager.getApplicationInfo(pkg.packageName,
PackageManager.GET_SHARED_LIBRARY_FILES);
pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
+ pkg.applicationInfo.sharedLibraryInfos = app.sharedLibraryInfos;
}
} catch (NameNotFoundException e) {
packages.remove(a);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index c660cc6..a19e928 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1702,8 +1702,11 @@
s.app.whitelistManager = true;
}
// This could have made the service more important.
- mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities()
- || s.app.treatLikeActivity, b.client);
+ mAm.updateLruProcessLocked(s.app,
+ (callerApp.hasActivitiesOrRecentTasks() && s.app.hasClientActivities())
+ || (callerApp.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP
+ && (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0),
+ b.client);
mAm.updateOomAdjLocked(s.app, true);
}
@@ -1787,6 +1790,32 @@
}
}
+ void updateServiceGroupLocked(IServiceConnection connection, int group, int importance) {
+ final IBinder binder = connection.asBinder();
+ if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "updateServiceGroup: conn=" + binder);
+ final ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
+ if (clist == null) {
+ throw new IllegalArgumentException("Could not find connection for "
+ + connection.asBinder());
+ }
+ for (int i = clist.size() - 1; i >= 0; i--) {
+ final ConnectionRecord crec = clist.get(i);
+ final ServiceRecord srec = crec.binding.service;
+ if (srec != null && srec.app != null
+ && (srec.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {
+ if (group > 0) {
+ srec.app.connectionService = srec;
+ srec.app.connectionGroup = group;
+ srec.app.connectionImportance = importance;
+ } else {
+ srec.app.connectionService = null;
+ srec.app.connectionGroup = 0;
+ srec.app.connectionImportance = 0;
+ }
+ }
+ }
+ }
+
boolean unbindServiceLocked(IServiceConnection connection) {
IBinder binder = connection.asBinder();
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 4e417ba..7e9e83c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9207,26 +9207,33 @@
}
dumpAssociationsLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
}
+ if (dumpPackage == null) {
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ mOomAdjProfiler.dump(pw);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ dumpBinderProxies(pw);
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ dumpLmkLocked(pw);
+ }
+ pw.println();
+ if (dumpAll) {
+ pw.println("-------------------------------------------------------------------------------");
+ }
+ dumpLruLocked(pw, dumpPackage);
pw.println();
if (dumpAll) {
pw.println("-------------------------------------------------------------------------------");
}
dumpProcessesLocked(fd, pw, args, opti, dumpAll, dumpPackage, dumpAppId);
- pw.println();
- if (dumpAll) {
- pw.println("-------------------------------------------------------------------------------");
- }
- mOomAdjProfiler.dump(pw);
- pw.println();
- if (dumpAll) {
- pw.println("-------------------------------------------------------------------------------");
- }
- dumpBinderProxies(pw);
- pw.println();
- if (dumpAll) {
- pw.println("-------------------------------------------------------------------------------");
- }
- dumpLmkLocked(pw);
}
}
@@ -9421,6 +9428,10 @@
synchronized (this) {
dumpLmkLocked(pw);
}
+ } else if ("lru".equals(cmd)) {
+ synchronized (this) {
+ dumpLruLocked(pw, null);
+ }
} else if ("permissions".equals(cmd) || "perm".equals(cmd)) {
synchronized (this) {
dumpPermissionsLocked(fd, pw, args, opti, true, null);
@@ -9698,17 +9709,102 @@
}
pw.println();
}
- pw.println();
return true;
}
return false;
}
void dumpBinderProxies(PrintWriter pw) {
+ pw.println("ACTIVITY MANAGER BINDER PROXY STATE (dumpsys activity binder-proxies)");
dumpBinderProxyInterfaceCounts(pw,
- "Top proxy interface names held by SYSTEM");
+ " Top proxy interface names held by SYSTEM");
dumpBinderProxiesCounts(pw,
- "Counts of Binder Proxies held by SYSTEM");
+ " Counts of Binder Proxies held by SYSTEM");
+ }
+
+ void dumpLruEntryLocked(PrintWriter pw, int index, ProcessRecord proc) {
+ pw.print(" #");
+ pw.print(index);
+ pw.print(": ");
+ pw.print(ProcessList.makeOomAdjString(proc.setAdj));
+ pw.print(" ");
+ pw.print(ProcessList.makeProcStateString(proc.getCurProcState()));
+ pw.print(" ");
+ pw.print(proc.toShortString());
+ pw.print(" ");
+ if (proc.hasActivitiesOrRecentTasks() || proc.hasClientActivities()
+ || proc.treatLikeActivity) {
+ pw.print(" activity=");
+ boolean printed = false;
+ if (proc.hasActivities()) {
+ pw.print("activities");
+ printed = true;
+ }
+ if (proc.hasRecentTasks()) {
+ if (printed) {
+ pw.print("|");
+ }
+ pw.print("recents");
+ printed = true;
+ }
+ if (proc.hasClientActivities()) {
+ if (printed) {
+ pw.print("|");
+ }
+ pw.print("client");
+ printed = true;
+ }
+ if (proc.treatLikeActivity) {
+ if (printed) {
+ pw.print("|");
+ }
+ pw.print("treated");
+ }
+ }
+ pw.println();
+ }
+
+ // TODO: Move to ProcessList?
+ void dumpLruLocked(PrintWriter pw, String dumpPackage) {
+ pw.println("ACTIVITY MANAGER LRU PROCESSES (dumpsys activity lru)");
+ final int N = mProcessList.mLruProcesses.size();
+ int i;
+ boolean first = true;
+ for (i = N - 1; i >= mProcessList.mLruProcessActivityStart; i--) {
+ final ProcessRecord r = mProcessList.mLruProcesses.get(i);
+ if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
+ continue;
+ }
+ if (first) {
+ pw.println(" Activities:");
+ first = false;
+ }
+ dumpLruEntryLocked(pw, i, r);
+ }
+ first = true;
+ for (; i >= mProcessList.mLruProcessServiceStart; i--) {
+ final ProcessRecord r = mProcessList.mLruProcesses.get(i);
+ if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
+ continue;
+ }
+ if (first) {
+ pw.println(" Services:");
+ first = false;
+ }
+ dumpLruEntryLocked(pw, i, r);
+ }
+ first = true;
+ for (; i >= 0; i--) {
+ final ProcessRecord r = mProcessList.mLruProcesses.get(i);
+ if (dumpPackage != null && !r.pkgList.containsKey(dumpPackage)) {
+ continue;
+ }
+ if (first) {
+ pw.println(" Other:");
+ first = false;
+ }
+ dumpLruEntryLocked(pw, i, r);
+ }
}
// TODO: Move to ProcessList?
@@ -13214,6 +13310,12 @@
}
}
+ public void updateServiceGroup(IServiceConnection connection, int group, int importance) {
+ synchronized (this) {
+ mServices.updateServiceGroupLocked(connection, group, importance);
+ }
+ }
+
public boolean unbindService(IServiceConnection connection) {
synchronized (this) {
return mServices.unbindServiceLocked(connection);
@@ -17398,8 +17500,11 @@
int stepCached = 0;
int stepEmpty = 0;
int numCached = 0;
+ int numCachedExtraGroup = 0;
int numEmpty = 0;
int numTrimming = 0;
+ int lastCachedGroup = 0;
+ int lastCachedGroupUid = 0;
mNumNonCachedProcs = 0;
mNumCachedHiddenProcs = 0;
@@ -17523,7 +17628,21 @@
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
mNumCachedHiddenProcs++;
numCached++;
- if (numCached > cachedProcessLimit) {
+ if (app.connectionGroup != 0) {
+ if (lastCachedGroupUid == app.uid
+ && lastCachedGroup == app.connectionGroup) {
+ // If this process is the next in the same group, we don't
+ // want it to count against our limit of the number of cached
+ // processes, so bump up the group count to account for it.
+ numCachedExtraGroup++;
+ } else {
+ lastCachedGroupUid = app.uid;
+ lastCachedGroup = app.connectionGroup;
+ }
+ } else {
+ lastCachedGroupUid = lastCachedGroup = 0;
+ }
+ if ((numCached - numCachedExtraGroup) > cachedProcessLimit) {
app.kill("cached #" + numCached, true);
}
break;
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 8f8d5ab..67a4d14 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2853,6 +2853,9 @@
pw.println(" provider [COMP_SPEC]: provider client-side state");
pw.println(" s[ervices] [COMP_SPEC ...]: service state");
pw.println(" as[sociations]: tracked app associations");
+ pw.println(" lmk: stats on low memory killer");
+ pw.println(" lru: raw LRU process list");
+ pw.println(" binder-proxies: stats on binder objects and IPCs");
pw.println(" settings: currently applied config settings");
pw.println(" service [COMP_SPEC]: service client-side state");
pw.println(" package [PACKAGE_NAME]: all state related to given package");
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index bfa3f66..aa76b3d 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -48,7 +48,7 @@
boolean serviceDead; // Well is it?
// Please keep the following two enum list synced.
- private static int[] BIND_ORIG_ENUMS = new int[] {
+ private static final int[] BIND_ORIG_ENUMS = new int[] {
Context.BIND_AUTO_CREATE,
Context.BIND_DEBUG_UNBIND,
Context.BIND_NOT_FOREGROUND,
@@ -65,7 +65,7 @@
Context.BIND_SHOWING_UI,
Context.BIND_NOT_VISIBLE,
};
- private static int[] BIND_PROTO_ENUMS = new int[] {
+ private static final int[] BIND_PROTO_ENUMS = new int[] {
ConnectionRecordProto.AUTO_CREATE,
ConnectionRecordProto.DEBUG_UNBIND,
ConnectionRecordProto.NOT_FG,
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 84b364b..4b19398 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -50,6 +50,7 @@
import android.app.AppProtoEnums;
import android.app.IApplicationThread;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
@@ -2204,7 +2205,7 @@
@GuardedBy("mService")
int updateLruProcessInternalLocked(ProcessRecord app, long now, int index,
- String what, Object obj, ProcessRecord srcApp) {
+ int lruSeq, String what, Object obj, ProcessRecord srcApp) {
app.lastActivityTime = now;
if (app.hasActivitiesOrRecentTasks()) {
@@ -2225,7 +2226,7 @@
return index;
}
- if (lrui >= mLruProcessActivityStart) {
+ if (lrui >= mLruProcessActivityStart && index < mLruProcessActivityStart) {
// Don't want to touch dependent processes that are hosting activities.
return index;
}
@@ -2237,6 +2238,7 @@
if (DEBUG_LRU) Slog.d(TAG_LRU, "Moving dep from " + lrui + " to " + index
+ " in LRU list: " + app);
mLruProcesses.add(index, app);
+ app.lruSeq = lruSeq;
return index;
}
@@ -2345,9 +2347,11 @@
*/
int nextIndex;
+ int nextActivityIndex = -1;
if (hasActivity) {
final int N = mLruProcesses.size();
- if ((!app.hasActivities() || app.hasRecentTasks())
+ nextIndex = mLruProcessServiceStart;
+ if (!app.hasActivitiesOrRecentTasks() && !app.treatLikeActivity
&& mLruProcessActivityStart < (N - 1)) {
// Process doesn't have activities, but has clients with
// activities... move it up, but one below the top (the top
@@ -2355,36 +2359,92 @@
if (DEBUG_LRU) Slog.d(TAG_LRU,
"Adding to second-top of LRU activity list: " + app);
mLruProcesses.add(N - 1, app);
- // To keep it from spamming the LRU list (by making a bunch of clients),
- // we will push down any other entries owned by the app.
+ // If this process is part of a group, need to pull up any other processes
+ // in that group to be with it.
final int uid = app.info.uid;
- for (int i = N - 2; i > mLruProcessActivityStart; i--) {
- ProcessRecord subProc = mLruProcesses.get(i);
- if (subProc.info.uid == uid) {
- // We want to push this one down the list. If the process after
- // it is for the same uid, however, don't do so, because we don't
- // want them internally to be re-ordered.
- if (mLruProcesses.get(i - 1).info.uid != uid) {
- if (DEBUG_LRU) Slog.d(TAG_LRU,
- "Pushing uid " + uid + " swapping at " + i + ": "
- + mLruProcesses.get(i) + " : "
- + mLruProcesses.get(i - 1));
- ProcessRecord tmp = mLruProcesses.get(i);
- mLruProcesses.set(i, mLruProcesses.get(i - 1));
- mLruProcesses.set(i - 1, tmp);
- i--;
+ int endIndex = N - 2;
+ nextActivityIndex = N - 2;
+ if (app.connectionGroup > 0) {
+ int endImportance = app.connectionImportance;
+ for (int i = endIndex; i >= mLruProcessActivityStart; i--) {
+ final ProcessRecord subProc = mLruProcesses.get(i);
+ if (subProc.info.uid == uid
+ && subProc.connectionGroup == subProc.connectionGroup) {
+ if (i == endIndex && subProc.connectionImportance >= endImportance) {
+ // This process is already in the group, and its importance
+ // is not as strong as the process before it, so it keep it
+ // correctly positioned in the group.
+ endIndex--;
+ endImportance = subProc.connectionImportance;
+ } else {
+ // We want to pull this up to be with the rest of the group,
+ // and order within the group by importance.
+ boolean moved = false;
+ for (int pos = N - 1; pos > endIndex; pos--) {
+ final ProcessRecord posProc = mLruProcesses.get(pos);
+ if (subProc.connectionImportance
+ <= posProc.connectionImportance) {
+ mLruProcesses.remove(i);
+ mLruProcesses.add(pos, subProc);
+ moved = true;
+ endIndex--;
+ break;
+ }
+ }
+ if (!moved) {
+ // Goes to the end of the group.
+ mLruProcesses.remove(i);
+ mLruProcesses.add(endIndex - 1, subProc);
+ endIndex--;
+ endImportance = subProc.connectionImportance;
+ }
+ }
}
- } else {
- // A gap, we can stop here.
- break;
+ }
+
+ }
+ // To keep it from spamming the LRU list (by making a bunch of clients),
+ // we will distribute other entries owned by it to be in-between other apps.
+ for (int i = endIndex; i >= mLruProcessActivityStart; i--) {
+ final ProcessRecord subProc = mLruProcesses.get(i);
+ if (subProc.info.uid != uid) {
+ // This is a different app... if we have gone through some of the
+ // target app, pull this up to be before them.
+ if (i < endIndex) {
+ mLruProcesses.remove(i);
+ mLruProcesses.add(endIndex, subProc);
+ }
+ // Find the end of the next group of processes for target app. This
+ // is after any entries of different apps (so we don't change the existing
+ // relative order of apps) and then after the next last group of processes
+ // of the target app.
+ for (endIndex--; endIndex >= mLruProcessActivityStart; endIndex--) {
+ final ProcessRecord endProc = mLruProcesses.get(endIndex);
+ if (endProc.info.uid == uid) {
+ break;
+ }
+ }
+ if (endIndex >= mLruProcessActivityStart) {
+ final ProcessRecord endProc = mLruProcesses.get(endIndex);
+ for (endIndex--; endIndex >= mLruProcessActivityStart; endIndex--) {
+ final ProcessRecord nextEndProc = mLruProcesses.get(endIndex);
+ if (nextEndProc.info.uid != uid
+ || nextEndProc.connectionGroup != endProc.connectionGroup) {
+ break;
+ }
+ }
+ }
+ if (i > endIndex) {
+ i = endIndex;
+ }
}
}
} else {
// Process has activities, put it at the very tipsy-top.
if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU activity list: " + app);
mLruProcesses.add(app);
+ nextActivityIndex = mLruProcesses.size() - 1;
}
- nextIndex = mLruProcessServiceStart;
} else if (hasService) {
// Process has services, put it at the top of the service list.
if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding to top of LRU service list: " + app);
@@ -2416,6 +2476,8 @@
mLruProcessServiceStart++;
}
+ app.lruSeq = mLruSeq;
+
// If the app is currently using a content provider or service,
// bump those processes as well.
for (int j = app.connections.size() - 1; j >= 0; j--) {
@@ -2423,17 +2485,27 @@
if (cr.binding != null && !cr.serviceDead && cr.binding.service != null
&& cr.binding.service.app != null
&& cr.binding.service.app.lruSeq != mLruSeq
+ && (cr.flags & Context.BIND_REDUCTION_FLAGS) == 0
&& !cr.binding.service.app.isPersistent()) {
- nextIndex = updateLruProcessInternalLocked(cr.binding.service.app,
- now,
- nextIndex,
- "service connection", cr, app);
+ if (cr.binding.service.app.hasClientActivities()) {
+ if (nextActivityIndex >= 0) {
+ nextActivityIndex = updateLruProcessInternalLocked(cr.binding.service.app,
+ now,
+ nextActivityIndex, mLruSeq,
+ "service connection", cr, app);
+ }
+ } else {
+ nextIndex = updateLruProcessInternalLocked(cr.binding.service.app,
+ now,
+ nextIndex, mLruSeq,
+ "service connection", cr, app);
+ }
}
}
for (int j = app.conProviders.size() - 1; j >= 0; j--) {
ContentProviderRecord cpr = app.conProviders.get(j).provider;
if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.isPersistent()) {
- nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex,
+ nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex, mLruSeq,
"provider reference", cpr, app);
}
}
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index faf8561..013de93 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -155,6 +155,9 @@
int pssStatType; // The type of stat collection that we are currently requesting
int savedPriority; // Previous priority value if we're switching to non-SCHED_OTHER
int renderThreadTid; // TID for RenderThread
+ ServiceRecord connectionService; // Service that applied current connectionGroup/Importance
+ int connectionGroup; // Last group set by a connection
+ int connectionImportance; // Last importance set by a connection
boolean serviceb; // Process currently is on the service B list
boolean serviceHighRam; // We are forcing to service B list due to its RAM use
boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle?
@@ -396,6 +399,11 @@
pw.print(" hasAboveClient="); pw.print(hasAboveClient);
pw.print(" treatLikeActivity="); pw.println(treatLikeActivity);
}
+ if (connectionService != null || connectionGroup != 0) {
+ pw.print(prefix); pw.print("connectionGroup="); pw.print(connectionGroup);
+ pw.print(" Importance="); pw.print(connectionImportance);
+ pw.print(" Service="); pw.println(connectionService);
+ }
if (hasTopUi() || hasOverlayUi() || runningRemoteAnimation) {
pw.print(prefix); pw.print("hasTopUi="); pw.print(hasTopUi());
pw.print(" hasOverlayUi="); pw.print(hasOverlayUi());
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index b442072..1dfb86a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -94,6 +94,7 @@
import android.service.vr.IVrStateCallbacks;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
@@ -179,7 +180,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
-import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.WeakHashMap;
@@ -321,7 +321,7 @@
// All known input methods. mMethodMap also serves as the global
// lock for this class.
final ArrayList<InputMethodInfo> mMethodList = new ArrayList<>();
- final HashMap<String, InputMethodInfo> mMethodMap = new HashMap<>();
+ final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans =
new LruCache<>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
private final InputMethodSubtypeSwitchingController mSwitchingController;
@@ -457,7 +457,7 @@
}
}
- final HashMap<IBinder, ClientState> mClients = new HashMap<>();
+ final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
/**
* Set once the system is ready to run third party code.
@@ -553,8 +553,8 @@
private InputMethodSubtype mCurrentSubtype;
// This list contains the pairs of InputMethodInfo and InputMethodSubtype.
- private final HashMap<InputMethodInfo, ArrayList<InputMethodSubtype>>
- mShortcutInputMethodsAndSubtypes = new HashMap<>();
+ private final ArrayMap<InputMethodInfo, ArrayList<InputMethodSubtype>>
+ mShortcutInputMethodsAndSubtypes = new ArrayMap<>();
// Was the keyguard locked when this client became current?
private boolean mCurClientInKeyguard;
@@ -1781,7 +1781,9 @@
final int callerPid = Binder.getCallingPid();
synchronized (mMethodMap) {
// TODO: Optimize this linear search.
- for (ClientState state : mClients.values()) {
+ final int numClients = mClients.size();
+ for (int i = 0; i < numClients; ++i) {
+ final ClientState state = mClients.valueAt(i);
if (state.uid == callerUid && state.pid == callerPid
&& state.selfReportedDisplayId == selfReportedDisplayId) {
throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
@@ -2192,8 +2194,9 @@
void clearCurMethodLocked() {
if (mCurMethod != null) {
- for (ClientState cs : mClients.values()) {
- clearClientSessionLocked(cs);
+ final int numClients = mClients.size();
+ for (int i = 0; i < numClients; ++i) {
+ clearClientSessionLocked(mClients.valueAt(i));
}
finishSessionLocked(mEnabledSession);
@@ -3670,7 +3673,7 @@
| PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS),
mSettings.getCurrentUserId());
- final HashMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
+ final ArrayMap<String, List<InputMethodSubtype>> additionalSubtypeMap =
mFileManager.getAllAdditionalInputMethodSubtypes();
for (int i = 0; i < services.size(); ++i) {
ResolveInfo ri = services.get(i);
@@ -4306,10 +4309,10 @@
private static final String ATTR_IS_AUXILIARY = "isAuxiliary";
private static final String ATTR_IS_ASCII_CAPABLE = "isAsciiCapable";
private final AtomicFile mAdditionalInputMethodSubtypeFile;
- private final HashMap<String, InputMethodInfo> mMethodMap;
- private final HashMap<String, List<InputMethodSubtype>> mAdditionalSubtypesMap =
- new HashMap<>();
- public InputMethodFileManager(HashMap<String, InputMethodInfo> methodMap, int userId) {
+ private final ArrayMap<String, InputMethodInfo> mMethodMap;
+ private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypesMap =
+ new ArrayMap<>();
+ InputMethodFileManager(ArrayMap<String, InputMethodInfo> methodMap, int userId) {
if (methodMap == null) {
throw new NullPointerException("methodMap is null");
}
@@ -4361,15 +4364,15 @@
}
}
- public HashMap<String, List<InputMethodSubtype>> getAllAdditionalInputMethodSubtypes() {
+ public ArrayMap<String, List<InputMethodSubtype>> getAllAdditionalInputMethodSubtypes() {
synchronized (mMethodMap) {
return mAdditionalSubtypesMap;
}
}
private static void writeAdditionalInputMethodSubtypes(
- HashMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile,
- HashMap<String, InputMethodInfo> methodMap) {
+ ArrayMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile,
+ ArrayMap<String, InputMethodInfo> methodMap) {
// Safety net for the case that this function is called before methodMap is set.
final boolean isSetMethodMap = methodMap != null && methodMap.size() > 0;
FileOutputStream fos = null;
@@ -4423,7 +4426,7 @@
}
private static void readAdditionalInputMethodSubtypes(
- HashMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile) {
+ ArrayMap<String, List<InputMethodSubtype>> allSubtypes, AtomicFile subtypesFile) {
if (allSubtypes == null || subtypesFile == null) return;
allSubtypes.clear();
try (final FileInputStream fis = subtypesFile.openRead()) {
@@ -4621,7 +4624,9 @@
info.dump(p, " ");
}
p.println(" Clients:");
- for (ClientState ci : mClients.values()) {
+ final int numClients = mClients.size();
+ for (int i = 0; i < numClients; ++i) {
+ final ClientState ci = mClients.valueAt(i);
p.println(" Client " + ci + ":");
p.println(" client=" + ci.client);
p.println(" inputContext=" + ci.inputContext);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index db6d826..8e3f351 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -31,6 +31,7 @@
import android.os.RemoteException;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Pair;
import android.util.Printer;
import android.util.Slog;
@@ -45,7 +46,6 @@
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
@@ -473,7 +473,7 @@
final int numSubtypes = subtypes.size();
// Handle overridesImplicitlyEnabledSubtype mechanism.
- final HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap = new HashMap<>();
+ final ArrayMap<String, InputMethodSubtype> applicableModeAndSubtypesMap = new ArrayMap<>();
for (int i = 0; i < numSubtypes; ++i) {
// scan overriding implicitly enabled subtypes.
final InputMethodSubtype subtype = subtypes.get(i);
@@ -488,8 +488,8 @@
return new ArrayList<>(applicableModeAndSubtypesMap.values());
}
- final HashMap<String, ArrayList<InputMethodSubtype>> nonKeyboardSubtypesMap =
- new HashMap<>();
+ final ArrayMap<String, ArrayList<InputMethodSubtype>> nonKeyboardSubtypesMap =
+ new ArrayMap<>();
final ArrayList<InputMethodSubtype> keyboardSubtypes = new ArrayList<>();
for (int i = 0; i < numSubtypes; ++i) {
@@ -761,12 +761,12 @@
private final Resources mRes;
private final ContentResolver mResolver;
- private final HashMap<String, InputMethodInfo> mMethodMap;
+ private final ArrayMap<String, InputMethodInfo> mMethodMap;
/**
* On-memory data store to emulate when {@link #mCopyOnWrite} is {@code true}.
*/
- private final HashMap<String, String> mCopyOnWriteDataStore = new HashMap<>();
+ private final ArrayMap<String, String> mCopyOnWriteDataStore = new ArrayMap<>();
private boolean mCopyOnWrite = false;
@NonNull
@@ -812,7 +812,7 @@
public InputMethodSettings(
Resources res, ContentResolver resolver,
- HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
+ ArrayMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
@UserIdInt int userId, boolean copyOnWrite) {
mRes = res;
mResolver = resolver;
diff --git a/services/core/java/com/android/server/inputmethod/LocaleUtils.java b/services/core/java/com/android/server/inputmethod/LocaleUtils.java
index 4958ece..7a6853a 100644
--- a/services/core/java/com/android/server/inputmethod/LocaleUtils.java
+++ b/services/core/java/com/android/server/inputmethod/LocaleUtils.java
@@ -22,10 +22,10 @@
import android.icu.util.ULocale;
import android.os.LocaleList;
import android.text.TextUtils;
+import android.util.ArrayMap;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -155,7 +155,7 @@
}
final int numPreferredLocales = preferredLocales.size();
- final HashMap<String, ScoreEntry> scoreboard = new HashMap<>();
+ final ArrayMap<String, ScoreEntry> scoreboard = new ArrayMap<>();
final byte[] score = new byte[numPreferredLocales];
final ULocale[] preferredULocaleCache = new ULocale[numPreferredLocales];
@@ -197,7 +197,11 @@
}
}
- final ScoreEntry[] result = scoreboard.values().toArray(new ScoreEntry[scoreboard.size()]);
+ final int numEntries = scoreboard.size();
+ final ScoreEntry[] result = new ScoreEntry[numEntries];
+ for (int i = 0; i < numEntries; ++i) {
+ result[i] = scoreboard.valueAt(i);
+ }
Arrays.sort(result);
for (final ScoreEntry entry : result) {
dest.add(sources.get(entry.mIndex));
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 9d402b3..c18a79f 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -16,10 +16,7 @@
package com.android.server.media;
-import static android.media.SessionToken2.TYPE_SESSION;
-
import android.app.ActivityManager;
-import android.app.AppGlobals;
import android.app.INotificationManager;
import android.app.KeyguardManager;
import android.app.PendingIntent;
@@ -30,7 +27,6 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
@@ -40,9 +36,6 @@
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.IRemoteVolumeController;
-import android.media.ISessionTokensListener;
-import android.media.MediaController2;
-import android.media.SessionToken2;
import android.media.session.IActiveSessionsListener;
import android.media.session.ICallback;
import android.media.session.IOnMediaKeyListener;
@@ -68,7 +61,6 @@
import android.provider.Settings;
import android.speech.RecognizerIntent;
import android.text.TextUtils;
-import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -85,15 +77,12 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
/**
* System implementation of MediaSessionManager
*/
public class MediaSessionService extends SystemService implements Monitor {
private static final String TAG = "MediaSessionService";
- static final boolean USE_MEDIA2_APIS = false; // TODO: Change this to true when we're ready.
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
// Leave log for key event always.
private static final boolean DEBUG_KEY_EVENT = true;
@@ -113,7 +102,6 @@
private final PowerManager.WakeLock mMediaEventWakeLock;
private final int mLongPressTimeout;
private final INotificationManager mNotificationManager;
- private final IPackageManager mPackageManager;
private KeyguardManager mKeyguardManager;
private IAudioService mAudioService;
@@ -131,13 +119,6 @@
// better way to handle this.
private IRemoteVolumeController mRvc;
- // MediaSession2 support
- // TODO(jaewan): Support multi-user and managed profile. (b/73597722)
- // TODO(jaewan): Make it priority list for handling volume/media key. (b/73760382)
- private final Map<SessionToken2, MediaController2> mSessionRecords = new ArrayMap<>();
-
- private final List<SessionTokensListenerRecord> mSessionTokensListeners = new ArrayList<>();
-
public MediaSessionService(Context context) {
super(context);
mSessionManagerImpl = new SessionManagerImpl();
@@ -146,7 +127,6 @@
mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
mNotificationManager = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- mPackageManager = AppGlobals.getPackageManager();
}
@Override
@@ -645,20 +625,6 @@
return mUserRecords.get(fullUserId);
}
- void destroySession2Internal(SessionToken2 token) {
- synchronized (mLock) {
- boolean notifySessionTokensUpdated = false;
- if (token.getType() == SessionToken2.TYPE_SESSION) {
- notifySessionTokensUpdated |= removeSessionRecordLocked(token);
- } else {
- notifySessionTokensUpdated |= addSessionRecordLocked(token);
- }
- if (notifySessionTokensUpdated) {
- postSessionTokensUpdated(UserHandle.getUserId(token.getUid()));
- }
- }
- }
-
/**
* Information about a full user and its corresponding managed profiles.
*
@@ -1417,163 +1383,6 @@
}
}
- /**
- * Called when a {@link android.media.MediaSession2} instance is created.
- * <p>
- * This does two things.
- * 1. Keep the newly created session in the service
- * 2. Do sanity check to ensure unique id per package, and return result
- *
- * @param sessionToken SessionToken2 object in bundled form
- * @return {@code true} if the session's id isn't used by the package now. {@code false}
- * otherwise.
- */
- @Override
- public boolean createSession2(Bundle sessionToken) {
- if (!USE_MEDIA2_APIS) {
- return false;
- }
- final int uid = Binder.getCallingUid();
- final SessionToken2 token = SessionToken2.fromBundle(sessionToken);
- if (token == null || token.getUid() != uid) {
- Log.w(TAG, "onSessionCreated failed, expected caller uid=" + token.getUid()
- + " but from uid=" + uid);
- }
- if (DEBUG) {
- Log.d(TAG, "createSession2: " + token);
- }
- synchronized (mLock) {
- MediaController2 controller = mSessionRecords.get(token);
- if (controller != null && controller.isConnected()) {
- return false;
- }
- Context context = getContext();
- controller = new MediaController2(context, token, context.getMainExecutor(),
- new ControllerCallback(token));
- if (addSessionRecordLocked(token, controller)) {
- postSessionTokensUpdated(UserHandle.getUserId(token.getUid()));
- }
- return true;
- }
- }
-
- /**
- * Called when a {@link android.media.MediaSession2} instance is closed. (i.e. destroyed)
- * <p>
- * Ideally service should know that a session is destroyed through the
- * {@link android.media.MediaController2.ControllerCallback#onDisconnected()}, which is
- * asynchronous call. However, we also need synchronous way together to address timing
- * issue. If the package recreates the session almost immediately, which happens commonly
- * for tests, service will reject the creation through {@link #onSessionCreated(Bundle)}
- * if the service hasn't notified previous destroy yet. This synchronous API will address
- * the issue.
- *
- * @param sessionToken SessionToken2 object in bundled form
- */
- @Override
- public void destroySession2(Bundle sessionToken) {
- if (!USE_MEDIA2_APIS) {
- return;
- }
- final int uid = Binder.getCallingUid();
- final SessionToken2 token = SessionToken2.fromBundle(sessionToken);
- if (token == null || token.getUid() != uid) {
- Log.w(TAG, "onSessionDestroyed failed, expected caller uid=" + token.getUid()
- + " but from uid=" + uid);
- }
- if (DEBUG) {
- Log.d(TAG, "destroySession2 " + token);
- }
- destroySession2Internal(token);
- }
-
- // TODO(jaewan): Make this API take userId as an argument (b/73597722)
- @Override
- public List<Bundle> getSessionTokens(boolean activeSessionOnly,
- boolean sessionServiceOnly, String packageName) throws RemoteException {
- if (!USE_MEDIA2_APIS) {
- return null;
- }
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
-
- List<Bundle> tokens = new ArrayList<>();
- try {
- verifySessionsRequest2(UserHandle.getUserId(uid), packageName, pid, uid);
- synchronized (mLock) {
- for (Map.Entry<SessionToken2, MediaController2> record
- : mSessionRecords.entrySet()) {
- boolean isSessionService = (record.getKey().getType() != TYPE_SESSION);
- boolean isActive = record.getValue() != null;
- if ((activeSessionOnly && !isActive)
- || (sessionServiceOnly && !isSessionService)) {
- continue;
- }
- tokens.add(record.getKey().toBundle());
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- return tokens;
- }
-
- @Override
- public void addSessionTokensListener(ISessionTokensListener listener, int userId,
- String packageName) throws RemoteException {
- if (!USE_MEDIA2_APIS) {
- return;
- }
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- int resolvedUserId = verifySessionsRequest2(userId, packageName, pid, uid);
- synchronized (mLock) {
- final SessionTokensListenerRecord record =
- new SessionTokensListenerRecord(listener, resolvedUserId);
- try {
- listener.asBinder().linkToDeath(record, 0);
- } catch (RemoteException e) {
- }
- mSessionTokensListeners.add(record);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- // TODO(jaewan): Make this API take userId as an argument (b/73597722)
- @Override
- public void removeSessionTokensListener(ISessionTokensListener listener,
- String packageName) throws RemoteException {
- if (!USE_MEDIA2_APIS) {
- return;
- }
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- verifySessionsRequest2(UserHandle.getUserId(uid), packageName, pid, uid);
- synchronized (mLock) {
- IBinder listenerBinder = listener.asBinder();
- for (SessionTokensListenerRecord record : mSessionTokensListeners) {
- if (listenerBinder.equals(record.mListener.asBinder())) {
- try {
- listenerBinder.unlinkToDeath(record, 0);
- } catch (NoSuchElementException e) {
- }
- mSessionTokensListeners.remove(record);
- break;
- }
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
// For MediaSession
private int verifySessionsRequest(ComponentName componentName, int userId, final int pid,
final int uid) {
@@ -1594,23 +1403,6 @@
return resolvedUserId;
}
- // For MediaSession2
- private int verifySessionsRequest2(int targetUserId, String callerPackageName,
- int callerPid, int callerUid) throws RemoteException {
- // Check that they can make calls on behalf of the user and get the final user id.
- int resolvedUserId = ActivityManager.handleIncomingUser(callerPid, callerUid,
- targetUserId, true /* allowAll */, true /* requireFull */, "getSessionTokens",
- callerPackageName);
- // Check if they have the permissions or their component is
- // enabled for the user they're calling from.
- if (!hasMediaControlPermission(
- resolvedUserId, callerPackageName, callerPid, callerUid)) {
- throw new SecurityException("Missing permission to control media.");
- }
- return resolvedUserId;
- }
-
- // For MediaSession2
private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
int pid, int uid) throws RemoteException {
// Allow API calls from the System UI
@@ -2014,7 +1806,6 @@
final class MessageHandler extends Handler {
private static final int MSG_SESSIONS_CHANGED = 1;
private static final int MSG_VOLUME_INITIAL_DOWN = 2;
- private static final int MSG_SESSIONS_TOKENS_CHANGED = 3;
private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
@Override
@@ -2033,9 +1824,6 @@
}
}
break;
- case MSG_SESSIONS_TOKENS_CHANGED:
- pushSessionTokensChanged((int) msg.obj);
- break;
}
}
@@ -2050,86 +1838,4 @@
obtainMessage(MSG_SESSIONS_CHANGED, userIdInteger).sendToTarget();
}
}
-
- private class ControllerCallback extends MediaController2.ControllerCallback {
-
- private final SessionToken2 mToken;
-
- ControllerCallback(SessionToken2 token) {
- mToken = token;
- }
-
- @Override
- public void onDisconnected(MediaController2 controller) {
- destroySession2Internal(mToken);
- }
- };
-
- private final class SessionTokensListenerRecord implements IBinder.DeathRecipient {
- private final ISessionTokensListener mListener;
- private final int mUserId;
-
- public SessionTokensListenerRecord(ISessionTokensListener listener, int userId) {
- mListener = listener;
- // TODO(jaewan): should userId be mapped through mFullUserIds? (b/73597722)
- mUserId = userId;
- }
-
- @Override
- public void binderDied() {
- synchronized (mLock) {
- mSessionTokensListeners.remove(this);
- }
- }
- }
-
- private void postSessionTokensUpdated(int userId) {
- mHandler.obtainMessage(MessageHandler.MSG_SESSIONS_TOKENS_CHANGED, userId).sendToTarget();
- }
-
- private void pushSessionTokensChanged(int userId) {
- synchronized (mLock) {
- List<Bundle> tokens = new ArrayList<>();
- for (SessionToken2 token : mSessionRecords.keySet()) {
- if (UserHandle.getUserId(token.getUid()) == userId) {
- tokens.add(token.toBundle());
- }
- }
-
- for (SessionTokensListenerRecord record : mSessionTokensListeners) {
- // TODO(jaewan): Should userId be mapped through mFullUserIds? (b/73760382)
- if (record.mUserId == userId || record.mUserId == UserHandle.USER_ALL) {
- try {
- record.mListener.onSessionTokensChanged(tokens);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to notify session tokens changed", e);
- }
- }
- }
- }
- }
-
- private boolean addSessionRecordLocked(SessionToken2 token) {
- return addSessionRecordLocked(token, null);
- }
-
- private boolean addSessionRecordLocked(SessionToken2 token, MediaController2 controller) {
- if (mSessionRecords.containsKey(token) && mSessionRecords.get(token) == controller) {
- // The key/value pair already exists, no need to update.
- return false;
- }
-
- mSessionRecords.put(token, controller);
- return true;
- }
-
- private boolean removeSessionRecordLocked(SessionToken2 token) {
- if (!mSessionRecords.containsKey(token)) {
- // The key is already removed, no need to remove.
- return false;
- }
-
- mSessionRecords.remove(token);
- return true;
- }
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 32990ce..4da29e4 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -411,7 +411,7 @@
private NotificationAssistants mAssistants;
private ConditionProviders mConditionProviders;
private NotificationUsageStats mUsageStats;
- private boolean mLockScreenAllowSecureNotifications;
+ private boolean mLockScreenAllowSecureNotifications = true;
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 5810e30..b52c021 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -333,9 +333,7 @@
PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
collectingInstaller, mPackageManagerService.mInstallLock, mContext);
- String[] libraryDependencies = pkg.usesLibraryFiles;
-
- optimizer.performDexOpt(pkg, libraryDependencies,
+ optimizer.performDexOpt(pkg, pkg.usesLibraryInfos,
null /* ISAs */,
null /* CompilerStats.PackageStats */,
mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(pkg.packageName),
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 95d2154..cc640f0 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.os.FileUtils;
@@ -129,7 +130,7 @@
* <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
* synchronized on {@link #mInstallLock}.
*/
- int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
+ int performDexOpt(PackageParser.Package pkg, List<SharedLibraryInfo> sharedLibraries,
String[] instructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
if (pkg.applicationInfo.uid == -1) {
@@ -155,7 +156,8 @@
* It assumes the install lock is held.
*/
@GuardedBy("mInstallLock")
- private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
+ private int performDexOptLI(PackageParser.Package pkg,
+ List<SharedLibraryInfo> sharedLibraries,
String[] targetInstructionSets, CompilerStats.PackageStats packageStats,
PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
final String[] instructionSets = targetInstructionSets != null ?
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9856a2b..acbd81d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2233,7 +2233,7 @@
for (int i = 0; i < builtInLibCount; i++) {
String name = libConfig.keyAt(i);
String path = libConfig.valueAt(i);
- addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
+ addSharedLibraryLPw(path, null, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
}
// Builtin libraries cannot encode their dependency where they are
@@ -4844,7 +4844,8 @@
}
SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(),
- libInfo.getPackageName(), libInfo.getName(), libInfo.getLongVersion(),
+ libInfo.getPackageName(), libInfo.getAllCodePaths(),
+ libInfo.getName(), libInfo.getLongVersion(),
libInfo.getType(), libInfo.getDeclaringPackage(),
getPackagesUsingSharedLibraryLPr(libInfo, flags, userId),
(libInfo.getDependencies() == null
@@ -9225,7 +9226,7 @@
mDexManager.getPackageUseInfoOrDefault(depPackage.packageName), libraryOptions);
}
}
- return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets,
+ return pdo.performDexOpt(p, p.usesLibraryInfos, instructionSets,
getOrCreateCompilerPackageStats(p),
mDexManager.getPackageUseInfoOrDefault(p.packageName), options);
}
@@ -9628,7 +9629,6 @@
@GuardedBy("mPackages")
private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles,
SharedLibraryInfo libInfo, PackageParser.Package changingLib) {
-
if (libInfo.getPath() != null) {
usesLibraryFiles.add(libInfo.getPath());
return;
@@ -11224,8 +11224,9 @@
}
}
- private boolean addSharedLibraryLPw(String path, String apk, String name, long version,
- int type, String declaringPackageName, long declaringVersionCode) {
+ private boolean addSharedLibraryLPw(String path, String apk, List<String> codePaths,
+ String name, long version, int type, String declaringPackageName,
+ long declaringVersionCode) {
LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(name);
if (versionedLib == null) {
versionedLib = new LongSparseArray<>();
@@ -11236,7 +11237,7 @@
} else if (versionedLib.indexOfKey(version) >= 0) {
return false;
}
- SharedLibraryInfo libraryInfo = new SharedLibraryInfo(path, apk, name,
+ SharedLibraryInfo libraryInfo = new SharedLibraryInfo(path, apk, codePaths, name,
version, type, new VersionedPackage(declaringPackageName, declaringVersionCode),
null, null);
versionedLib.put(version, libraryInfo);
@@ -11323,10 +11324,17 @@
if (pkg.staticSharedLibName != null) {
// Static shared libs don't allow renaming as they have synthetic package
// names to allow install of multiple versions, so use name from manifest.
- if (addSharedLibraryLPw(null, pkg.packageName, pkg.staticSharedLibName,
+ if (addSharedLibraryLPw(null, pkg.packageName, pkg.getAllCodePaths(),
+ pkg.staticSharedLibName,
pkg.staticSharedLibVersion, SharedLibraryInfo.TYPE_STATIC,
pkg.manifestPackageName, pkg.getLongVersionCode())) {
hasStaticSharedLibs = true;
+ // Shared libraries for the package need to be updated.
+ try {
+ updateSharedLibrariesLPr(pkg, null);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
+ }
} else {
Slog.w(TAG, "Package " + pkg.packageName + " library "
+ pkg.staticSharedLibName + " already exists; skipping");
@@ -11368,13 +11376,19 @@
allowed = true;
}
if (allowed) {
- if (!addSharedLibraryLPw(null, pkg.packageName, name,
- SharedLibraryInfo.VERSION_UNDEFINED,
+ if (!addSharedLibraryLPw(null, pkg.packageName, pkg.getAllCodePaths(),
+ name, SharedLibraryInfo.VERSION_UNDEFINED,
SharedLibraryInfo.TYPE_DYNAMIC,
pkg.packageName, pkg.getLongVersionCode())) {
Slog.w(TAG, "Package " + pkg.packageName + " library "
+ name + " already exists; skipping");
}
+ // Shared libraries for the package need to be updated.
+ try {
+ updateSharedLibrariesLPr(pkg, null);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
+ }
} else {
Slog.w(TAG, "Package " + pkg.packageName + " declares lib "
+ name + " that is not declared on system image; skipping");
@@ -15617,7 +15631,7 @@
REASON_INSTALL,
DexoptOptions.DEXOPT_BOOT_COMPLETE
| DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
- mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+ mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryInfos,
null /* instructionSets */,
getOrCreateCompilerPackageStats(pkg),
mDexManager.getPackageUseInfoOrDefault(packageName),
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index 9a12a2f..93ee44c 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -17,6 +17,7 @@
package com.android.server.pm.dex;
import android.content.pm.ApplicationInfo;
+import android.content.pm.SharedLibraryInfo;
import android.util.Slog;
import android.util.SparseArray;
@@ -29,6 +30,11 @@
public final class DexoptUtils {
private static final String TAG = "DexoptUtils";
+ // Shared libraries have more or less followed PCL behavior due to the way
+ // they were added to the classpath pre Q.
+ private static final String SHARED_LIBRARY_LOADER_TYPE =
+ ClassLoaderFactory.getPathClassLoaderName();
+
private DexoptUtils() {}
/**
@@ -62,12 +68,15 @@
* android.app.ActivityThread, boolean, ApplicationInfo, List, List)}.
*/
public static String[] getClassLoaderContexts(ApplicationInfo info,
- String[] sharedLibraries, boolean[] pathsWithCode) {
+ List<SharedLibraryInfo> sharedLibraries, boolean[] pathsWithCode) {
// The base class loader context contains only the shared library.
- String sharedLibrariesClassPath = encodeClasspath(sharedLibraries);
- String baseApkContextClassLoader = encodeClassLoader(
- sharedLibrariesClassPath, info.classLoaderName);
+ String sharedLibrariesContext = "";
+ if (sharedLibraries != null) {
+ sharedLibrariesContext = encodeSharedLibraries(sharedLibraries);
+ }
+ String baseApkContextClassLoader = encodeClassLoader(
+ "", info.classLoaderName, sharedLibrariesContext);
if (info.getSplitCodePaths() == null) {
// The application has no splits.
return new String[] {baseApkContextClassLoader};
@@ -81,11 +90,10 @@
// The splits have an implicit dependency on the base apk.
// This means that we have to add the base apk file in addition to the shared libraries.
String baseApkName = new File(info.getBaseCodePath()).getName();
- String sharedLibrariesAndBaseClassPath =
- encodeClasspath(sharedLibrariesClassPath, baseApkName);
+ String baseClassPath = baseApkName;
// The result is stored in classLoaderContexts.
- // Index 0 is the class loaded context for the base apk.
+ // Index 0 is the class loader context for the base apk.
// Index `i` is the class loader context encoding for split `i`.
String[] classLoaderContexts = new String[/*base apk*/ 1 + splitRelativeCodePaths.length];
classLoaderContexts[0] = pathsWithCode[0] ? baseApkContextClassLoader : null;
@@ -94,10 +102,14 @@
// If the app didn't request for the splits to be loaded in isolation or if it does not
// declare inter-split dependencies, then all the splits will be loaded in the base
// apk class loader (in the order of their definition).
- String classpath = sharedLibrariesAndBaseClassPath;
+ String classpath = baseClassPath;
for (int i = 1; i < classLoaderContexts.length; i++) {
- classLoaderContexts[i] = pathsWithCode[i]
- ? encodeClassLoader(classpath, info.classLoaderName) : null;
+ if (pathsWithCode[i]) {
+ classLoaderContexts[i] = encodeClassLoader(
+ classpath, info.classLoaderName, sharedLibrariesContext);
+ } else {
+ classLoaderContexts[i] = null;
+ }
// Note that the splits with no code are not removed from the classpath computation.
// i.e. split_n might get the split_n-1 in its classpath dependency even
// if split_n-1 has no code.
@@ -124,7 +136,7 @@
info.splitClassLoaderNames[i]);
}
String splitDependencyOnBase = encodeClassLoader(
- sharedLibrariesAndBaseClassPath, info.classLoaderName);
+ baseClassPath, info.classLoaderName);
SparseArray<int[]> splitDependencies = info.splitDependencies;
// Note that not all splits have dependencies (e.g. configuration splits)
@@ -149,7 +161,8 @@
// any dependency. In this case its context equals its declared class loader.
classLoaderContexts[i] = classLoaderContexts[i] == null
? splitClassLoader
- : encodeClassLoaderChain(splitClassLoader, classLoaderContexts[i]);
+ : encodeClassLoaderChain(splitClassLoader, classLoaderContexts[i])
+ + sharedLibrariesContext;
} else {
// This is a split without code, it has no dependency and it is not compiled.
// Its context will be null.
@@ -207,6 +220,31 @@
return splitContext;
}
+ private static String encodeSharedLibrary(SharedLibraryInfo sharedLibrary) {
+ List<String> paths = sharedLibrary.getAllCodePaths();
+ String classLoaderSpec = encodeClassLoader(
+ encodeClasspath(paths.toArray(new String[paths.size()])),
+ SHARED_LIBRARY_LOADER_TYPE);
+ if (sharedLibrary.getDependencies() != null) {
+ classLoaderSpec += encodeSharedLibraries(sharedLibrary.getDependencies());
+ }
+ return classLoaderSpec;
+ }
+
+ private static String encodeSharedLibraries(List<SharedLibraryInfo> sharedLibraries) {
+ String sharedLibrariesContext = "{";
+ boolean first = true;
+ for (SharedLibraryInfo info : sharedLibraries) {
+ if (!first) {
+ sharedLibrariesContext += "#";
+ }
+ first = false;
+ sharedLibrariesContext += encodeSharedLibrary(info);
+ }
+ sharedLibrariesContext += "}";
+ return sharedLibrariesContext;
+ }
+
/**
* Encodes the shared libraries classpathElements in a format accepted by dexopt.
* NOTE: Keep this in sync with the dexopt expectations! Right now that is
@@ -258,6 +296,14 @@
}
/**
+ * Same as above, but appends {@param sharedLibraries} to the result.
+ */
+ private static String encodeClassLoader(String classpath, String classLoaderName,
+ String sharedLibraries) {
+ return encodeClassLoader(classpath, classLoaderName) + sharedLibraries;
+ }
+
+ /**
* Links to dependencies together in a format accepted by dexopt.
* For the special case when either of cl1 or cl2 equals
* {@link PackageDexOptimizer#SKIP_SHARED_LIBRARY_CHECK}, the method returns the same. This
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/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 812fd82..79e2688 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.power;
+import android.annotation.Nullable;
import android.content.Context;
import android.hardware.thermal.V1_0.ThermalStatus;
import android.hardware.thermal.V1_0.ThermalStatusCode;
@@ -26,12 +27,16 @@
import android.os.HwBinder;
import android.os.IThermalEventListener;
import android.os.IThermalService;
+import android.os.IThermalStatusListener;
import android.os.PowerManager;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.os.Temperature;
+import android.util.ArrayMap;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
import com.android.server.SystemService;
@@ -39,6 +44,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.NoSuchElementException;
@@ -51,210 +57,154 @@
public class ThermalManagerService extends SystemService {
private static final String TAG = ThermalManagerService.class.getSimpleName();
- /** Registered observers of the thermal changed events. Cookie is used to store type */
+ /** Lock to protect listen list. */
+ private final Object mLock = new Object();
+
+ /**
+ * Registered observers of the thermal events. Cookie is used to store type as Integer, null
+ * means no filter.
+ */
@GuardedBy("mLock")
private final RemoteCallbackList<IThermalEventListener> mThermalEventListeners =
new RemoteCallbackList<>();
- /** Lock to protect HAL handles and listen list. */
- private final Object mLock = new Object();
-
- /** Newly registered callback. */
+ /** Registered observers of the thermal status. */
@GuardedBy("mLock")
- private IThermalEventListener mNewListenerCallback = null;
+ private final RemoteCallbackList<IThermalStatusListener> mThermalStatusListeners =
+ new RemoteCallbackList<>();
- /** Newly registered callback type, null means not filter type. */
+ /** Current thermal status */
@GuardedBy("mLock")
- private Integer mNewListenerType = null;
+ private int mStatus;
+
+ /** Current thermal map, key as name */
+ @GuardedBy("mLock")
+ private ArrayMap<String, Temperature> mTemperatureMap = new ArrayMap<>();
/** Local PMS handle. */
private final PowerManager mPowerManager;
- /** Proxy object for the Thermal HAL 2.0 service. */
+ /** HAL wrapper. */
+ private ThermalHalWrapper mHalWrapper;
+
+ /** Hal ready. */
@GuardedBy("mLock")
- private android.hardware.thermal.V2_0.IThermal mThermalHal20 = null;
+ private boolean mHalReady;
- /** Proxy object for the Thermal HAL 1.1 service. */
- @GuardedBy("mLock")
- private android.hardware.thermal.V1_1.IThermal mThermalHal11 = null;
-
- /** Cookie for matching the right end point. */
- private static final int THERMAL_HAL_DEATH_COOKIE = 5612;
-
- /** HWbinder callback for Thermal HAL 2.0. */
- private final IThermalChangedCallback.Stub mThermalCallback20 =
- new IThermalChangedCallback.Stub() {
- @Override
- public void notifyThrottling(
- android.hardware.thermal.V2_0.Temperature temperature) {
- android.os.Temperature thermalSvcTemp = new android.os.Temperature(
- temperature.value, temperature.type, temperature.name,
- temperature.throttlingStatus);
- final long token = Binder.clearCallingIdentity();
- try {
- notifyThrottlingImpl(thermalSvcTemp);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- };
-
- /** HWbinder callback for Thermal HAL 1.1. */
- private final IThermalCallback.Stub mThermalCallback11 =
- new IThermalCallback.Stub() {
- @Override
- public void notifyThrottling(boolean isThrottling,
- android.hardware.thermal.V1_0.Temperature temperature) {
- android.os.Temperature thermalSvcTemp = new android.os.Temperature(
- temperature.currentValue, temperature.type, temperature.name,
- isThrottling ? ThrottlingSeverity.SEVERE : ThrottlingSeverity.NONE);
- final long token = Binder.clearCallingIdentity();
- try {
- notifyThrottlingImpl(thermalSvcTemp);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- };
+ /** Invalid throttling status */
+ private static final int INVALID_THROTTLING = Integer.MIN_VALUE;
public ThermalManagerService(Context context) {
+ this(context, null);
+ }
+
+ @VisibleForTesting
+ ThermalManagerService(Context context, @Nullable ThermalHalWrapper halWrapper) {
super(context);
mPowerManager = context.getSystemService(PowerManager.class);
+ mHalWrapper = halWrapper;
+ // Initialize to invalid to send status onActivityManagerReady
+ mStatus = INVALID_THROTTLING;
}
- private void setNewListener(IThermalEventListener listener, Integer type) {
- synchronized (mLock) {
- mNewListenerCallback = listener;
- mNewListenerType = type;
+ @Override
+ public void onStart() {
+ publishBinderService(Context.THERMAL_SERVICE, mService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ onActivityManagerReady();
}
}
- private void clearNewListener() {
+ private void onActivityManagerReady() {
synchronized (mLock) {
- mNewListenerCallback = null;
- mNewListenerType = null;
- }
- }
-
- private final IThermalService.Stub mService = new IThermalService.Stub() {
- @Override
- public void registerThermalEventListener(IThermalEventListener listener) {
- synchronized (mLock) {
- mThermalEventListeners.register(listener, null);
- // Notify its callback after new client registered.
- setNewListener(listener, null);
- long token = Binder.clearCallingIdentity();
- try {
- notifyCurrentTemperaturesLocked();
- } finally {
- Binder.restoreCallingIdentity(token);
- clearNewListener();
+ // Connect to HAL and post to listeners.
+ boolean halConnected = (mHalWrapper != null);
+ if (!halConnected) {
+ mHalWrapper = new ThermalHal20Wrapper();
+ halConnected = mHalWrapper.connectToHal();
+ if (!halConnected) {
+ mHalWrapper = new ThermalHal11Wrapper();
+ halConnected = mHalWrapper.connectToHal();
}
}
- }
-
- @Override
- public void registerThermalEventListenerWithType(IThermalEventListener listener, int type) {
- synchronized (mLock) {
- mThermalEventListeners.register(listener, new Integer(type));
- setNewListener(listener, new Integer(type));
- // Notify its callback after new client registered.
- long token = Binder.clearCallingIdentity();
- try {
- notifyCurrentTemperaturesLocked();
- } finally {
- Binder.restoreCallingIdentity(token);
- clearNewListener();
- }
+ mHalWrapper.setCallback(this::onTemperatureChangedCallback);
+ if (!halConnected) {
+ return;
}
- }
-
- @Override
- public void unregisterThermalEventListener(IThermalEventListener listener) {
- synchronized (mLock) {
- long token = Binder.clearCallingIdentity();
- try {
- mThermalEventListeners.unregister(listener);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ List<Temperature> temperatures = mHalWrapper.getCurrentTemperatures(false,
+ 0);
+ final int count = temperatures.size();
+ for (int i = 0; i < count; i++) {
+ onTemperatureChanged(temperatures.get(i), false);
}
+ onTemperatureMapChangedLocked();
+ mHalReady = halConnected /* true */;
}
-
- @Override
- public List<android.os.Temperature> getCurrentTemperatures() {
- List<android.os.Temperature> ret;
- long token = Binder.clearCallingIdentity();
- try {
- ret = getCurrentTemperaturesInternal(false, 0 /* not used */);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- return ret;
- }
-
- @Override
- public List<android.os.Temperature> getCurrentTemperaturesWithType(int type) {
- List<android.os.Temperature> ret;
- long token = Binder.clearCallingIdentity();
- try {
- ret = getCurrentTemperaturesInternal(true, type);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- return ret;
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
- pw.println("ThermalEventListeners dump:");
- synchronized (mLock) {
- mThermalEventListeners.dump(pw, "\t");
- pw.println("ThermalHAL 1.1 connected: " + (mThermalHal11 != null ? "yes" : "no"));
- pw.println("ThermalHAL 2.0 connected: " + (mThermalHal20 != null ? "yes" : "no"));
- }
- }
- };
-
- private List<android.os.Temperature> getCurrentTemperaturesInternal(boolean shouldFilter,
- int type) {
- List<android.os.Temperature> ret = new ArrayList<>();
- synchronized (mLock) {
- if (mThermalHal20 == null) {
- return ret;
- }
- try {
- mThermalHal20.getCurrentTemperatures(shouldFilter, type,
- (ThermalStatus status,
- ArrayList<android.hardware.thermal.V2_0.Temperature>
- temperatures) -> {
- if (ThermalStatusCode.SUCCESS == status.code) {
- for (android.hardware.thermal.V2_0.Temperature
- temperature : temperatures) {
- ret.add(new android.os.Temperature(
- temperature.value, temperature.type, temperature.name,
- temperature.throttlingStatus));
- }
- } else {
- Slog.e(TAG,
- "Couldn't get temperatures because of HAL error: "
- + status.debugMessage);
- }
-
- });
- } catch (RemoteException e) {
- Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
- connectToHalLocked();
- // Post to listeners after reconnect to HAL.
- notifyCurrentTemperaturesLocked();
- }
- }
- return ret;
}
- private void notifyListener(android.os.Temperature temperature, IThermalEventListener listener,
- Integer type) {
+ private void postStatusListener(IThermalStatusListener listener) {
+ final boolean thermalCallbackQueued = FgThread.getHandler().post(() -> {
+ try {
+ listener.onStatusChange(mStatus);
+ } catch (RemoteException | RuntimeException e) {
+ Slog.e(TAG, "Thermal callback failed to call", e);
+ }
+ });
+ if (!thermalCallbackQueued) {
+ Slog.e(TAG, "Thermal callback failed to queue");
+ }
+ }
+
+ private void notifyStatusListenersLocked() {
+ if (!Temperature.isValidStatus(mStatus)) {
+ return;
+ }
+ final int length = mThermalStatusListeners.beginBroadcast();
+ try {
+ for (int i = 0; i < length; i++) {
+ final IThermalStatusListener listener =
+ mThermalStatusListeners.getBroadcastItem(i);
+ postStatusListener(listener);
+ }
+ } finally {
+ mThermalStatusListeners.finishBroadcast();
+ }
+ }
+
+ private void onTemperatureMapChangedLocked() {
+ int newStatus = INVALID_THROTTLING;
+ final int count = mTemperatureMap.size();
+ for (int i = 0; i < count; i++) {
+ Temperature t = mTemperatureMap.valueAt(i);
+ if (t.getStatus() >= newStatus) {
+ newStatus = t.getStatus();
+ }
+ }
+ if (newStatus != mStatus) {
+ mStatus = newStatus;
+ notifyStatusListenersLocked();
+ }
+ }
+
+
+ private void postEventListenerCurrentTemperatures(IThermalEventListener listener,
+ @Nullable Integer type) {
+ synchronized (mLock) {
+ final int count = mTemperatureMap.size();
+ for (int i = 0; i < count; i++) {
+ postEventListener(mTemperatureMap.valueAt(i), listener,
+ type);
+ }
+ }
+ }
+
+ private void postEventListener(Temperature temperature,
+ IThermalEventListener listener,
+ @Nullable Integer type) {
// Skip if listener registered with a different type
if (type != null && type != temperature.getType()) {
return;
@@ -271,11 +221,26 @@
}
}
- private void notifyThrottlingImpl(android.os.Temperature temperature) {
+ private void notifyEventListenersLocked(Temperature temperature) {
+ final int length = mThermalEventListeners.beginBroadcast();
+ try {
+ for (int i = 0; i < length; i++) {
+ final IThermalEventListener listener =
+ mThermalEventListeners.getBroadcastItem(i);
+ final Integer type =
+ (Integer) mThermalEventListeners.getBroadcastCookie(i);
+ postEventListener(temperature, listener, type);
+ }
+ } finally {
+ mThermalEventListeners.finishBroadcast();
+ }
+ }
+
+ private void onTemperatureChanged(Temperature temperature, boolean sendStatus) {
synchronized (mLock) {
// Thermal Shutdown for Skin temperature
- if (temperature.getStatus() == android.os.Temperature.THROTTLING_SHUTDOWN
- && temperature.getType() == android.os.Temperature.TYPE_SKIN) {
+ if (temperature.getStatus() == Temperature.THROTTLING_SHUTDOWN
+ && temperature.getType() == Temperature.TYPE_SKIN) {
final long token = Binder.clearCallingIdentity();
try {
mPowerManager.shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
@@ -284,107 +249,420 @@
}
}
- if (mNewListenerCallback != null) {
- // Only notify current newly added callback.
- notifyListener(temperature, mNewListenerCallback, mNewListenerType);
+ Temperature old = mTemperatureMap.put(temperature.getName(), temperature);
+ if (old != null) {
+ if (old.getStatus() != temperature.getStatus()) {
+ notifyEventListenersLocked(temperature);
+ }
} else {
- final int length = mThermalEventListeners.beginBroadcast();
- try {
- for (int i = 0; i < length; i++) {
- final IThermalEventListener listener =
- mThermalEventListeners.getBroadcastItem(i);
- final Integer type = (Integer) mThermalEventListeners.getBroadcastCookie(i);
- notifyListener(temperature, listener, type);
- }
- } finally {
- mThermalEventListeners.finishBroadcast();
- }
+ notifyEventListenersLocked(temperature);
+ }
+ if (sendStatus) {
+ onTemperatureMapChangedLocked();
}
}
}
- @Override
- public void onStart() {
- publishBinderService(Context.THERMAL_SERVICE, mService);
+ private void onTemperatureChangedCallback(Temperature temperature) {
+ onTemperatureChanged(temperature, true);
}
- @Override
- public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
- onActivityManagerReady();
+ private void dumpTemperaturesLocked(PrintWriter pw, String prefix,
+ Collection<Temperature> temperatures) {
+ for (Temperature t : temperatures) {
+ pw.print(prefix);
+ String out = String.format("Name: %s, Type: %d, Status: %d, Value: %f",
+ t.getName(),
+ t.getType(),
+ t.getStatus(),
+ t.getValue()
+ );
+ pw.println(out);
}
}
- private void notifyCurrentTemperaturesCallbackLocked(ThermalStatus status,
- ArrayList<android.hardware.thermal.V2_0.Temperature> temperatures) {
- if (ThermalStatusCode.SUCCESS != status.code) {
- Slog.e(TAG, "Couldn't get temperatures because of HAL error: "
- + status.debugMessage);
- return;
- }
- for (android.hardware.thermal.V2_0.Temperature temperature : temperatures) {
- android.os.Temperature thermal_svc_temp =
- new android.os.Temperature(
- temperature.value, temperature.type,
- temperature.name,
- temperature.throttlingStatus);
- notifyThrottlingImpl(thermal_svc_temp);
- }
- }
-
- private void notifyCurrentTemperaturesLocked() {
- if (mThermalHal20 == null) {
- return;
- }
- try {
- mThermalHal20.getCurrentTemperatures(false, 0,
- this::notifyCurrentTemperaturesCallbackLocked);
- } catch (RemoteException e) {
- Slog.e(TAG, "Couldn't get temperatures, reconnecting...", e);
- connectToHalLocked();
- }
- }
-
- private void onActivityManagerReady() {
- synchronized (mLock) {
- connectToHalLocked();
- // Post to listeners after connect to HAL.
- notifyCurrentTemperaturesLocked();
- }
- }
-
- final class DeathRecipient implements HwBinder.DeathRecipient {
+ @VisibleForTesting
+ final IThermalService.Stub mService = new IThermalService.Stub() {
@Override
- public void serviceDied(long cookie) {
- if (cookie == THERMAL_HAL_DEATH_COOKIE) {
- Slog.e(TAG, "Thermal HAL service died cookie: " + cookie);
+ public boolean registerThermalEventListener(IThermalEventListener listener) {
+ synchronized (mLock) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mThermalEventListeners.register(listener, null)) {
+ return false;
+ }
+ if (mHalReady) {
+ // Notify its callback after new client registered.
+ postEventListenerCurrentTemperatures(listener, null);
+ }
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ @Override
+ public boolean registerThermalEventListenerWithType(IThermalEventListener listener,
+ int type) {
+ synchronized (mLock) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mThermalEventListeners.register(listener, new Integer(type))) {
+ return false;
+ }
+ if (mHalReady) {
+ // Notify its callback after new client registered.
+ postEventListenerCurrentTemperatures(listener, new Integer(type));
+ }
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ @Override
+ public boolean unregisterThermalEventListener(IThermalEventListener listener) {
+ synchronized (mLock) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mThermalEventListeners.unregister(listener);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ @Override
+ public List<Temperature> getCurrentTemperatures() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mHalReady) {
+ return new ArrayList<>();
+ }
+ return mHalWrapper.getCurrentTemperatures(false, 0 /* not used */);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public List<Temperature> getCurrentTemperaturesWithType(int type) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mHalReady) {
+ return new ArrayList<>();
+ }
+ return mHalWrapper.getCurrentTemperatures(true, type);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public boolean registerThermalStatusListener(IThermalStatusListener listener) {
+ synchronized (mLock) {
+ // Notify its callback after new client registered.
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mThermalStatusListeners.register(listener)) {
+ return false;
+ }
+ if (mHalReady) {
+ // Notify its callback after new client registered.
+ postStatusListener(listener);
+ }
+ return true;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ @Override
+ public boolean unregisterThermalStatusListener(IThermalStatusListener listener) {
+ synchronized (mLock) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mThermalStatusListeners.unregister(listener);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ @Override
+ public int getCurrentStatus() {
+ synchronized (mLock) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return Temperature.isValidStatus(mStatus) ? mStatus
+ : Temperature.THROTTLING_NONE;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
+ return;
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
synchronized (mLock) {
- connectToHalLocked();
- // Post to listeners after reconnect to HAL.
- notifyCurrentTemperaturesLocked();
+ pw.println("ThermalEventListeners:");
+ mThermalEventListeners.dump(pw, "\t");
+ pw.println("ThermalStatusListeners:");
+ mThermalStatusListeners.dump(pw, "\t");
+ pw.println("Thermal Status: " + Integer.toString(mStatus));
+ pw.println("Cached temperatures:");
+ dumpTemperaturesLocked(pw, "\t", mTemperatureMap.values());
+ pw.println("HAL Ready: " + Boolean.toString(mHalReady));
+ if (mHalReady) {
+ pw.println("HAL connection:");
+ mHalWrapper.dump(pw, "\t");
+ pw.println("Current temperatures from HAL:");
+ dumpTemperaturesLocked(pw, "\t",
+ mHalWrapper.getCurrentTemperatures(false, 0));
+ }
+ }
+
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ };
+
+ abstract static class ThermalHalWrapper {
+ protected static final String TAG = ThermalHalWrapper.class.getSimpleName();
+
+ /** Lock to protect HAL handle. */
+ protected final Object mHalLock = new Object();
+
+ @FunctionalInterface
+ interface TemperatureChangedCallback {
+ void onValues(Temperature temperature);
+ }
+
+ /** Temperature callback. */
+ protected TemperatureChangedCallback mCallback;
+
+ /** Cookie for matching the right end point. */
+ protected static final int THERMAL_HAL_DEATH_COOKIE = 5612;
+
+ @VisibleForTesting
+ protected void setCallback(TemperatureChangedCallback cb) {
+ mCallback = cb;
+ }
+
+ protected abstract List<Temperature> getCurrentTemperatures(boolean shouldFilter,
+ int type);
+
+ protected abstract boolean connectToHal();
+
+ protected abstract void dump(PrintWriter pw, String prefix);
+
+ protected void resendCurrentTemperatures() {
+ synchronized (mHalLock) {
+ List<Temperature> temperatures = getCurrentTemperatures(false, 0);
+ final int count = temperatures.size();
+ for (int i = 0; i < count; i++) {
+ mCallback.onValues(temperatures.get(i));
+ }
+ }
+ }
+
+ final class DeathRecipient implements HwBinder.DeathRecipient {
+ @Override
+ public void serviceDied(long cookie) {
+ if (cookie == THERMAL_HAL_DEATH_COOKIE) {
+ Slog.e(TAG, "Thermal HAL service died cookie: " + cookie);
+ synchronized (mHalLock) {
+ connectToHal();
+ // Post to listeners after reconnect to HAL.
+ resendCurrentTemperatures();
+ }
}
}
}
}
- private void connectToHalLocked() {
- try {
- mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService();
- mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
- mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
- 0 /* not used */);
- } catch (NoSuchElementException | RemoteException e) {
- Slog.e(TAG, "Thermal HAL 2.0 service not connected, trying 1.1.");
- mThermalHal20 = null;
- try {
- mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService();
- mThermalHal11.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
- mThermalHal11.registerThermalCallback(mThermalCallback11);
- } catch (NoSuchElementException | RemoteException e2) {
- Slog.e(TAG,
- "Thermal HAL 1.1 service not connected, no thermal call back "
- + "will be called.");
- mThermalHal11 = null;
+ static class ThermalHal11Wrapper extends ThermalHalWrapper {
+ /** Proxy object for the Thermal HAL 1.1 service. */
+ @GuardedBy("mHalLock")
+ private android.hardware.thermal.V1_1.IThermal mThermalHal11 = null;
+
+ /** HWbinder callback for Thermal HAL 1.1. */
+ private final IThermalCallback.Stub mThermalCallback11 =
+ new IThermalCallback.Stub() {
+ @Override
+ public void notifyThrottling(boolean isThrottling,
+ android.hardware.thermal.V1_0.Temperature temperature) {
+ Temperature thermalSvcTemp = new Temperature(
+ temperature.currentValue, temperature.type, temperature.name,
+ isThrottling ? ThrottlingSeverity.SEVERE
+ : ThrottlingSeverity.NONE);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.onValues(thermalSvcTemp);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ };
+
+ @Override
+ protected List<Temperature> getCurrentTemperatures(boolean shouldFilter,
+ int type) {
+ synchronized (mHalLock) {
+ List<Temperature> ret = new ArrayList<>();
+ if (mThermalHal11 == null) {
+ return ret;
+ }
+ try {
+ mThermalHal11.getTemperatures(
+ (ThermalStatus status,
+ ArrayList<android.hardware.thermal.V1_0.Temperature>
+ temperatures) -> {
+ if (ThermalStatusCode.SUCCESS == status.code) {
+ for (android.hardware.thermal.V1_0.Temperature
+ temperature : temperatures) {
+ if (shouldFilter && type != temperature.type) {
+ continue;
+ }
+ // Thermal HAL 1.1 doesn't report current throttling status
+ ret.add(new Temperature(
+ temperature.currentValue, temperature.type,
+ temperature.name,
+ Temperature.THROTTLING_NONE));
+ }
+ } else {
+ Slog.e(TAG,
+ "Couldn't get temperatures because of HAL error: "
+ + status.debugMessage);
+ }
+
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
+ connectToHal();
+ }
+ return ret;
+ }
+ }
+
+ @Override
+ protected boolean connectToHal() {
+ synchronized (mHalLock) {
+ try {
+ mThermalHal11 = android.hardware.thermal.V1_1.IThermal.getService();
+ mThermalHal11.linkToDeath(new DeathRecipient(),
+ THERMAL_HAL_DEATH_COOKIE);
+ mThermalHal11.registerThermalCallback(mThermalCallback11);
+ } catch (NoSuchElementException | RemoteException e) {
+ Slog.e(TAG,
+ "Thermal HAL 1.1 service not connected, no thermal call back will be "
+ + "called.");
+ mThermalHal11 = null;
+ }
+ return (mThermalHal11 != null);
+ }
+ }
+
+ @Override
+ protected void dump(PrintWriter pw, String prefix) {
+ synchronized (mHalLock) {
+ pw.print(prefix);
+ pw.println("ThermalHAL 1.1 connected: " + (mThermalHal11 != null ? "yes"
+ : "no"));
+ }
+ }
+ }
+
+ static class ThermalHal20Wrapper extends ThermalHalWrapper {
+ /** Proxy object for the Thermal HAL 2.0 service. */
+ @GuardedBy("mHalLock")
+ private android.hardware.thermal.V2_0.IThermal mThermalHal20 = null;
+
+ /** HWbinder callback for Thermal HAL 2.0. */
+ private final IThermalChangedCallback.Stub mThermalCallback20 =
+ new IThermalChangedCallback.Stub() {
+ @Override
+ public void notifyThrottling(
+ android.hardware.thermal.V2_0.Temperature temperature) {
+ Temperature thermalSvcTemp = new Temperature(
+ temperature.value, temperature.type, temperature.name,
+ temperature.throttlingStatus);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.onValues(thermalSvcTemp);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ };
+
+ @Override
+ protected List<Temperature> getCurrentTemperatures(boolean shouldFilter,
+ int type) {
+ synchronized (mHalLock) {
+ List<Temperature> ret = new ArrayList<>();
+ if (mThermalHal20 == null) {
+ return ret;
+ }
+ try {
+ mThermalHal20.getCurrentTemperatures(shouldFilter, type,
+ (ThermalStatus status,
+ ArrayList<android.hardware.thermal.V2_0.Temperature>
+ temperatures) -> {
+ if (ThermalStatusCode.SUCCESS == status.code) {
+ for (android.hardware.thermal.V2_0.Temperature
+ temperature : temperatures) {
+ ret.add(new Temperature(
+ temperature.value, temperature.type,
+ temperature.name,
+ temperature.throttlingStatus));
+ }
+ } else {
+ Slog.e(TAG,
+ "Couldn't get temperatures because of HAL error: "
+ + status.debugMessage);
+ }
+
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't getCurrentTemperatures, reconnecting...", e);
+ connectToHal();
+ }
+ return ret;
+ }
+ }
+
+ @Override
+ protected boolean connectToHal() {
+ synchronized (mHalLock) {
+ try {
+ mThermalHal20 = android.hardware.thermal.V2_0.IThermal.getService();
+ mThermalHal20.linkToDeath(new DeathRecipient(), THERMAL_HAL_DEATH_COOKIE);
+ mThermalHal20.registerThermalChangedCallback(mThermalCallback20, false,
+ 0 /* not used */);
+ } catch (NoSuchElementException | RemoteException e) {
+ Slog.e(TAG, "Thermal HAL 2.0 service not connected, trying 1.1.");
+ mThermalHal20 = null;
+ }
+ return (mThermalHal20 != null);
+ }
+ }
+
+ @Override
+ protected void dump(PrintWriter pw, String prefix) {
+ synchronized (mHalLock) {
+ pw.print(prefix);
+ pw.println("ThermalHAL 2.0 connected: " + (mThermalHal20 != null ? "yes"
+ : "no"));
}
}
}
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index d2ca850..6f6846d 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -1630,37 +1630,42 @@
if (this.mKernelCpuThreadReader == null) {
return;
}
- KernelCpuThreadReader.ProcessCpuUsage processCpuUsage = this.mKernelCpuThreadReader
- .getCurrentProcessCpuUsage();
- if (processCpuUsage == null) {
+ ArrayList<KernelCpuThreadReader.ProcessCpuUsage> processCpuUsages =
+ this.mKernelCpuThreadReader.getProcessCpuUsageByUids();
+ if (processCpuUsages == null) {
return;
}
int[] cpuFrequencies = mKernelCpuThreadReader.getCpuFrequenciesKhz();
- for (KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage
- : processCpuUsage.threadCpuUsages) {
- if (threadCpuUsage.usageTimesMillis.length != cpuFrequencies.length) {
- Slog.w(TAG, "Unexpected number of usage times,"
- + " expected " + cpuFrequencies.length
- + " but got " + threadCpuUsage.usageTimesMillis.length);
- continue;
- }
-
- for (int i = 0; i < threadCpuUsage.usageTimesMillis.length; i++) {
- // Do not report CPU usage at a frequency when it's zero
- if (threadCpuUsage.usageTimesMillis[i] == 0) {
+ for (int i = 0; i < processCpuUsages.size(); i++) {
+ KernelCpuThreadReader.ProcessCpuUsage processCpuUsage = processCpuUsages.get(i);
+ ArrayList<KernelCpuThreadReader.ThreadCpuUsage> threadCpuUsages =
+ processCpuUsage.threadCpuUsages;
+ for (int j = 0; j < threadCpuUsages.size(); j++) {
+ KernelCpuThreadReader.ThreadCpuUsage threadCpuUsage = threadCpuUsages.get(j);
+ if (threadCpuUsage.usageTimesMillis.length != cpuFrequencies.length) {
+ Slog.w(TAG, "Unexpected number of usage times,"
+ + " expected " + cpuFrequencies.length
+ + " but got " + threadCpuUsage.usageTimesMillis.length);
continue;
}
- StatsLogEventWrapper e =
- new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
- e.writeInt(processCpuUsage.uid);
- e.writeInt(processCpuUsage.processId);
- e.writeInt(threadCpuUsage.threadId);
- e.writeString(processCpuUsage.processName);
- e.writeString(threadCpuUsage.threadName);
- e.writeInt(cpuFrequencies[i]);
- e.writeInt(threadCpuUsage.usageTimesMillis[i]);
- pulledData.add(e);
+ for (int k = 0; k < threadCpuUsage.usageTimesMillis.length; k++) {
+ // Do not report CPU usage at a frequency when it's zero
+ if (threadCpuUsage.usageTimesMillis[k] == 0) {
+ continue;
+ }
+
+ StatsLogEventWrapper e =
+ new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+ e.writeInt(processCpuUsage.uid);
+ e.writeInt(processCpuUsage.processId);
+ e.writeInt(threadCpuUsage.threadId);
+ e.writeString(processCpuUsage.processName);
+ e.writeString(threadCpuUsage.threadName);
+ e.writeInt(cpuFrequencies[k]);
+ e.writeInt(threadCpuUsage.usageTimesMillis[k]);
+ pulledData.add(e);
+ }
}
}
}
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/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 5ce8145..8d27d1e 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -28,18 +28,22 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.service.textclassifier.IConversationActionsCallback;
import android.service.textclassifier.ITextClassificationCallback;
import android.service.textclassifier.ITextClassifierService;
+import android.service.textclassifier.ITextLanguageCallback;
import android.service.textclassifier.ITextLinksCallback;
import android.service.textclassifier.ITextSelectionCallback;
import android.service.textclassifier.TextClassifierService;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationContext;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassificationSessionId;
+import android.view.textclassifier.TextLanguage;
import android.view.textclassifier.TextLinks;
import android.view.textclassifier.TextSelection;
@@ -210,6 +214,50 @@
}
@Override
+ public void onDetectLanguage(
+ TextClassificationSessionId sessionId,
+ TextLanguage.Request request,
+ ITextLanguageCallback callback) throws RemoteException {
+ Preconditions.checkNotNull(request);
+ Preconditions.checkNotNull(callback);
+
+ synchronized (mLock) {
+ UserState userState = getCallingUserStateLocked();
+ if (!userState.bindLocked()) {
+ callback.onFailure();
+ } else if (userState.isBoundLocked()) {
+ userState.mService.onDetectLanguage(sessionId, request, callback);
+ } else {
+ userState.mPendingRequests.add(new PendingRequest(
+ () -> onDetectLanguage(sessionId, request, callback),
+ callback::onFailure, callback.asBinder(), this, userState));
+ }
+ }
+ }
+
+ @Override
+ public void onSuggestConversationActions(
+ TextClassificationSessionId sessionId,
+ ConversationActions.Request request,
+ IConversationActionsCallback callback) throws RemoteException {
+ Preconditions.checkNotNull(request);
+ Preconditions.checkNotNull(callback);
+
+ synchronized (mLock) {
+ UserState userState = getCallingUserStateLocked();
+ if (!userState.bindLocked()) {
+ callback.onFailure();
+ } else if (userState.isBoundLocked()) {
+ userState.mService.onSuggestConversationActions(sessionId, request, callback);
+ } else {
+ userState.mPendingRequests.add(new PendingRequest(
+ () -> onSuggestConversationActions(sessionId, request, callback),
+ callback::onFailure, callback.asBinder(), this, userState));
+ }
+ }
+ }
+
+ @Override
public void onCreateTextClassificationSession(
TextClassificationContext classificationContext, TextClassificationSessionId sessionId)
throws RemoteException {
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index c4d2851..da0a794 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -48,7 +48,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
import libcore.icu.ICU;
import libcore.timezone.TzDataSetVersion;
-import libcore.util.TimeZoneFinder;
+import libcore.timezone.TimeZoneFinder;
import libcore.util.ZoneInfoDB;
import static android.app.timezone.RulesState.DISTRO_STATUS_INSTALLED;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 479f427..409d2b4 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -18,6 +18,7 @@
import static android.app.WallpaperManager.FLAG_LOCK;
import static android.app.WallpaperManager.FLAG_SYSTEM;
+import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO;
import static android.os.ParcelFileDescriptor.MODE_CREATE;
import static android.os.ParcelFileDescriptor.MODE_READ_ONLY;
import static android.os.ParcelFileDescriptor.MODE_READ_WRITE;
@@ -56,6 +57,7 @@
import android.graphics.BitmapRegionDecoder;
import android.graphics.Color;
import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
import android.os.Binder;
import android.os.Bundle;
import android.os.Environment;
@@ -118,6 +120,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.function.Consumer;
public class WallpaperManagerService extends IWallpaperManager.Stub
implements IWallpaperManagerService {
@@ -640,6 +643,43 @@
final IPackageManager mIPackageManager;
final MyPackageMonitor mMonitor;
final AppOpsManager mAppOpsManager;
+
+ private final DisplayManager mDisplayManager;
+ private final DisplayManager.DisplayListener mDisplayListener =
+ new DisplayManager.DisplayListener() {
+
+ @Override
+ public void onDisplayAdded(int displayId) {
+ synchronized (mLock) {
+ if (mLastWallpaper != null) {
+ final WallpaperConnection.DisplayConnector connector =
+ mLastWallpaper.connection.getDisplayConnectorOrCreate(displayId);
+ if (connector == null) return;
+
+ connector.connectLocked(mLastWallpaper.connection, mLastWallpaper);
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ synchronized (mLock) {
+ if (mLastWallpaper != null) {
+ final WallpaperConnection.DisplayConnector connector =
+ mLastWallpaper.connection.getDisplayConnectorOrCreate(displayId);
+ if (connector == null) return;
+ connector.disconnectLocked();
+ mLastWallpaper.connection.removeDisplayConnector(displayId);
+ }
+ }
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ // TODO(b/115486823) Review that do we need to handle display changes.
+ }
+ };
+
/**
* Map of color listeners per user id.
* The key will be the id of a user or UserHandle.USER_ALL - for wildcard listeners.
@@ -775,20 +815,96 @@
class WallpaperConnection extends IWallpaperConnection.Stub
implements ServiceConnection {
+ /**
+ * Collect needed info for a display.
+ */
+ private final class DisplayConnector {
+ final int mDisplayId;
+ final Binder mToken = new Binder();
+ IWallpaperEngine mEngine;
+ boolean mDimensionsChanged;
+ boolean mPaddingChanged;
+
+ DisplayConnector(int displayId) {
+ mDisplayId = displayId;
+ }
+
+ void ensureStatusHandled() {
+ if (mDimensionsChanged) {
+ try {
+ mEngine.setDesiredSize(mWallpaper.width, mWallpaper.height);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to set wallpaper dimensions", e);
+ }
+ mDimensionsChanged = false;
+ }
+ if (mPaddingChanged) {
+ try {
+ mEngine.setDisplayPadding(mWallpaper.padding);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to set wallpaper padding", e);
+ }
+ mPaddingChanged = false;
+ }
+ }
+
+ void connectLocked(WallpaperConnection connection, WallpaperData wallpaper) {
+ if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken);
+ try {
+ mIWindowManager.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed add wallpaper window token on display " + mDisplayId, e);
+ return;
+ }
+
+ 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);
+ } 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) {
+ bindWallpaperComponentLocked(null /* componentName */, false /* force */,
+ false /* fromUser */, wallpaper, null /* reply */);
+ }
+ }
+ }
+
+ void disconnectLocked() {
+ if (DEBUG) Slog.v(TAG, "Removing window token: " + mToken);
+ try {
+ mIWindowManager.removeWindowToken(mToken, mDisplayId);
+ } catch (RemoteException e) {
+ }
+ try {
+ if (mEngine != null) {
+ mEngine.destroy();
+ }
+ } catch (RemoteException e) {
+ }
+ mEngine = null;
+ }
+ }
+
+ /**
+ * A map for each display.
+ * Use {@link #getDisplayConnectorOrCreate(int displayId)} to ensure the display is usable.
+ */
+ private SparseArray<DisplayConnector> mDisplayConnector = new SparseArray<>();
+
/** Time in milliseconds until we expect the wallpaper to reconnect (unless we're in the
* middle of an update). If exceeded, the wallpaper gets reset to the system default. */
private static final long WALLPAPER_RECONNECT_TIMEOUT_MS = 10000;
final WallpaperInfo mInfo;
- final Binder mToken = new Binder();
IWallpaperService mService;
- IWallpaperEngine mEngine;
WallpaperData mWallpaper;
+ final int mClientUid;
IRemoteCallback mReply;
- boolean mDimensionsChanged = false;
- boolean mPaddingChanged = false;
-
private Runnable mResetRunnable = () -> {
synchronized (mLock) {
if (mShuttingDown) {
@@ -809,9 +925,55 @@
}
};
- public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
+ WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper, int clientUid) {
mInfo = info;
mWallpaper = wallpaper;
+ mClientUid = clientUid;
+ initDisplayState();
+ }
+
+ private void initDisplayState() {
+ final Display[] displays = mDisplayManager.getDisplays();
+ for (Display display : displays) {
+ if (isUsableDisplay(display)) {
+ final int displayId = display.getDisplayId();
+ mDisplayConnector.append(displayId, new DisplayConnector(displayId));
+ }
+ }
+ }
+
+ // TODO(b/115486823) Support the system decorations change at runtime.
+ private boolean isUsableDisplay(Display display) {
+ return display != null && display.hasAccess(mClientUid)
+ // TODO(b/114338689) Use WindowManager.supportsSystemDecorations when ready
+ && (display.supportsSystemDecorations()
+ || display.getDisplayId() == DEFAULT_DISPLAY);
+ }
+
+ void forEachDisplayConnector(Consumer<DisplayConnector> action) {
+ for (int i = mDisplayConnector.size() - 1; i >= 0; i--) {
+ final DisplayConnector connector = mDisplayConnector.get(i);
+ action.accept(connector);
+ }
+ }
+
+ DisplayConnector getDisplayConnectorOrCreate(int displayId) {
+ DisplayConnector connector = mDisplayConnector.get(displayId);
+ if (connector == null) {
+ final Display display = mDisplayManager.getDisplay(displayId);
+ if (isUsableDisplay(display)) {
+ connector = new DisplayConnector(displayId);
+ mDisplayConnector.append(displayId, connector);
+ }
+ }
+ return connector;
+ }
+
+ void removeDisplayConnector(int displayId) {
+ final DisplayConnector connector = mDisplayConnector.get(displayId);
+ if (connector != null) {
+ mDisplayConnector.remove(displayId);
+ }
}
@Override
@@ -839,7 +1001,7 @@
+ mWallpaper.wallpaperComponent);
}
mService = null;
- mEngine = null;
+ forEachDisplayConnector(connector -> connector.mEngine = null);
if (mWallpaper.connection == this) {
// There is an inherent ordering race between this callback and the
// package monitor that receives notice that a package is being updated,
@@ -863,7 +1025,8 @@
fgHandler.removeCallbacks(mResetRunnable);
fgHandler.postDelayed(mResetRunnable, WALLPAPER_RECONNECT_TIMEOUT_MS);
if (DEBUG_LIVE) {
- Slog.i(TAG, "Started wallpaper reconnect timeout for " + mWallpaper.wallpaperComponent);
+ Slog.i(TAG,
+ "Started wallpaper reconnect timeout for " + mWallpaper.wallpaperComponent);
}
}
@@ -943,38 +1106,37 @@
}
@Override
- public void attachEngine(IWallpaperEngine engine) {
+ public void attachEngine(IWallpaperEngine engine, int displayId) {
synchronized (mLock) {
- mEngine = engine;
- if (mDimensionsChanged) {
+ final DisplayConnector connector = getDisplayConnectorOrCreate(displayId);
+ if (connector == null) {
try {
- mEngine.setDesiredSize(mWallpaper.width, mWallpaper.height);
+ engine.destroy();
} catch (RemoteException e) {
- Slog.w(TAG, "Failed to set wallpaper dimensions", e);
+ Slog.w(TAG, "Failed to destroy engine", e);
}
- mDimensionsChanged = false;
+ return;
}
- if (mPaddingChanged) {
+ connector.mEngine = engine;
+ connector.ensureStatusHandled();
+
+ // TODO(multi-display) TBD.
+ if (mInfo != null && mInfo.supportsAmbientMode() && displayId == DEFAULT_DISPLAY) {
try {
- mEngine.setDisplayPadding(mWallpaper.padding);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to set wallpaper padding", e);
- }
- mPaddingChanged = false;
- }
- if (mInfo != null && mInfo.supportsAmbientMode()) {
- try {
- mEngine.setInAmbientMode(mInAmbientMode, false /* animated */);
+ connector.mEngine.setInAmbientMode(mInAmbientMode, false /* animated */);
} catch (RemoteException e) {
Slog.w(TAG, "Failed to set ambient mode state", e);
}
}
- try {
- // This will trigger onComputeColors in the wallpaper engine.
- // It's fine to be locked in here since the binder is oneway.
- mEngine.requestWallpaperColors();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to request wallpaper colors", e);
+ // TODO(b/115486823) Extends for secondary display.
+ if (displayId == DEFAULT_DISPLAY) {
+ try {
+ // This will trigger onComputeColors in the wallpaper engine.
+ // It's fine to be locked in here since the binder is oneway.
+ connector.mEngine.requestWallpaperColors();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to request wallpaper colors", e);
+ }
}
}
}
@@ -1162,6 +1324,8 @@
ServiceManager.getService(Context.WINDOW_SERVICE));
mIPackageManager = AppGlobals.getPackageManager();
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ mDisplayManager = mContext.getSystemService(DisplayManager.class);
+ mDisplayManager.registerDisplayListener(mDisplayListener, null /* handler */);
mMonitor = new MyPackageMonitor();
mColorsChangedListeners = new SparseArray<>();
}
@@ -1541,6 +1705,7 @@
return false;
}
+ // TODO(b/115486823) Extends this method with specific display.
public void setDimensionHints(int width, int height, String callingPackage)
throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
@@ -1560,10 +1725,12 @@
saveSettingsLocked(userId);
if (mCurrentUserId != userId) return; // Don't change the properties now
if (wallpaper.connection != null) {
- if (wallpaper.connection.mEngine != null) {
+ // TODO(b/115486823) Extends this method with specific display.
+ final IWallpaperEngine engine = wallpaper.connection
+ .getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
+ if (engine != null) {
try {
- wallpaper.connection.mEngine.setDesiredSize(
- width, height);
+ engine.setDesiredSize(width, height);
} catch (RemoteException e) {
}
notifyCallbacksLocked(wallpaper);
@@ -1571,7 +1738,9 @@
// 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.
- wallpaper.connection.mDimensionsChanged = true;
+ // TODO(b/115486823) Extends this method with specific display.
+ wallpaper.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY)
+ .mDimensionsChanged = true;
}
}
}
@@ -1600,6 +1769,7 @@
}
}
+ // TODO(b/115486823) Extends this method with specific display.
public void setDisplayPadding(Rect padding, String callingPackage) {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
if (!isWallpaperSupported(callingPackage)) {
@@ -1617,9 +1787,12 @@
saveSettingsLocked(userId);
if (mCurrentUserId != userId) return; // Don't change the properties now
if (wallpaper.connection != null) {
- if (wallpaper.connection.mEngine != null) {
+ // TODO(b/115486823) Extends this method with specific display.
+ final IWallpaperEngine engine = wallpaper.connection
+ .getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
+ if (engine != null) {
try {
- wallpaper.connection.mEngine.setDisplayPadding(padding);
+ engine.setDisplayPadding(padding);
} catch (RemoteException e) {
}
notifyCallbacksLocked(wallpaper);
@@ -1627,7 +1800,9 @@
// 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.
- wallpaper.connection.mPaddingChanged = true;
+ // TODO(b/115486823) Extends this method with specific display.
+ wallpaper.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY)
+ .mPaddingChanged = true;
}
}
}
@@ -1756,6 +1931,7 @@
}
}
+ // TODO(b/115486823) Extends this method with specific display.
public void setInAmbientMode(boolean inAmbienMode, boolean animated) {
final IWallpaperEngine engine;
synchronized (mLock) {
@@ -1763,7 +1939,8 @@
final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
if (data != null && data.connection != null && data.connection.mInfo != null
&& data.connection.mInfo.supportsAmbientMode()) {
- engine = data.connection.mEngine;
+ // TODO(b/115486823) Extends this method with specific display.
+ engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
} else {
engine = null;
}
@@ -2125,7 +2302,9 @@
// Bind the service!
if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
- WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
+ final int componentUid = mIPackageManager.getPackageUid(componentName.getPackageName(),
+ MATCH_DIRECT_BOOT_AUTO, wallpaper.userId);
+ WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper, componentUid);
intent.setComponent(componentName);
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.wallpaper_binding_label);
@@ -2152,14 +2331,8 @@
wallpaper.wallpaperComponent = componentName;
wallpaper.connection = newConn;
newConn.mReply = reply;
- try {
- if (wallpaper.userId == mCurrentUserId) {
- if (DEBUG)
- Slog.v(TAG, "Adding window token: " + newConn.mToken);
- mIWindowManager.addWindowToken(newConn.mToken, TYPE_WALLPAPER, DEFAULT_DISPLAY);
- mLastWallpaper = wallpaper;
- }
- } catch (RemoteException e) {
+ if (wallpaper.userId == mCurrentUserId) {
+ mLastWallpaper = wallpaper;
}
} catch (RemoteException e) {
String msg = "Remote exception for " + componentName + "\n" + e;
@@ -2181,22 +2354,12 @@
}
wallpaper.connection.mReply = null;
}
- if (wallpaper.connection.mEngine != null) {
- try {
- wallpaper.connection.mEngine.destroy();
- } catch (RemoteException e) {
- }
- }
mContext.unbindService(wallpaper.connection);
- try {
- if (DEBUG)
- Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken);
- mIWindowManager.removeWindowToken(wallpaper.connection.mToken, DEFAULT_DISPLAY);
- } catch (RemoteException e) {
- }
+ wallpaper.connection.forEachDisplayConnector(connector -> connector.disconnectLocked());
wallpaper.connection.mService = null;
- wallpaper.connection.mEngine = null;
+ wallpaper.connection.mDisplayConnector.clear();
wallpaper.connection = null;
+ if (wallpaper == mLastWallpaper) mLastWallpaper = null;
}
}
@@ -2206,16 +2369,7 @@
}
void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
- try {
- conn.mService.attach(conn, conn.mToken,
- TYPE_WALLPAPER, false,
- wallpaper.width, wallpaper.height, wallpaper.padding);
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
- if (!wallpaper.wallpaperUpdating) {
- bindWallpaperComponentLocked(null, false, false, wallpaper, null);
- }
- }
+ conn.forEachDisplayConnector(connector-> connector.connectLocked(conn, wallpaper));
}
private void notifyCallbacksLocked(WallpaperData wallpaper) {
@@ -2801,12 +2955,16 @@
pw.print(" mInfo.component=");
pw.println(conn.mInfo.getComponent());
}
- pw.print(" mToken=");
- pw.println(conn.mToken);
+ conn.forEachDisplayConnector(connector -> {
+ pw.print(" mDisplayId=");
+ pw.println(connector.mDisplayId);
+ pw.print(" mToken=");
+ pw.println(connector.mToken);
+ pw.print(" mEngine=");
+ pw.println(connector.mEngine);
+ });
pw.print(" mService=");
pw.println(conn.mService);
- pw.print(" mEngine=");
- pw.println(conn.mEngine);
pw.print(" mLastDiedTime=");
pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
}
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/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 8d467c8..bd3e43c 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -2548,11 +2548,16 @@
// If the current top activity may be able to occlude keyguard but the occluded state
// has not been set, update visibility and check again if we should continue to resume.
boolean nothingToResume = true;
- if (!mService.mShuttingDown && !mTopActivityOccludesKeyguard
- && next.canShowWhenLocked()) {
- ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
- !PRESERVE_WINDOWS);
- nothingToResume = shouldSleepActivities();
+ if (!mService.mShuttingDown) {
+ final boolean canShowWhenLocked = !mTopActivityOccludesKeyguard
+ && next.canShowWhenLocked();
+ final boolean mayDismissKeyguard = mTopDismissingKeyguardActivity != next
+ && next.hasDismissKeyguardWindows();
+ if (canShowWhenLocked || mayDismissKeyguard) {
+ ensureActivitiesVisibleLocked(null /* starting */, 0 /* configChanges */,
+ !PRESERVE_WINDOWS);
+ nothingToResume = shouldSleepActivities();
+ }
}
if (nothingToResume) {
// Make sure we have executed any pending transitions, since there
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 94a47dd..32a6f74 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -51,7 +51,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
-import android.app.WindowConfiguration;
import android.os.Trace;
import android.util.ArraySet;
import android.util.Slog;
@@ -83,7 +82,7 @@
AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
mDisplayContent = displayContent;
- mWallpaperControllerLocked = new WallpaperController(mService);
+ mWallpaperControllerLocked = mDisplayContent.mWallpaperController;
}
/**
@@ -97,16 +96,17 @@
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();
- mService.mRoot.mWallpaperMayChange = false;
+ mDisplayContent.mWallpaperMayChange = false;
int i;
for (i = 0; i < appsCount; i++) {
@@ -121,7 +121,7 @@
// Adjust wallpaper before we pull the lower/upper target, since pending changes
// (like the clearAnimatingFlags() above) might affect wallpaper target result.
// Or, the opening app window should be a wallpaper target.
- mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(mDisplayContent,
+ mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
mDisplayContent.mOpeningApps);
// Determine if closing and opening app token sets are wallpaper targets, in which case
@@ -142,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;
@@ -166,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();
}
@@ -255,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 ab7d259..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();
/**
@@ -414,6 +413,8 @@
WallpaperController mWallpaperController;
+ boolean mWallpaperMayChange = false;
+
private final SurfaceSession mSession = new SurfaceSession();
/**
@@ -506,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;
@@ -647,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
@@ -686,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()
@@ -706,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 -> {
@@ -751,8 +757,7 @@
}
}
- if (isDefaultDisplay && obscuredChanged && w.isVisibleLw()
- && mWallpaperController.isWallpaperTarget(w)) {
+ if (obscuredChanged && w.isVisibleLw() && mWallpaperController.isWallpaperTarget(w)) {
// This is the wallpaper target and its obscured state changed... make sure the
// current wallpaper's visibility has been updated accordingly.
mWallpaperController.updateWallpaperVisibility();
@@ -784,7 +789,7 @@
if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
"First draw done in potential wallpaper target " + w);
- root.mWallpaperMayChange = true;
+ mWallpaperMayChange = true;
pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
if (DEBUG_LAYOUT_REPEATS) {
surfacePlacer.debugLayoutRepeats(
@@ -816,11 +821,10 @@
* initialize direct children.
* @param display May not be null.
* @param service You know.
- * @param wallpaperController wallpaper windows controller used to adjust the positioning of the
- * wallpaper windows in the window list.
+ * @param controller The controller for the display container.
*/
DisplayContent(Display display, WindowManagerService service,
- WallpaperController wallpaperController, DisplayWindowController controller) {
+ DisplayWindowController controller) {
super(service);
setController(controller);
if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
@@ -831,22 +835,13 @@
mDisplay = display;
mDisplayId = display.getDisplayId();
- mWallpaperController = wallpaperController;
+ mWallpaperController = new WallpaperController(mService, this);
display.getDisplayInfo(mDisplayInfo);
display.getMetrics(mDisplayMetrics);
isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
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,13 @@
}
}
pw.print(" mFocusedApp="); pw.println(mFocusedApp);
+ if (mLastStatusBarVisibility != 0) {
+ pw.print(" mLastStatusBarVisibility=0x");
+ pw.println(Integer.toHexString(mLastStatusBarVisibility));
+ }
+
+ pw.println();
+ mWallpaperController.dump(pw, " ");
pw.println();
pw.println(prefix + "Application tokens in top down Z order:");
@@ -2849,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.
@@ -3318,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 {
@@ -3338,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;
@@ -3369,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();
@@ -3388,12 +3431,8 @@
if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
pendingLayoutChanges);
- // TODO(multi-display): For now adjusting wallpaper only on primary display to avoid
- // the wallpaper window jumping across displays.
- // Remove check for default display when there will be support for multiple wallpaper
- // targets (on different displays).
- if (isDefaultDisplay && (pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
- mWallpaperController.adjustWallpaperWindows(this);
+ if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+ mWallpaperController.adjustWallpaperWindows();
}
if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
@@ -3418,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();
@@ -3514,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;
@@ -4549,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);
@@ -4673,7 +4705,7 @@
Slog.v(TAG_WM, "Wallpaper layer changed: assigning layers + relayout");
}
computeImeTarget(true /* updateImeTarget */);
- mService.mRoot.mWallpaperMayChange = true;
+ mWallpaperMayChange = true;
// Since the window list has been rebuilt, focus might have to be recomputed since the
// actual order of windows might have changed again.
mService.mFocusMayChange = true;
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/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 61bc4e4..83d32c8ad 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -40,14 +40,11 @@
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
+import android.view.InputApplicationHandle;
import android.view.InputChannel;
import android.view.InputEventReceiver;
-import android.view.KeyEvent;
-import android.view.WindowManager;
-import android.view.InputApplicationHandle;
import android.view.InputWindowHandle;
-import com.android.server.input.InputManagerService;
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
@@ -401,10 +398,10 @@
mTmpRect.setEmpty();
mDisableWallpaperTouchEvents = false;
this.inDrag = inDrag;
- wallpaperController = mService.mRoot.mWallpaperController;
+ final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+ wallpaperController = dc.mWallpaperController;
- mService.mRoot.getDisplayContent(mDisplayId).forAllWindows(this,
- true /* traverseTopToBottom */);
+ dc.forAllWindows(this, true /* traverseTopToBottom */);
if (mAddWallpaperInputConsumerHandle) {
// No visible wallpaper found, add the wallpaper input consumer at the end.
addInputWindowHandle(wallpaperInputConsumer.mWindowHandle);
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 d21f67d9..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 2399716..b483fd3 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -51,7 +51,6 @@
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
-import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
import android.annotation.CallSuper;
import android.annotation.NonNull;
@@ -106,7 +105,6 @@
private boolean mSustainedPerformanceModeEnabled = false;
private boolean mSustainedPerformanceModeCurrent = false;
- boolean mWallpaperMayChange = false;
// During an orientation change, we track whether all windows have rendered
// at the new orientation, and this will be false from changing orientation until that occurs.
// For seamless rotation cases this always stays true, as the windows complete their orientation
@@ -114,8 +112,6 @@
boolean mOrientationChangeComplete = true;
boolean mWallpaperActionPending = false;
- final WallpaperController mWallpaperController;
-
private final Handler mHandler;
private String mCloseSystemDialogsReason;
@@ -124,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 {
@@ -150,7 +143,6 @@
RootWindowContainer(WindowManagerService service) {
super(service);
mHandler = new MyHandler(service.mH.getLooper());
- mWallpaperController = new WallpaperController(mService);
}
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
@@ -236,8 +228,7 @@
return existing;
}
- final DisplayContent dc =
- new DisplayContent(display, mService, mWallpaperController, controller);
+ final DisplayContent dc = new DisplayContent(display, mService, controller);
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
@@ -368,8 +359,6 @@
public void onConfigurationChanged(Configuration newParentConfig) {
prepareFreezingTaskBounds();
super.onConfigurationChanged(newParentConfig);
-
- forAllDisplays(mDisplayContentConfigChangesConsumer);
}
private void prepareFreezingTaskBounds() {
@@ -579,14 +568,19 @@
final RecentsAnimationController recentsAnimationController =
mService.getRecentsAnimationController();
if (recentsAnimationController != null) {
- recentsAnimationController.checkAnimationReady(mWallpaperController);
+ recentsAnimationController.checkAnimationReady(defaultDisplay.mWallpaperController);
}
- if (mWallpaperMayChange) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change! Adjusting");
- defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("WallpaperMayChange",
- defaultDisplay.pendingLayoutChanges);
+ for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+ final DisplayContent displayContent = mChildren.get(displayNdx);
+ if (displayContent.mWallpaperMayChange) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change! Adjusting");
+ displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ if (DEBUG_LAYOUT_REPEATS) {
+ surfacePlacer.debugLayoutRepeats("WallpaperMayChange",
+ displayContent.pendingLayoutChanges);
+ }
+ }
}
if (mService.mFocusMayChange) {
@@ -617,7 +611,6 @@
}
// Destroy the surface of any windows that are no longer visible.
- boolean wallpaperDestroyed = false;
i = mService.mDestroySurface.size();
if (i > 0) {
do {
@@ -629,7 +622,7 @@
displayContent.setInputMethodWindowLocked(null);
}
if (displayContent.mWallpaperController.isWallpaperTarget(win)) {
- wallpaperDestroyed = true;
+ displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
win.destroySurfaceUnchecked();
win.mWinAnimator.destroyPreservedSurfaceLocked();
@@ -643,11 +636,6 @@
displayContent.removeExistingTokensIfPossible();
}
- if (wallpaperDestroyed) {
- defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- defaultDisplay.setLayoutNeeded();
- }
-
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
final DisplayContent displayContent = mChildren.get(displayNdx);
if (displayContent.pendingLayoutChanges != 0) {
@@ -905,10 +893,6 @@
mUpdateRotation = true;
doRequest = true;
}
- if ((bulkUpdateParams & SET_WALLPAPER_MAY_CHANGE) != 0) {
- mWallpaperMayChange = true;
- doRequest = true;
- }
if ((bulkUpdateParams & SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
mOrientationChangeComplete = false;
} else {
@@ -1063,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/Session.java b/services/core/java/com/android/server/wm/Session.java
index b411fad..6838c55 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -29,7 +29,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.content.ClipData;
-import android.content.Context;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
@@ -42,7 +41,6 @@
import android.os.UserHandle;
import android.util.MergedConfiguration;
import android.util.Slog;
-import android.view.Display;
import android.view.DisplayCutout;
import android.view.IWindow;
import android.view.IWindowId;
@@ -60,6 +58,7 @@
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
+import java.util.function.BiConsumer;
/**
* This class represents an active client session. There is generally one
@@ -315,14 +314,19 @@
}
}
+ private void actionOnWallpaper(IBinder window,
+ BiConsumer<WallpaperController, WindowState> action) {
+ final WindowState windowState = mService.windowForClientLocked(this, window, true);
+ action.accept(windowState.getDisplayContent().mWallpaperController, windowState);
+ }
+
@Override
public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) {
synchronized (mService.mGlobalLock) {
long ident = Binder.clearCallingIdentity();
try {
- mService.mRoot.mWallpaperController.setWindowWallpaperPosition(
- mService.windowForClientLocked(this, window, true),
- x, y, xStep, yStep);
+ actionOnWallpaper(window, (wpController, windowState) ->
+ wpController.setWindowWallpaperPosition(windowState, x, y, xStep, yStep));
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -332,7 +336,8 @@
@Override
public void wallpaperOffsetsComplete(IBinder window) {
synchronized (mService.mGlobalLock) {
- mService.mRoot.mWallpaperController.wallpaperOffsetsComplete(window);
+ actionOnWallpaper(window, (wpController, windowState) ->
+ wpController.wallpaperOffsetsComplete(window));
}
}
@@ -341,8 +346,8 @@
synchronized (mService.mGlobalLock) {
long ident = Binder.clearCallingIdentity();
try {
- mService.mRoot.mWallpaperController.setWindowWallpaperDisplayOffset(
- mService.windowForClientLocked(this, window, true), x, y);
+ actionOnWallpaper(window, (wpController, windowState) ->
+ wpController.setWindowWallpaperDisplayOffset(windowState, x, y));
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -355,9 +360,9 @@
synchronized (mService.mGlobalLock) {
long ident = Binder.clearCallingIdentity();
try {
- return mService.mRoot.mWallpaperController.sendWindowWallpaperCommand(
- mService.windowForClientLocked(this, window, true),
- action, x, y, z, extras, sync);
+ final WindowState windowState = mService.windowForClientLocked(this, window, true);
+ return windowState.getDisplayContent().mWallpaperController
+ .sendWindowWallpaperCommand(windowState, action, x, y, z, extras, sync);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -367,7 +372,8 @@
@Override
public void wallpaperCommandComplete(IBinder window, Bundle result) {
synchronized (mService.mGlobalLock) {
- mService.mRoot.mWallpaperController.wallpaperCommandComplete(window);
+ actionOnWallpaper(window, (wpController, windowState) ->
+ wpController.wallpaperCommandComplete(window));
}
}
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/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 29e1b20..15239c7 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -60,6 +60,7 @@
class WallpaperController {
private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperController" : TAG_WM;
private WindowManagerService mService;
+ private final DisplayContent mDisplayContent;
private final ArrayList<WallpaperWindowToken> mWallpaperTokens = new ArrayList<>();
@@ -187,8 +188,9 @@
return false;
};
- public WallpaperController(WindowManagerService service) {
+ WallpaperController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
+ mDisplayContent = displayContent;
}
WindowState getWallpaperTarget() {
@@ -397,11 +399,7 @@
}
private void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) {
- final DisplayContent displayContent = changingTarget.getDisplayContent();
- if (displayContent == null) {
- return;
- }
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
final int dw = displayInfo.logicalWidth;
final int dh = displayInfo.logicalHeight;
@@ -464,15 +462,15 @@
}
}
- private void findWallpaperTarget(DisplayContent dc) {
+ private void findWallpaperTarget() {
mFindResults.reset();
- if (dc.isStackVisible(WINDOWING_MODE_FREEFORM)) {
+ if (mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM)) {
// In freeform mode we set the wallpaper as its own target, so we don't need an
// additional window to make it visible.
mFindResults.setUseTopWallpaperAsTarget(true);
}
- dc.forAllWindows(mFindWallpaperTargetFunction, true /* traverseTopToBottom */);
+ mDisplayContent.forAllWindows(mFindWallpaperTargetFunction, true /* traverseTopToBottom */);
if (mFindResults.wallpaperTarget == null && mFindResults.useTopWallpaperAsTarget) {
mFindResults.setWallpaperTarget(mFindResults.topWallpaper);
@@ -485,8 +483,7 @@
}
/** Updates the target wallpaper if needed and returns true if an update happened. */
- private void updateWallpaperWindowsTarget(DisplayContent dc,
- FindWallpaperTargetResult result) {
+ private void updateWallpaperWindowsTarget(FindWallpaperTargetResult result) {
WindowState wallpaperTarget = result.wallpaperTarget;
@@ -529,7 +526,7 @@
return;
}
- if (dc.getWindow(w -> w == prevWallpaperTarget) == null) {
+ if (mDisplayContent.getWindow(w -> w == prevWallpaperTarget) == null) {
return;
}
@@ -550,9 +547,9 @@
// is not. If they're both hidden, still use the new target.
mWallpaperTarget = prevWallpaperTarget;
} else if (newTargetHidden == oldTargetHidden
- && !dc.mOpeningApps.contains(wallpaperTarget.mAppToken)
- && (dc.mOpeningApps.contains(prevWallpaperTarget.mAppToken)
- || dc.mClosingApps.contains(prevWallpaperTarget.mAppToken))) {
+ && !mDisplayContent.mOpeningApps.contains(wallpaperTarget.mAppToken)
+ && (mDisplayContent.mOpeningApps.contains(prevWallpaperTarget.mAppToken)
+ || mDisplayContent.mClosingApps.contains(prevWallpaperTarget.mAppToken))) {
// If they're both hidden (or both not hidden), prefer the one that's currently in
// opening or closing app list, this allows transition selection logic to better
// determine the wallpaper status of opening/closing apps.
@@ -570,18 +567,21 @@
}
}
- void adjustWallpaperWindows(DisplayContent dc) {
- mService.mRoot.mWallpaperMayChange = false;
+ void adjustWallpaperWindows() {
+ mDisplayContent.mWallpaperMayChange = false;
// First find top-most window that has asked to be on top of the wallpaper;
// all wallpapers go behind it.
- findWallpaperTarget(dc);
- updateWallpaperWindowsTarget(dc, mFindResults);
+ findWallpaperTarget();
+ updateWallpaperWindowsTarget(mFindResults);
// The window is visible to the compositor...but is it visible to the user?
// That is what the wallpaper cares about.
final boolean visible = mWallpaperTarget != null && isWallpaperVisible(mWallpaperTarget);
- if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
+ if (DEBUG_WALLPAPER) {
+ Slog.v(TAG, "Wallpaper visibility: " + visible + " at display "
+ + mDisplayContent.getDisplayId());
+ }
if (visible) {
if (mWallpaperTarget.mWallpaperX >= 0) {
@@ -637,9 +637,11 @@
}
if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
- mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
- mService.mH.sendEmptyMessageDelayed(WALLPAPER_DRAW_PENDING_TIMEOUT,
- WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
+ mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT, this);
+ mService.mH.sendMessageDelayed(
+ mService.mH.obtainMessage(WALLPAPER_DRAW_PENDING_TIMEOUT, this),
+ WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
+
}
if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
"Wallpaper should be visible but has not been drawn yet. " +
@@ -649,7 +651,7 @@
}
if (wallpaperReady) {
mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
- mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT);
+ mService.mH.removeMessages(WALLPAPER_DRAW_PENDING_TIMEOUT, this);
}
return transitionReady;
@@ -659,10 +661,9 @@
* Adjusts the wallpaper windows if the input display has a pending wallpaper layout or one of
* the opening apps should be a wallpaper target.
*/
- void adjustWallpaperWindowsForAppTransitionIfNeeded(DisplayContent dc,
- ArraySet<AppWindowToken> openingApps) {
+ void adjustWallpaperWindowsForAppTransitionIfNeeded(ArraySet<AppWindowToken> openingApps) {
boolean adjust = false;
- if ((dc.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+ if ((mDisplayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
adjust = true;
} else {
for (int i = openingApps.size() - 1; i >= 0; --i) {
@@ -675,7 +676,7 @@
}
if (adjust) {
- adjustWallpaperWindows(dc);
+ adjustWallpaperWindows();
}
}
@@ -740,6 +741,7 @@
}
void dump(PrintWriter pw, String prefix) {
+ pw.print(prefix); pw.print("displayId="); pw.println(mDisplayContent.getDisplayId());
pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
if (mPrevWallpaperTarget != null) {
pw.print(prefix); pw.print("mPrevWallpaperTarget="); pw.println(mPrevWallpaperTarget);
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 46bb981..449c409 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -270,9 +271,6 @@
if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) {
builder.append(" UPDATE_ROTATION");
}
- if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE) != 0) {
- builder.append(" WALLPAPER_MAY_CHANGE");
- }
if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
builder.append(" ORIENTATION_CHANGE_COMPLETE");
}
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 c47b22f..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()) {
@@ -2286,7 +2319,7 @@
}
synchronized (mGlobalLock) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ final DisplayContent dc = getDisplayContentOrCreate(displayId, null /* token */);
if (dc == null) {
Slog.w(TAG_WM, "addWindowToken: Attempted to add token: " + binder
+ " for non-exiting displayId=" + displayId);
@@ -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();
}
}
@@ -3462,7 +3513,9 @@
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "screenshotWallpaper");
synchronized (mGlobalLock) {
- return mRoot.mWallpaperController.screenshotWallpaperLocked();
+ // TODO(b/115486823) Screenshot at secondary displays if needed.
+ final DisplayContent dc = mRoot.getDisplayContent(DEFAULT_DISPLAY);
+ return dc.mWallpaperController.screenshotWallpaperLocked();
}
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -3670,13 +3723,6 @@
}
@Override
- public WindowManagerPolicy.DisplayContentInfo getDefaultDisplayContentInfo() {
- synchronized (mGlobalLock) {
- return getDefaultDisplayContentLocked();
- }
- }
-
- @Override
public int getDefaultDisplayRotation() {
synchronized (mGlobalLock) {
return getDefaultDisplayContentLocked().getRotation();
@@ -4289,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() {
@@ -4694,7 +4759,10 @@
break;
case WALLPAPER_DRAW_PENDING_TIMEOUT: {
synchronized (mGlobalLock) {
- if (mRoot.mWallpaperController.processWallpaperDrawPendingTimeout()) {
+ final WallpaperController wallpaperController =
+ (WallpaperController) msg.obj;
+ if (wallpaperController != null
+ && wallpaperController.processWallpaperDrawPendingTimeout()) {
mWindowPlacerLocked.performSurfacePlacement();
}
}
@@ -5377,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,
@@ -5517,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 "
@@ -5525,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);
+ }
}
}
@@ -5543,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();
}
}
@@ -5771,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);
@@ -5964,18 +6018,11 @@
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);
}
mWindowPlacerLocked.dump(pw, " ");
- mRoot.mWallpaperController.dump(pw, " ");
pw.print(" mSystemBooted="); pw.print(mSystemBooted);
pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
@@ -6003,6 +6050,7 @@
pw.print(" mRecentsAnimationController="); pw.println(mRecentsAnimationController);
mRecentsAnimationController.dump(pw, " ");
}
+ PolicyControl.dump(" ", pw);
}
}
@@ -6266,7 +6314,7 @@
public void onOverlayChanged() {
synchronized (mGlobalLock) {
mRoot.forAllDisplays(displayContent -> {
- mPolicy.onOverlayChangedLw(displayContent);
+ displayContent.getDisplayPolicy().onOverlayChangedLw();
displayContent.updateDisplayInfo();
});
requestTraversal();
@@ -6496,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);
}
}
@@ -7098,13 +7146,6 @@
}
@Override
- public boolean isDockedDividerResizing() {
- synchronized (mGlobalLock) {
- return getDefaultDisplayContentLocked().getDockedDividerController().isResizing();
- }
- }
-
- @Override
public void computeWindowsForAccessibility() {
final AccessibilityController accessibilityController;
synchronized (mGlobalLock) {
@@ -7363,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 838d2a1..e090cc5 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -245,7 +245,7 @@
mSession = win.mSession;
mAttrType = win.mAttrs.type;
mIsWallpaper = win.mIsWallpaper;
- mWallpaperControllerLocked = mService.mRoot.mWallpaperController;
+ mWallpaperControllerLocked = win.getDisplayContent().mWallpaperController;
}
void cancelExitAnimationForNextAnimationLocked() {
@@ -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/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 7d25b8c..7193dd7 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -38,7 +38,6 @@
class WindowSurfacePlacer {
private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowSurfacePlacer" : TAG_WM;
private final WindowManagerService mService;
- private final WallpaperController mWallpaperControllerLocked;
private boolean mInLayout = false;
@@ -46,7 +45,6 @@
private int mLayoutRepeatCount;
static final int SET_UPDATE_ROTATION = 1 << 0;
- static final int SET_WALLPAPER_MAY_CHANGE = 1 << 1;
static final int SET_ORIENTATION_CHANGE_COMPLETE = 1 << 2;
static final int SET_WALLPAPER_ACTION_PENDING = 1 << 3;
@@ -59,7 +57,6 @@
public WindowSurfacePlacer(WindowManagerService service) {
mService = service;
- mWallpaperControllerLocked = mService.mRoot.mWallpaperController;
mPerformSurfacePlacement = () -> {
synchronized (mService.mGlobalLock) {
performSurfacePlacement();
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 04a526f..bf83ac13 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -83,6 +83,7 @@
"libui",
"libinput",
"libinputflinger",
+ "libinputflinger_base",
"libinputservice",
"libschedulerservicehidl",
"libsensorservice",
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index e2db807..ee8a08b 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -341,8 +341,7 @@
}
mInteractive = true;
- sp<EventHub> eventHub = new EventHub();
- mInputManager = new InputManager(eventHub, this, this);
+ mInputManager = new InputManager(this, this);
}
NativeInputManager::~NativeInputManager() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 58c4bbf..d798865 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -494,7 +494,8 @@
pkg.usesLibraryFiles = new String[] { "foo13"};
pkg.usesLibraryInfos = new ArrayList<>();
- pkg.usesLibraryInfos.add(new SharedLibraryInfo(null, null, null, 0L, 0, null, null, null));
+ pkg.usesLibraryInfos.add(
+ new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null));
pkg.mOriginalPackages = new ArrayList<>();
pkg.mOriginalPackages.add("foo14");
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index cd15a57..813fa82 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.fail;
import android.content.pm.ApplicationInfo;
+import android.content.pm.SharedLibraryInfo;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
@@ -39,6 +40,7 @@
import java.io.File;
import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -108,22 +110,31 @@
return data;
}
+ private List<SharedLibraryInfo> createMockSharedLibrary(String [] sharedLibrary) {
+ SharedLibraryInfo info = new SharedLibraryInfo(null, null, Arrays.asList(sharedLibrary),
+ null, 0L, SharedLibraryInfo.TYPE_STATIC, null, null, null);
+ ArrayList<SharedLibraryInfo> libraries = new ArrayList<>();
+ libraries.add(info);
+ return libraries;
+ }
+
@Test
public void testSplitChain() {
TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
- String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+ List<SharedLibraryInfo> sharedLibrary =
+ createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
data.info, sharedLibrary, data.pathsWithCode);
assertEquals(9, contexts.length);
- assertEquals("PCL[a.dex:b.dex]", contexts[0]);
- assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]",
+ assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
+ assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}",
contexts[1]);
- assertEquals("DLC[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[2]);
- assertEquals("PCL[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[3]);
- assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[4]);
- assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[5]);
- assertEquals("PCL[];PCL[base-5.dex];PCL[a.dex:b.dex:base.dex]", contexts[6]);
+ assertEquals("DLC[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[2]);
+ assertEquals("PCL[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[3]);
+ assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[4]);
+ assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[5]);
+ assertEquals("PCL[];PCL[base-5.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[6]);
assertEquals(null, contexts[7]); // config split
assertEquals("PCL[]", contexts[8]); // feature split with no dependency
}
@@ -131,25 +142,28 @@
@Test
public void testSplitChainNoSplitDependencies() {
TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false);
- String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+ List<SharedLibraryInfo> sharedLibrary =
+ createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
data.info, sharedLibrary, data.pathsWithCode);
assertEquals(9, contexts.length);
- assertEquals("PCL[a.dex:b.dex]", contexts[0]);
- assertEquals("PCL[a.dex:b.dex:base.dex]", contexts[1]);
- assertEquals("PCL[a.dex:b.dex:base.dex:base-1.dex]", contexts[2]);
- assertEquals("PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex]", contexts[3]);
- assertEquals("PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex]", contexts[4]);
+ assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
+ assertEquals("PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[1]);
+ assertEquals("PCL[base.dex:base-1.dex]{PCL[a.dex:b.dex]}", contexts[2]);
+ assertEquals("PCL[base.dex:base-1.dex:base-2.dex]{PCL[a.dex:b.dex]}", contexts[3]);
assertEquals(
- "PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex]",
+ "PCL[base.dex:base-1.dex:base-2.dex:base-3.dex]{PCL[a.dex:b.dex]}",
+ contexts[4]);
+ assertEquals(
+ "PCL[base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex]{PCL[a.dex:b.dex]}",
contexts[5]);
assertEquals(
- "PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex]",
+ "PCL[base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex]{PCL[a.dex:b.dex]}",
contexts[6]);
assertEquals(null, contexts[7]); // config split
assertEquals(
- "PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex:base-6.dex:config-split-7.dex]",
+ "PCL[base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex:base-6.dex:config-split-7.dex]{PCL[a.dex:b.dex]}",
contexts[8]); // feature split with no dependency
}
@@ -200,18 +214,21 @@
public void testSplitChainWithNullPrimaryClassLoader() {
// A null classLoaderName should mean PathClassLoader.
TestData data = createMockApplicationInfo(null, true, true);
- String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+ List<SharedLibraryInfo> sharedLibrary =
+ createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
data.info, sharedLibrary, data.pathsWithCode);
assertEquals(9, contexts.length);
- assertEquals("PCL[a.dex:b.dex]", contexts[0]);
- assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[1]);
- assertEquals("DLC[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[2]);
- assertEquals("PCL[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[3]);
- assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[4]);
- assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[5]);
- assertEquals("PCL[];PCL[base-5.dex];PCL[a.dex:b.dex:base.dex]", contexts[6]);
+ assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
+ assertEquals(
+ "DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}",
+ contexts[1]);
+ assertEquals("DLC[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[2]);
+ assertEquals("PCL[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[3]);
+ assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[4]);
+ assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[5]);
+ assertEquals("PCL[];PCL[base-5.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[6]);
assertEquals(null, contexts[7]); // config split
assertEquals("PCL[]", contexts[8]); // feature split with no dependency
}
@@ -219,35 +236,38 @@
@Test
public void tesNoSplits() {
TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
- String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+ List<SharedLibraryInfo> sharedLibrary =
+ createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
data.info, sharedLibrary, data.pathsWithCode);
assertEquals(1, contexts.length);
- assertEquals("PCL[a.dex:b.dex]", contexts[0]);
+ assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
}
@Test
public void tesNoSplitsNullClassLoaderName() {
TestData data = createMockApplicationInfo(null, false, false);
- String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+ List<SharedLibraryInfo> sharedLibrary =
+ createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
data.info, sharedLibrary, data.pathsWithCode);
assertEquals(1, contexts.length);
- assertEquals("PCL[a.dex:b.dex]", contexts[0]);
+ assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
}
@Test
public void tesNoSplitDelegateLast() {
TestData data = createMockApplicationInfo(
DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
- String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+ List<SharedLibraryInfo> sharedLibrary =
+ createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
data.info, sharedLibrary, data.pathsWithCode);
assertEquals(1, contexts.length);
- assertEquals("DLC[a.dex:b.dex]", contexts[0]);
+ assertEquals("DLC[]{PCL[a.dex:b.dex]}", contexts[0]);
}
@Test
@@ -276,7 +296,8 @@
TestData data = createMockApplicationInfo(null, true, false);
Arrays.fill(data.pathsWithCode, false);
- String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+ List<SharedLibraryInfo> sharedLibrary =
+ createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
data.info, sharedLibrary, data.pathsWithCode);
@@ -295,18 +316,21 @@
public void testContextBaseNoCode() {
TestData data = createMockApplicationInfo(null, true, true);
data.pathsWithCode[0] = false;
- String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+ List<SharedLibraryInfo> sharedLibrary =
+ createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
String[] contexts = DexoptUtils.getClassLoaderContexts(
data.info, sharedLibrary, data.pathsWithCode);
assertEquals(9, contexts.length);
assertEquals(null, contexts[0]);
- assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[1]);
- assertEquals("DLC[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[2]);
- assertEquals("PCL[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[3]);
- assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[4]);
- assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[5]);
- assertEquals("PCL[];PCL[base-5.dex];PCL[a.dex:b.dex:base.dex]", contexts[6]);
+ assertEquals(
+ "DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}",
+ contexts[1]);
+ assertEquals("DLC[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[2]);
+ assertEquals("PCL[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[3]);
+ assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[4]);
+ assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[5]);
+ assertEquals("PCL[];PCL[base-5.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[6]);
assertEquals(null, contexts[7]);
}
diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
new file mode 100644
index 0000000..7cf7df13
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
@@ -0,0 +1,299 @@
+/*
+ * 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.power;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.IThermalEventListener;
+import android.os.IThermalStatusListener;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.Temperature;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.SystemService;
+import com.android.server.power.ThermalManagerService.ThermalHalWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server
+ * /power/ThermalManagerServiceTest.java
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ThermalManagerServiceTest {
+ private static final long CALLBACK_TIMEOUT_MILLI_SEC = 5000;
+ private ThermalManagerService mService;
+ private ThermalHalFake mFakeHal;
+ private PowerManager mPowerManager;
+ @Mock
+ private Context mContext;
+ @Mock
+ private IPowerManager mIPowerManagerMock;
+ @Mock
+ private IThermalEventListener mEventListener1;
+ @Mock
+ private IThermalEventListener mEventListener2;
+ @Mock
+ private IThermalStatusListener mStatusListener1;
+ @Mock
+ private IThermalStatusListener mStatusListener2;
+
+ /**
+ * Fake Hal class.
+ */
+ private class ThermalHalFake extends ThermalHalWrapper {
+ private static final int INIT_STATUS = Temperature.THROTTLING_NONE;
+ private ArrayList<Temperature> mTemperatureList = new ArrayList<>();
+ private Temperature mSkin1 = new Temperature(0, Temperature.TYPE_SKIN, "skin1",
+ INIT_STATUS);
+ private Temperature mSkin2 = new Temperature(0, Temperature.TYPE_SKIN, "skin2",
+ INIT_STATUS);
+ private Temperature mBattery = new Temperature(0, Temperature.TYPE_BATTERY, "batt",
+ INIT_STATUS);
+ private Temperature mUsbPort = new Temperature(0, Temperature.TYPE_USB_PORT, "usbport",
+ INIT_STATUS);
+
+ ThermalHalFake() {
+ mTemperatureList.add(mSkin1);
+ mTemperatureList.add(mSkin2);
+ mTemperatureList.add(mBattery);
+ mTemperatureList.add(mUsbPort);
+ }
+
+ @Override
+ protected List<Temperature> getCurrentTemperatures(boolean shouldFilter, int type) {
+ return mTemperatureList;
+ }
+
+ @Override
+ protected boolean connectToHal() {
+ return true;
+ }
+
+ @Override
+ protected void dump(PrintWriter pw, String prefix) {
+ return;
+ }
+ }
+
+ private void assertTemperatureEquals(List<Temperature> expected, List<Temperature> value) {
+ assertEquals(new HashSet<>(expected), new HashSet<>(value));
+ }
+
+ @Before
+ public void setUp() throws RemoteException {
+ MockitoAnnotations.initMocks(this);
+ mFakeHal = new ThermalHalFake();
+ mPowerManager = new PowerManager(mContext, mIPowerManagerMock, null);
+ when(mContext.getSystemServiceName(PowerManager.class)).thenReturn(Context.POWER_SERVICE);
+ when(mContext.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
+ resetListenerMock();
+ mService = new ThermalManagerService(mContext, mFakeHal);
+ // Register callbacks before AMS ready and no callback sent
+ assertTrue(mService.mService.registerThermalEventListener(mEventListener1));
+ assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1));
+ assertTrue(mService.mService.registerThermalEventListenerWithType(mEventListener2,
+ Temperature.TYPE_SKIN));
+ assertTrue(mService.mService.registerThermalStatusListener(mStatusListener2));
+ verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(0)).notifyThrottling(any(Temperature.class));
+ verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(0)).onStatusChange(anyInt());
+ verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(0)).notifyThrottling(any(Temperature.class));
+ verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(0)).onStatusChange(anyInt());
+ mService.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
+ ArgumentCaptor<Temperature> captor = ArgumentCaptor.forClass(Temperature.class);
+ verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(4)).notifyThrottling(captor.capture());
+ assertTemperatureEquals(mFakeHal.mTemperatureList, captor.getAllValues());
+ verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
+ captor = ArgumentCaptor.forClass(Temperature.class);
+ verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(2)).notifyThrottling(captor.capture());
+ assertTemperatureEquals(new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
+ captor.getAllValues());
+ verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
+ }
+
+ private void resetListenerMock() {
+ reset(mEventListener1);
+ reset(mStatusListener1);
+ reset(mEventListener2);
+ reset(mStatusListener2);
+ doReturn(mock(IBinder.class)).when(mEventListener1).asBinder();
+ doReturn(mock(IBinder.class)).when(mStatusListener1).asBinder();
+ doReturn(mock(IBinder.class)).when(mEventListener2).asBinder();
+ doReturn(mock(IBinder.class)).when(mStatusListener2).asBinder();
+ }
+
+ @Test
+ public void testRegister() throws RemoteException {
+ // Unregister all
+ assertTrue(mService.mService.unregisterThermalEventListener(mEventListener1));
+ assertTrue(mService.mService.unregisterThermalStatusListener(mStatusListener1));
+ assertTrue(mService.mService.unregisterThermalEventListener(mEventListener2));
+ assertTrue(mService.mService.unregisterThermalStatusListener(mStatusListener2));
+ resetListenerMock();
+ // Register callbacks and verify they are called
+ assertTrue(mService.mService.registerThermalEventListener(mEventListener1));
+ assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1));
+ ArgumentCaptor<Temperature> captor = ArgumentCaptor.forClass(Temperature.class);
+ verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(4)).notifyThrottling(captor.capture());
+ assertTemperatureEquals(mFakeHal.mTemperatureList, captor.getAllValues());
+ verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
+ // Register new callbacks and verify old ones are not called (remained same) while new
+ // ones are called
+ assertTrue(mService.mService.registerThermalEventListenerWithType(mEventListener2,
+ Temperature.TYPE_SKIN));
+ assertTrue(mService.mService.registerThermalStatusListener(mStatusListener2));
+ verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(4)).notifyThrottling(any(Temperature.class));
+ verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
+ captor = ArgumentCaptor.forClass(Temperature.class);
+ verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(2)).notifyThrottling(captor.capture());
+ assertTemperatureEquals(new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
+ captor.getAllValues());
+ verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).onStatusChange(Temperature.THROTTLING_NONE);
+ }
+
+ @Test
+ public void testNotify() throws RemoteException {
+ int status = Temperature.THROTTLING_SEVERE;
+ Temperature newBattery = new Temperature(50, Temperature.TYPE_BATTERY, "batt", status);
+ mFakeHal.mCallback.onValues(newBattery);
+ verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).notifyThrottling(newBattery);
+ verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).onStatusChange(status);
+ verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(0)).notifyThrottling(newBattery);
+ verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).onStatusChange(status);
+ resetListenerMock();
+ // Should only notify event not status
+ Temperature newSkin = new Temperature(50, Temperature.TYPE_SKIN, "skin1", status);
+ mFakeHal.mCallback.onValues(newSkin);
+ verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).notifyThrottling(newSkin);
+ verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(0)).onStatusChange(anyInt());
+ verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).notifyThrottling(newSkin);
+ verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(0)).onStatusChange(anyInt());
+ resetListenerMock();
+ // Back to None, should only notify event not status
+ status = Temperature.THROTTLING_NONE;
+ newBattery = new Temperature(50, Temperature.TYPE_BATTERY, "batt", status);
+ mFakeHal.mCallback.onValues(newBattery);
+ verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).notifyThrottling(newBattery);
+ verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(0)).onStatusChange(anyInt());
+ verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(0)).notifyThrottling(newBattery);
+ verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(0)).onStatusChange(anyInt());
+ resetListenerMock();
+ // Should also notify status
+ newSkin = new Temperature(50, Temperature.TYPE_SKIN, "skin1", status);
+ mFakeHal.mCallback.onValues(newSkin);
+ verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).notifyThrottling(newSkin);
+ verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).onStatusChange(status);
+ verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).notifyThrottling(newSkin);
+ verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).onStatusChange(status);
+ }
+
+ @Test
+ public void testGetCurrentTemperatures() throws RemoteException {
+ assertTemperatureEquals(mFakeHal.getCurrentTemperatures(false, 0),
+ mService.mService.getCurrentTemperatures());
+ assertTemperatureEquals(mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN),
+ mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN));
+ }
+
+ @Test
+ public void testGetCurrentStatus() throws RemoteException {
+ int status = Temperature.THROTTLING_WARNING;
+ Temperature newSkin = new Temperature(100, Temperature.TYPE_SKIN, "skin1", status);
+ mFakeHal.mCallback.onValues(newSkin);
+ assertEquals(status, mService.mService.getCurrentStatus());
+ }
+
+ @Test
+ public void testThermalShutdown() throws RemoteException {
+ int status = Temperature.THROTTLING_SHUTDOWN;
+ Temperature newSkin = new Temperature(100, Temperature.TYPE_SKIN, "skin1", status);
+ mFakeHal.mCallback.onValues(newSkin);
+ verify(mIPowerManagerMock, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
+ }
+
+ @Test
+ public void testNoHal() throws RemoteException {
+ mService = new ThermalManagerService(mContext);
+ // Do no call onActivityManagerReady to skip connect HAL
+ assertTrue(mService.mService.registerThermalEventListener(mEventListener1));
+ assertTrue(mService.mService.registerThermalStatusListener(mStatusListener1));
+ assertTrue(mService.mService.unregisterThermalEventListener(mEventListener1));
+ assertTrue(mService.mService.unregisterThermalStatusListener(mStatusListener1));
+ assertEquals(0, mService.mService.getCurrentTemperatures().size());
+ assertEquals(0,
+ mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN).size());
+ assertEquals(Temperature.THROTTLING_NONE, mService.mService.getCurrentStatus());
+ }
+}
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/WallpaperControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java
index 25e73e3..4ea6b39 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -48,7 +48,7 @@
synchronized (mWm.mGlobalLock) {
// No wallpaper
final DisplayContent dc = createNewDisplay();
- Bitmap wallpaperBitmap = mWm.mRoot.mWallpaperController.screenshotWallpaperLocked();
+ Bitmap wallpaperBitmap = dc.mWallpaperController.screenshotWallpaperLocked();
assertNull(wallpaperBitmap);
// No wallpaper WSA Surface
@@ -56,25 +56,25 @@
true, dc, true /* ownerCanManageAppTokens */);
WindowState wallpaperWindow = createWindow(null /* parent */, TYPE_WALLPAPER,
wallpaperWindowToken, "wallpaperWindow");
- wallpaperBitmap = mWallpaperController.screenshotWallpaperLocked();
+ wallpaperBitmap = dc.mWallpaperController.screenshotWallpaperLocked();
assertNull(wallpaperBitmap);
// Wallpaper with not visible WSA surface.
wallpaperWindow.mWinAnimator.mSurfaceController = windowSurfaceController;
wallpaperWindow.mWinAnimator.mLastAlpha = 1;
- wallpaperBitmap = mWallpaperController.screenshotWallpaperLocked();
+ wallpaperBitmap = dc.mWallpaperController.screenshotWallpaperLocked();
assertNull(wallpaperBitmap);
when(windowSurfaceController.getShown()).thenReturn(true);
// Wallpaper with WSA alpha set to 0.
wallpaperWindow.mWinAnimator.mLastAlpha = 0;
- wallpaperBitmap = mWallpaperController.screenshotWallpaperLocked();
+ wallpaperBitmap = dc.mWallpaperController.screenshotWallpaperLocked();
assertNull(wallpaperBitmap);
// Wallpaper window with WSA Surface
wallpaperWindow.mWinAnimator.mLastAlpha = 1;
- wallpaperBitmap = mWallpaperController.screenshotWallpaperLocked();
+ wallpaperBitmap = dc.mWallpaperController.screenshotWallpaperLocked();
assertNotNull(wallpaperBitmap);
}
}
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 80bb936..60c0459 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -27,21 +27,16 @@
import static org.mockito.Mockito.anyFloat;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
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;
@@ -54,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,
- WallpaperController wallpaperController, DisplayWindowController controller) {
- super(display, service, wallpaperController, 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/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 53858c7..1eb46fb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -90,7 +90,6 @@
WindowState mChildAppWindowAbove;
WindowState mChildAppWindowBelow;
HashSet<WindowState> mCommonWindows;
- WallpaperController mWallpaperController;
@Rule
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
@@ -119,8 +118,6 @@
mWm = mWmRule.getWindowManagerService();
beforeCreateDisplay();
- mWallpaperController = new WallpaperController(mWm);
-
context.getDisplay().getDisplayInfo(mDisplayInfo);
mDisplayContent = createNewDisplay();
mWm.mDisplayEnabled = true;
@@ -363,8 +360,7 @@
final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
synchronized (mWm.mGlobalLock) {
- return new DisplayContent(display, mWm, mWallpaperController,
- mock(DisplayWindowController.class));
+ return new DisplayContent(display, mWm, mock(DisplayWindowController.class));
}
}
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/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 72d7c90..630a8bf 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -47,12 +47,10 @@
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.OutputStream;
+import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
@@ -79,15 +77,10 @@
final TaskRecord expected = createTaskRecord(64);
expected.mLastNonFullscreenBounds = new Rect(50, 50, 100, 100);
- final File serializedFile = serializeToFile(expected);
-
- try {
- final TaskRecord actual = restoreFromFile(serializedFile);
- assertEquals(expected.taskId, actual.taskId);
- assertEquals(expected.mLastNonFullscreenBounds, actual.mLastNonFullscreenBounds);
- } finally {
- serializedFile.delete();
- }
+ final byte[] serializedBytes = serializeToBytes(expected);
+ final TaskRecord actual = restoreFromBytes(serializedBytes);
+ assertEquals(expected.taskId, actual.taskId);
+ assertEquals(expected.mLastNonFullscreenBounds, actual.mLastNonFullscreenBounds);
}
@Test
@@ -131,10 +124,8 @@
assertTrue(task.returnsToHomeStack());
}
- private File serializeToFile(TaskRecord r) throws IOException, XmlPullParserException {
- final File tmpFile = File.createTempFile(r.taskId + "_task_", "xml");
-
- try (OutputStream os = new FileOutputStream(tmpFile)) {
+ private byte[] serializeToBytes(TaskRecord r) throws IOException, XmlPullParserException {
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
final XmlSerializer serializer = Xml.newSerializer();
serializer.setOutput(os, "UTF-8");
serializer.startDocument(null, true);
@@ -142,13 +133,14 @@
r.saveToXml(serializer);
serializer.endTag(null, TASK_TAG);
serializer.endDocument();
- }
- return tmpFile;
+ os.flush();
+ return os.toByteArray();
+ }
}
- private TaskRecord restoreFromFile(File file) throws IOException, XmlPullParserException {
- try (Reader reader = new BufferedReader(new FileReader(file))) {
+ private TaskRecord restoreFromBytes(byte[] in) throws IOException, XmlPullParserException {
+ try (Reader reader = new InputStreamReader(new ByteArrayInputStream(in))) {
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(reader);
assertEquals(XmlPullParser.START_TAG, parser.next());
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index cf34fe7..e56edab 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -42,8 +42,8 @@
public static class TestDisplayContent extends DisplayContent {
private TestDisplayContent(Display display, WindowManagerService service,
- WallpaperController wallpaperController, DisplayWindowController controller) {
- super(display, service, wallpaperController, controller);
+ DisplayWindowController controller) {
+ super(display, service, controller);
}
/**
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index bcc0e6b..5ad7c30 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1023,9 +1023,9 @@
public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool";
/**
- * Default Enhanced 4G LTE mode enabled. When this is {@code true}, Enhanced 4G LTE mode by
- * default is on, otherwise if {@code false}, Enhanced 4G LTE mode by default is off.
- * @hide
+ * Sets the default state for the "Enhanced 4G LTE" or "Advanced Calling" mode toggle set by the
+ * user. When this is {@code true}, this mode by default is on, otherwise if {@code false},
+ * this mode by default is off.
*/
public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL =
"enhanced_4g_lte_on_by_default_bool";
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 8324f00..79ed93e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -7696,7 +7696,7 @@
try {
return getITelephony().isAvailable(getSubId(),
MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
- ImsRegistrationImplBase.REGISTRATION_TECH_LTE, getOpPackageName());
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
} catch (RemoteException | NullPointerException ex) {
return false;
}
@@ -8557,6 +8557,26 @@
return UNKNOWN_CARRIER_ID;
}
+ /**
+ * Returns carrier id based on MCCMNC only. This is for fallback when exact carrier id
+ * {@link #getSimCarrierId()} configurations are not found
+ *
+ * @return matching carrier id from passing mccmnc.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public int getCarrierIdFromMccMnc(String mccmnc) {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ return service.getCarrierIdFromMccMnc(getSlotIndex(), mccmnc);
+ }
+ } catch (RemoteException ex) {
+ // This could happen if binder process crashes.
+ }
+ return UNKNOWN_CARRIER_ID;
+ }
+
/**
* Return the application ID for the uicc application type like {@link #APPTYPE_CSIM}.
* All uicc applications are uniquely identified by application ID. See ETSI 102.221 and 101.220
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index e06c372..122626f 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -28,17 +28,22 @@
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.telephony.AccessNetworkConstants;
import android.telephony.SubscriptionManager;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.ITelephony;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.Executor;
/**
@@ -52,6 +57,7 @@
* @see #createForSubscriptionId(Context, int)
* @hide
*/
+@SystemApi
public class ImsMmTelManager {
private static final String TAG = "ImsMmTelManager";
@@ -70,16 +76,12 @@
/**
* Register for IMS over IWLAN if WiFi signal quality is high enough. Do not hand over to LTE
* registration if signal quality degrades.
- * @hide
*/
- @SystemApi
public static final int WIFI_MODE_WIFI_ONLY = 0;
/**
* Prefer registering for IMS over LTE if LTE signal quality is high enough.
- * @hide
*/
- @SystemApi
public static final int WIFI_MODE_CELLULAR_PREFERRED = 1;
/**
@@ -91,13 +93,26 @@
/**
* Callback class for receiving Registration callback events.
- * @see #addImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
- * @see #removeImsRegistrationCallback(RegistrationCallback)
+ * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
+ * @see #unregisterImsRegistrationCallback(RegistrationCallback)
*/
public static class RegistrationCallback {
private static class RegistrationBinder extends IImsRegistrationCallback.Stub {
+ // Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN
+ // and WWAN are more accurate constants.
+ private static final Map<Integer, Integer> IMS_REG_TO_ACCESS_TYPE_MAP =
+ new HashMap<Integer, Integer>() {{
+ // Map NONE to -1 to make sure that we handle the REGISTRATION_TECH_NONE
+ // case, since it is defined.
+ put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, -1);
+ put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
+ AccessNetworkConstants.TransportType.WWAN);
+ put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
+ AccessNetworkConstants.TransportType.WLAN);
+ }};
+
private final RegistrationCallback mLocalCallback;
private Executor mExecutor;
@@ -109,16 +124,16 @@
public void onRegistered(int imsRadioTech) {
if (mLocalCallback == null) return;
- Binder.withCleanCallingIdentity(() ->
- mExecutor.execute(() -> mLocalCallback.onRegistered(imsRadioTech)));
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
+ mLocalCallback.onRegistered(getAccessType(imsRadioTech))));
}
@Override
public void onRegistering(int imsRadioTech) {
if (mLocalCallback == null) return;
- Binder.withCleanCallingIdentity(() ->
- mExecutor.execute(() -> mLocalCallback.onRegistering(imsRadioTech)));
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(() ->
+ mLocalCallback.onRegistering(getAccessType(imsRadioTech))));
}
@Override
@@ -134,8 +149,8 @@
if (mLocalCallback == null) return;
Binder.withCleanCallingIdentity(() ->
- mExecutor.execute(() ->
- mLocalCallback.onTechnologyChangeFailed(imsRadioTech, info)));
+ mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed(
+ getAccessType(imsRadioTech), info)));
}
@Override
@@ -150,6 +165,15 @@
private void setExecutor(Executor executor) {
mExecutor = executor;
}
+
+ private static int getAccessType(int regType) {
+ if (!IMS_REG_TO_ACCESS_TYPE_MAP.containsKey(regType)) {
+ Log.w("ImsMmTelManager", "RegistrationBinder - invalid regType returned: "
+ + regType);
+ return -1;
+ }
+ return IMS_REG_TO_ACCESS_TYPE_MAP.get(regType);
+ }
}
private final RegistrationBinder mBinder = new RegistrationBinder(this);
@@ -157,19 +181,19 @@
/**
* Notifies the framework when the IMS Provider is registered to the IMS network.
*
- * @param imsRadioTech the radio access technology. Valid values are defined in
- * {@link ImsRegistrationImplBase.ImsRegistrationTech}.
+ * @param imsTransportType the radio access technology. Valid values are defined in
+ * {@link android.telephony.AccessNetworkConstants.TransportType}.
*/
- public void onRegistered(@ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) {
+ public void onRegistered(int imsTransportType) {
}
/**
* Notifies the framework when the IMS Provider is trying to register the IMS network.
*
- * @param imsRadioTech the radio access technology. Valid values are defined in
- * {@link ImsRegistrationImplBase.ImsRegistrationTech}.
+ * @param imsTransportType the radio access technology. Valid values are defined in
+ * {@link android.telephony.AccessNetworkConstants.TransportType}.
*/
- public void onRegistering(@ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech) {
+ public void onRegistering(int imsTransportType) {
}
/**
@@ -182,14 +206,14 @@
/**
* A failure has occurred when trying to handover registration to another technology type,
- * defined in {@link ImsRegistrationImplBase.ImsRegistrationTech}
+ * defined in {@link android.telephony.AccessNetworkConstants.TransportType}
*
- * @param imsRadioTech The {@link ImsRegistrationImplBase.ImsRegistrationTech} type that has
- * failed
+ * @param imsTransportType The
+ * {@link android.telephony.AccessNetworkConstants.TransportType}
+ * transport type that has failed to handover registration to.
* @param info A {@link ImsReasonInfo} that identifies the reason for failure.
*/
- public void onTechnologyChangeFailed(
- @ImsRegistrationImplBase.ImsRegistrationTech int imsRadioTech, ImsReasonInfo info) {
+ public void onTechnologyChangeFailed(int imsTransportType, ImsReasonInfo info) {
}
/**
@@ -219,8 +243,8 @@
/**
* Receives IMS capability status updates from the ImsService.
*
- * @see #addMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
- * @see #removeMmTelCapabilityCallback(CapabilityCallback)
+ * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
+ * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
*/
public static class CapabilityCallback {
@@ -285,13 +309,12 @@
}
}
- private Context mContext;
private int mSubId;
/**
* Create an instance of ImsManager for the subscription id specified.
*
- * @param context
+ * @param context The context to create this ImsMmTelManager instance within.
* @param subId The ID of the subscription that this ImsMmTelManager will use.
* @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList()
* @throws IllegalArgumentException if the subscription is invalid or
@@ -303,11 +326,15 @@
throw new IllegalArgumentException("Invalid subscription ID");
}
- return new ImsMmTelManager(context, subId);
+ return new ImsMmTelManager(subId);
}
- private ImsMmTelManager(Context context, int subId) {
- mContext = context;
+ /**
+ * Only visible for testing, use {@link #createForSubscriptionId(Context, int)} instead.
+ * @hide
+ */
+ @VisibleForTesting
+ public ImsMmTelManager(int subId) {
mSubId = subId;
}
@@ -315,14 +342,18 @@
* Registers a {@link RegistrationCallback} with the system, which will provide registration
* updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}. Use
* {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
- * events and call {@link #removeImsRegistrationCallback(RegistrationCallback)} to clean up
+ * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up
* after a subscription is removed.
+ *
+ * When the callback is registered, it will initiate the callback c to be called with the
+ * current registration state.
+ *
* @param executor The executor the callback events should be run on.
* @param c The {@link RegistrationCallback} to be added.
- * @see #removeImsRegistrationCallback(RegistrationCallback)
+ * @see #unregisterImsRegistrationCallback(RegistrationCallback)
*/
- @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
- public void addImsRegistrationCallback(@CallbackExecutor Executor executor,
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void registerImsRegistrationCallback(@CallbackExecutor Executor executor,
@NonNull RegistrationCallback c) {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
@@ -332,8 +363,7 @@
}
c.setExecutor(executor);
try {
- getITelephony().addImsRegistrationCallback(mSubId, c.getBinder(),
- mContext.getOpPackageName());
+ getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -344,16 +374,15 @@
* up to avoid memory leaks or when the subscription is removed.
* @param c The {@link RegistrationCallback} to be removed.
* @see SubscriptionManager.OnSubscriptionsChangedListener
- * @see #addImsRegistrationCallback(Executor, RegistrationCallback)
+ * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
*/
- @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
- public void removeImsRegistrationCallback(@NonNull RegistrationCallback c) {
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
try {
- getITelephony().removeImsRegistrationCallback(mSubId, c.getBinder(),
- mContext.getOpPackageName());
+ getITelephony().unregisterImsRegistrationCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -364,14 +393,18 @@
* updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}.
* Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
* subscription changed events and call
- * {@link #removeImsRegistrationCallback(RegistrationCallback)} to clean up after a subscription
- * is removed.
+ * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up after a
+ * subscription is removed.
+ *
+ * When the callback is registered, it will initiate the callback c to be called with the
+ * current capabilities.
+ *
* @param executor The executor the callback events should be run on.
* @param c The MmTel {@link CapabilityCallback} to be registered.
- * @see #removeMmTelCapabilityCallback(CapabilityCallback)
+ * @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
*/
- @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
- public void addMmTelCapabilityCallback(@CallbackExecutor Executor executor,
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void registerMmTelCapabilityCallback(@CallbackExecutor Executor executor,
@NonNull CapabilityCallback c) {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
@@ -381,8 +414,7 @@
}
c.setExecutor(executor);
try {
- getITelephony().addMmTelCapabilityCallback(mSubId, c.getBinder(),
- mContext.getOpPackageName());
+ getITelephony().registerMmTelCapabilityCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -392,29 +424,42 @@
* Removes an existing MmTel {@link CapabilityCallback}. Be sure to call this when cleaning
* up to avoid memory leaks.
* @param c The MmTel {@link CapabilityCallback} to be removed.
- * @see #addMmTelCapabilityCallback(Executor, CapabilityCallback)
+ * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
*/
- @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
- public void removeMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
try {
- getITelephony().removeMmTelCapabilityCallback(mSubId, c.getBinder(),
- mContext.getOpPackageName());
+ getITelephony().unregisterMmTelCapabilityCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
- * Query the user's setting for whether or not to use MmTel capabilities over IMS,
- * such as voice and video, depending on carrier configuration for the current subscription.
+ * Query the user’s setting for “Advanced Calling” or "Enhanced 4G LTE", which is used to
+ * enable MmTel IMS features, depending on the carrier configuration for the current
+ * subscription. If this setting is enabled, IMS voice and video telephony over IWLAN/LTE will
+ * be enabled as long as the carrier has provisioned these services for the specified
+ * subscription. Other IMS services (SMS/UT) are not affected by this user setting and depend on
+ * carrier requirements.
+ *
+ * Modifying this value may also trigger an IMS registration or deregistration, depending on
+ * whether or not the new value is enabled or disabled.
+ *
+ * Note: If the carrier configuration for advanced calling is not editable or hidden, this
+ * method will do nothing and will instead always use the default value.
+ *
+ * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
+ * @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
+ * @see android.telephony.CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL
+ * @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
+ * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
* @see #setAdvancedCallingSetting(boolean)
- * @return true if the user’s setting for advanced calling is enabled and false otherwise.
- * @hide
+ * @return true if the user's setting for advanced calling is enabled, false otherwise.
*/
- @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isAdvancedCallingSettingEnabled() {
try {
@@ -426,13 +471,25 @@
/**
* Modify the user’s setting for “Advanced Calling” or "Enhanced 4G LTE", which is used to
- * enable MmTel IMS features, such as voice and video calling, depending on the carrier
- * configuration for the current subscription. Modifying this value may also trigger an IMS
- * registration or deregistration, depending on the new value.
- * @see #isAdvancedCallingEnabled()
- * @hide
+ * enable MmTel IMS features, depending on the carrier configuration for the current
+ * subscription. If this setting is enabled, IMS voice and video telephony over IWLAN/LTE will
+ * be enabled as long as the carrier has provisioned these services for the specified
+ * subscription. Other IMS services (SMS/UT) are not affected by this user setting and depend on
+ * carrier requirements.
+ *
+ * Modifying this value may also trigger an IMS registration or deregistration, depending on
+ * whether or not the new value is enabled or disabled.
+ *
+ * Note: If the carrier configuration for advanced calling is not editable or hidden, this
+ * method will do nothing and will instead always use the default value.
+ *
+ * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL
+ * @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL
+ * @see android.telephony.CarrierConfigManager#KEY_HIDE_ENHANCED_4G_LTE_BOOL
+ * @see android.telephony.CarrierConfigManager#KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL
+ * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_AVAILABLE_BOOL
+ * @see #isAdvancedCallingSettingEnabled()
*/
- @SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setAdvancedCallingSetting(boolean isEnabled) {
try {
@@ -464,12 +521,11 @@
* @return {@code true} if the MmTel IMS capability is capable for this subscription, false
* otherwise.
*/
- @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isCapable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
try {
- return getITelephony().isCapable(mSubId, capability, imsRegTech,
- mContext.getOpPackageName());
+ return getITelephony().isCapable(mSubId, capability, imsRegTech);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -492,12 +548,11 @@
* @return {@code true} if the MmTel IMS capability is available for this subscription, false
* otherwise.
*/
- @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isAvailable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
try {
- return getITelephony().isAvailable(mSubId, capability, imsRegTech,
- mContext.getOpPackageName());
+ return getITelephony().isAvailable(mSubId, capability, imsRegTech);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -508,11 +563,10 @@
* @return true if the user’s “Video Calling” setting is currently enabled.
* @see #setVtSetting(boolean)
*/
- @SystemApi
- @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isVtSettingEnabled() {
try {
- return getITelephony().isVtSettingEnabled(mSubId, mContext.getOpPackageName());
+ return getITelephony().isVtSettingEnabled(mSubId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -521,9 +575,7 @@
/**
* Change the user's setting for Video Telephony and enable the Video Telephony capability.
* @see #isVtSettingEnabled()
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVtSetting(boolean isEnabled) {
try {
@@ -537,9 +589,7 @@
/**
* @return true if the user's setting for Voice over WiFi is enabled and false if it is not.
* @see #setVoWiFiSetting(boolean)
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isVoWiFiSettingEnabled() {
try {
@@ -553,9 +603,7 @@
* Sets the user's setting for whether or not Voice over WiFi is enabled.
* @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise=
* @see #isVoWiFiSettingEnabled()
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiSetting(boolean isEnabled) {
try {
@@ -570,9 +618,7 @@
* @return true if the user's setting for Voice over WiFi while roaming is enabled, false
* if disabled.
* @see #setVoWiFiRoamingSetting(boolean)
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isVoWiFiRoamingSettingEnabled() {
try {
@@ -587,9 +633,7 @@
* @param isEnabled true if the user's setting for Voice over WiFi while roaming is enabled,
* false otherwise.
* @see #isVoWiFiRoamingSettingEnabled()
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingSetting(boolean isEnabled) {
try {
@@ -611,9 +655,7 @@
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
* @see #setVoWiFiSetting(boolean)
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
try {
@@ -631,9 +673,7 @@
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
* @see #setVoWiFiSetting(boolean)
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @WiFiCallingMode int getVoWiFiModeSetting() {
try {
@@ -651,9 +691,7 @@
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
* @see #getVoWiFiModeSetting()
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
try {
@@ -674,9 +712,7 @@
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
* @see #setVoWiFiRoamingSetting(boolean)
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
@WiFiCallingMode int getVoWiFiRoamingModeSetting() {
try {
@@ -696,9 +732,7 @@
* - {@link #WIFI_MODE_CELLULAR_PREFERRED}
* - {@link #WIFI_MODE_WIFI_PREFERRED}
* @see #getVoWiFiRoamingModeSetting()
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
try {
@@ -712,9 +746,7 @@
/**
* Change the user's setting for RTT capability of this device.
* @param isEnabled if true RTT will be enabled during calls.
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setRttCapabilitySetting(boolean isEnabled) {
try {
@@ -729,9 +761,7 @@
* @return true if TTY over VoLTE is supported
* @see android.telecom.TelecomManager#getCurrentTtyMode
* @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL
- * @hide
*/
- @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
boolean isTtyOverVolteEnabled() {
try {
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 3f22f98..b55866b 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -425,6 +425,12 @@
*/
public final void addCapabilityCallback(IImsCapabilityCallback c) {
mCapabilityCallbacks.register(c);
+ try {
+ // Notify the Capability callback that was just registered of the current capabilities.
+ c.onCapabilitiesStatusChanged(queryCapabilityStatus().mCapabilities);
+ } catch (RemoteException e) {
+ Log.w(LOG_TAG, "addCapabilityCallback: error accessing callback: " + e.getMessage());
+ }
}
/**
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index f0e8586..fc42de5 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1372,6 +1372,15 @@
String getSubscriptionPreciseCarrierName(int subId);
/**
+ * Returns carrier id based on MCCMNC only. This will return a MNO carrier id used for fallback
+ * check when exact carrier id {@link #getSimCarrierId()} configurations are not found
+ *
+ * @return carrier id from passing mccmnc.
+ * @hide
+ */
+ int getCarrierIdFromMccMnc(int slotIndex, String mccmnc);
+
+ /**
* Action set from carrier signalling broadcast receivers to enable/disable metered apns
* Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
* @param subId the subscription ID that this action applies to.
@@ -1587,35 +1596,31 @@
/**
* Adds an IMS registration status callback for the subscription id specified.
*/
- void addImsRegistrationCallback(int subId, IImsRegistrationCallback c,
- String callingPackage);
+ void registerImsRegistrationCallback(int subId, IImsRegistrationCallback c);
/**
* Removes an existing IMS registration status callback for the subscription specified.
*/
- void removeImsRegistrationCallback(int subId, IImsRegistrationCallback c,
- String callingPackage);
+ void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c);
/**
* Adds an IMS MmTel capabilities callback for the subscription specified.
*/
- void addMmTelCapabilityCallback(int subId, IImsCapabilityCallback c,
- String callingPackage);
+ void registerMmTelCapabilityCallback(int subId, IImsCapabilityCallback c);
/**
* Removes an existing IMS MmTel capabilities callback for the subscription specified.
*/
- void removeMmTelCapabilityCallback(int subId, IImsCapabilityCallback c,
- String callingPackage);
+ void unregisterMmTelCapabilityCallback(int subId, IImsCapabilityCallback c);
/**
* return true if the IMS MmTel capability for the given registration tech is capable.
*/
- boolean isCapable(int subId, int capability, int regTech, String callingPackage);
+ boolean isCapable(int subId, int capability, int regTech);
/**
* return true if the IMS MmTel capability for the given registration tech is available.
*/
- boolean isAvailable(int subId, int capability, int regTech, String callingPackage);
+ boolean isAvailable(int subId, int capability, int regTech);
/**
* Returns true if the user's setting for 4G LTE is enabled, for the subscription specified.
@@ -1630,7 +1635,7 @@
/**
* return true if the user's setting for VT is enabled for the subscription.
*/
- boolean isVtSettingEnabled(int subId, String callingPackage);
+ boolean isVtSettingEnabled(int subId);
/**
* Modify the user's setting for whether or not VT is available for the subscrption specified.
@@ -1704,7 +1709,7 @@
* Identify if the number is emergency number, based on all the active subscriptions.
*/
boolean isCurrentEmergencyNumber(String number);
-
+
/**
* Return a list of certs in hex string from loaded carrier privileges access rules.
*/
diff --git a/test-mock/api/current.txt b/test-mock/api/current.txt
index f91d74a..7842a1c 100644
--- a/test-mock/api/current.txt
+++ b/test-mock/api/current.txt
@@ -135,6 +135,7 @@
method public boolean stopService(android.content.Intent);
method public void unbindService(android.content.ServiceConnection);
method public void unregisterReceiver(android.content.BroadcastReceiver);
+ method public void updateServiceGroup(android.content.ServiceConnection, int, int);
}
public deprecated class MockCursor implements android.database.Cursor {
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 66be6d9..ae6cd29 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -591,6 +591,11 @@
}
@Override
+ public void updateServiceGroup(ServiceConnection conn, int group, int importance) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
public void unbindService(ServiceConnection conn) {
throw new UnsupportedOperationException();
}