Merge "Persist data to disk when system shuts down"
diff --git a/Android.bp b/Android.bp
index 7e71bdf..e135a50 100644
--- a/Android.bp
+++ b/Android.bp
@@ -614,6 +614,7 @@
":netd_aidl",
":vold_aidl",
":installd_aidl",
+ ":dumpstate_aidl",
"lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl",
"lowpan/java/android/net/lowpan/ILowpanNetScanCallback.aidl",
@@ -660,6 +661,7 @@
include_dirs: [
"system/update_engine/binder_bindings",
"frameworks/native/aidl/binder",
+ "frameworks/native/cmds/dumpstate/binder",
"frameworks/av/camera/aidl",
"frameworks/av/media/libaudioclient/aidl",
"frameworks/native/aidl/gui",
@@ -682,9 +684,6 @@
no_framework_libs: true,
libs: [
- "conscrypt",
- "okhttp",
- "bouncycastle",
"ext",
],
@@ -706,6 +705,7 @@
"android.hardware.radio-V1.0-java",
"android.hardware.radio-V1.3-java",
"android.hardware.usb.gadget-V1.0-java",
+ "netd_aidl_interface-java",
],
// Loaded with System.loadLibrary by android.view.textclassifier
@@ -835,7 +835,6 @@
"cmds/statsd/src/**/*.proto",
"core/proto/**/*.proto",
"libs/incident/proto/**/*.proto",
- "proto/src/stats_enums.proto",
],
proto: {
include_dirs: ["external/protobuf/src"],
@@ -873,7 +872,6 @@
srcs: [
"core/proto/**/*.proto",
"libs/incident/proto/android/os/**/*.proto",
- "proto/src/stats_enums.proto",
],
// Protos have lots of MissingOverride and similar.
errorprone: {
@@ -899,7 +897,6 @@
srcs: [
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
- "proto/src/stats_enums.proto",
],
target: {
@@ -1102,8 +1099,6 @@
"-federationapi SupportLib $(location current/support-api.txt) "
framework_docs_only_libs = [
- "conscrypt",
- "bouncycastle",
"voip-common",
"android.test.mock",
"android-support-annotations",
@@ -1580,7 +1575,6 @@
"core/java/org/apache/http/params/CoreConnectionPNames.java",
"core/java/org/apache/http/params/HttpConnectionParams.java",
"core/java/org/apache/http/params/HttpParams.java",
- "core/java/android/net/http/HttpResponseCache.java",
"core/java/android/net/http/SslCertificate.java",
"core/java/android/net/http/SslError.java",
"core/java/com/android/internal/util/HexDump.java",
diff --git a/api/current.txt b/api/current.txt
index 3a44d34..0b6af29 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -32540,7 +32540,7 @@
public class Build {
ctor public Build();
- method public static java.util.List<android.os.Build.Partition> getPartitions();
+ method public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions();
method public static java.lang.String getRadioVersion();
method public static java.lang.String getSerial();
field public static final java.lang.String BOARD;
@@ -32571,9 +32571,9 @@
public static class Build.Partition {
ctor public Build.Partition();
+ method public long getBuildTimeMillis();
method public java.lang.String getFingerprint();
method public java.lang.String getName();
- method public long getTimeMillis();
field public static final java.lang.String PARTITION_NAME_SYSTEM = "system";
}
@@ -43323,7 +43323,7 @@
field public static final int PROTOCOL_IPV6 = 1; // 0x1
field public static final int PROTOCOL_PPP = 3; // 0x3
field public static final int TYPE_CBS = 128; // 0x80
- field public static final int TYPE_DEFAULT = 1; // 0x1
+ field public static final int TYPE_DEFAULT = 17; // 0x11
field public static final int TYPE_DUN = 8; // 0x8
field public static final int TYPE_EMERGENCY = 512; // 0x200
field public static final int TYPE_FOTA = 32; // 0x20
@@ -48025,6 +48025,7 @@
public class TouchDelegate {
ctor public TouchDelegate(android.graphics.Rect, android.view.View);
+ method public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo();
method public boolean onTouchEvent(android.view.MotionEvent);
field public static final int ABOVE = 1; // 0x1
field public static final int BELOW = 2; // 0x2
@@ -50007,6 +50008,7 @@
method public int getTextSelectionEnd();
method public int getTextSelectionStart();
method public java.lang.CharSequence getTooltipText();
+ method public android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo getTouchDelegateInfo();
method public android.view.accessibility.AccessibilityNodeInfo getTraversalAfter();
method public android.view.accessibility.AccessibilityNodeInfo getTraversalBefore();
method public java.lang.String getViewIdResourceName();
@@ -50097,6 +50099,7 @@
method public void setTextEntryKey(boolean);
method public void setTextSelection(int, int);
method public void setTooltipText(java.lang.CharSequence);
+ method public void setTouchDelegateInfo(android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo);
method public void setTraversalAfter(android.view.View);
method public void setTraversalAfter(android.view.View, int);
method public void setTraversalBefore(android.view.View);
@@ -50223,6 +50226,16 @@
field public static final int RANGE_TYPE_PERCENT = 2; // 0x2
}
+ public static final class AccessibilityNodeInfo.TouchDelegateInfo implements android.os.Parcelable {
+ ctor public AccessibilityNodeInfo.TouchDelegateInfo(java.util.Map<android.graphics.Region, android.view.View>);
+ method public int describeContents();
+ method public android.graphics.Region getRegionAt(int);
+ method public int getRegionCount();
+ method public android.view.accessibility.AccessibilityNodeInfo getTargetForRegion(android.graphics.Region);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo> CREATOR;
+ }
+
public abstract class AccessibilityNodeProvider {
ctor public AccessibilityNodeProvider();
method public void addExtraDataToAccessibilityNodeInfo(int, android.view.accessibility.AccessibilityNodeInfo, java.lang.String, android.os.Bundle);
diff --git a/api/system-current.txt b/api/system-current.txt
index ac8fc9c..8bcb0be 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -119,6 +119,7 @@
field public static final java.lang.String MOUNT_FORMAT_FILESYSTEMS = "android.permission.MOUNT_FORMAT_FILESYSTEMS";
field public static final java.lang.String MOUNT_UNMOUNT_FILESYSTEMS = "android.permission.MOUNT_UNMOUNT_FILESYSTEMS";
field public static final java.lang.String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
+ field public static final java.lang.String NETWORK_SETUP_WIZARD = "android.permission.NETWORK_SETUP_WIZARD";
field public static final java.lang.String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
field public static final java.lang.String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
field public static final java.lang.String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
@@ -1280,14 +1281,6 @@
}
-package android.graphics.drawable {
-
- public final class Icon implements android.os.Parcelable {
- method public static android.graphics.drawable.Icon createWithResource(android.content.res.Resources, int);
- }
-
-}
-
package android.hardware {
public final class Sensor {
@@ -3189,6 +3182,7 @@
public class ConnectivityManager {
method public java.lang.String getCaptivePortalServerUrl();
method public boolean isTetheringSupported();
+ method public void setAirplaneMode(boolean);
method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
method public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
method public void stopTethering(int);
@@ -5287,6 +5281,7 @@
method public int getRejectCause();
method public int getTransportType();
method public boolean isEmergencyEnabled();
+ method public boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationState> CREATOR;
field public static final int DOMAIN_CS = 1; // 0x1
@@ -5374,6 +5369,8 @@
method public void setSubscriptionPlans(int, java.util.List<android.telephony.SubscriptionPlan>);
field public static final java.lang.String ACTION_MANAGE_SUBSCRIPTION_PLANS = "android.telephony.action.MANAGE_SUBSCRIPTION_PLANS";
field public static final java.lang.String ACTION_REFRESH_SUBSCRIPTION_PLANS = "android.telephony.action.REFRESH_SUBSCRIPTION_PLANS";
+ field public static final android.net.Uri ENHANCED_4G_ENABLED_CONTENT_URI;
+ field public static final android.net.Uri WFC_ENABLED_CONTENT_URI;
}
public final class SubscriptionPlan implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 937c266..463c9d3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1609,6 +1609,10 @@
method public void writeToParcelNoRecycle(android.os.Parcel, int);
}
+ public static final class AccessibilityNodeInfo.TouchDelegateInfo implements android.os.Parcelable {
+ method public long getAccessibilityIdForRegion(android.graphics.Region);
+ }
+
public final class AccessibilityWindowInfo implements android.os.Parcelable {
method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger);
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 9d83afd..e5d71d9 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -29,8 +29,8 @@
import "frameworks/base/core/proto/android/telecomm/enums.proto";
import "frameworks/base/core/proto/android/telephony/enums.proto";
import "frameworks/base/core/proto/android/view/enums.proto";
-import "frameworks/base/proto/src/stats_enums.proto";
import "frameworks/base/core/proto/android/service/procstats.proto";
+import "frameworks/base/core/proto/android/stats/enums.proto";
import "frameworks/base/core/proto/android/internal/powerprofile.proto";
/**
@@ -129,6 +129,8 @@
AppCrashOccurred app_crash_occurred = 78;
ANROccurred anr_occurred = 79;
WTFOccurred wtf_occurred = 80;
+ PhoneServiceStateChanged phone_service_state_changed = 94;
+ PhoneStateChanged phone_state_changed = 95;
LowMemReported low_mem_reported = 81;
GenericAtom generic_atom = 82;
KeyValuePairsAtom key_value_pairs_atom = 83;
@@ -1406,6 +1408,33 @@
optional android.telephony.SignalStrengthEnum signal_strength = 1;
}
+
+/**
+ * Logs when the phone state, sim state or signal strength changes
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message PhoneServiceStateChanged {
+ optional android.telephony.ServiceStateEnum state = 1;
+ optional android.telephony.SimStateEnum sim_state = 2;
+ optional android.telephony.SignalStrengthEnum signal_strength = 3;
+}
+
+/**
+ * Logs when the phone becomes on or off.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/TelephonyRegistry.java
+ */
+message PhoneStateChanged {
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 1;
+}
+
/**
* Logs that a setting was updated.
* Logged from:
@@ -1923,7 +1952,7 @@
optional int32 uid = 1 [(is_uid) = true];
// An event_id indicates the type of event.
- optional android.os.statsd.EventType event_id = 2;
+ optional android.stats.EventType event_id = 2;
}
/**
@@ -2675,4 +2704,4 @@
*/
message PowerProfile {
optional com.android.internal.os.PowerProfileProto power_profile_proto = 1;
-}
\ No newline at end of file
+}
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 6af34f9..b71274c 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -523,7 +523,6 @@
Landroid/net/IConnectivityManager;->getTetheredIfaces()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->getTetheringErroredIfaces()[Ljava/lang/String;
Landroid/net/IConnectivityManager;->reportInetCondition(II)V
-Landroid/net/IConnectivityManager;->setAirplaneMode(Z)V
Landroid/net/IConnectivityManager;->startLegacyVpn(Lcom/android/internal/net/VpnProfile;)V
Landroid/net/INetworkManagementEventObserver$Stub;-><init>()V
Landroid/net/INetworkPolicyListener$Stub;-><init>()V
@@ -2216,6 +2215,7 @@
Lcom/android/org/conscrypt/OpenSSLKey;->getNativeRef()Lcom/android/org/conscrypt/NativeRef$EVP_PKEY;
Lcom/android/org/conscrypt/OpenSSLKey;->getPublicKey()Ljava/security/PublicKey;
Lcom/android/org/conscrypt/OpenSSLProvider;-><init>()V
+Lcom/android/org/conscrypt/OpenSSLRandom;-><init>()V
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getAlpnSelectedProtocol()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getChannelId()[B
Lcom/android/org/conscrypt/OpenSSLSocketImpl;->getHostname()Ljava/lang/String;
@@ -2791,6 +2791,7 @@
Ljavax/net/ssl/SSLSocketFactory;->createSocket(Ljava/net/Socket;Ljava/io/InputStream;Z)Ljava/net/Socket;
Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
Llibcore/icu/ICU;->addLikelySubtags(Ljava/util/Locale;)Ljava/util/Locale;
+Llibcore/io/Libcore;->os:Llibcore/io/Os;
Llibcore/io/Memory;->peekByte(J)B
Llibcore/io/Memory;->peekByteArray(J[BII)V
Llibcore/io/Memory;->peekInt(JZ)I
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 6c87fe7..0044005 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -377,15 +377,11 @@
return new DisplayManager(ctx.getOuterContext());
}});
- // InputMethodManager has its own cache strategy based on display id to support apps that
- // still assume InputMethodManager is a per-process singleton and it's safe to directly
- // access internal fields via reflection. Hence directly use ServiceFetcher instead of
- // StaticServiceFetcher/CachedServiceFetcher.
registerService(Context.INPUT_METHOD_SERVICE, InputMethodManager.class,
- new ServiceFetcher<InputMethodManager>() {
+ new StaticServiceFetcher<InputMethodManager>() {
@Override
- public InputMethodManager getService(ContextImpl ctx) {
- return InputMethodManager.forContext(ctx);
+ public InputMethodManager createService() {
+ return InputMethodManager.getInstanceInternal();
}});
registerService(Context.TEXT_SERVICES_MANAGER_SERVICE, TextServicesManager.class,
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 30d5fbc..0aa0535 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -107,20 +107,6 @@
"android.bluetooth.device.action.FOUND";
/**
- * Broadcast Action: Remote device disappeared.
- * <p>Sent when a remote device that was found in the last discovery is not
- * found in the current discovery.
- * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
- *
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage
- public static final String ACTION_DISAPPEARED =
- "android.bluetooth.device.action.DISAPPEARED";
-
- /**
* Broadcast Action: Bluetooth class of a remote device has changed.
* <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
* #EXTRA_CLASS}.
@@ -654,7 +640,7 @@
public static final int ACCESS_REJECTED = 2;
/**
- * No preferrence of physical transport for GATT connections to remote dual-mode devices
+ * No preference of physical transport for GATT connections to remote dual-mode devices
*/
public static final int TRANSPORT_AUTO = 0;
@@ -1971,9 +1957,7 @@
* <p>The remote device will be authenticated and communication on this socket will be
* encrypted.
* <p> Use this socket if an authenticated socket link is possible. Authentication refers
- * to the authentication of the link key to prevent man-in-the-middle type of attacks. When a
- * secure socket connection is not possible, use {@link createInsecureLeL2capCocSocket(int,
- * int)}.
+ * to the authentication of the link key to prevent man-in-the-middle type of attacks.
*
* @param psm dynamic PSM value from remote device
* @return a CoC #BluetoothSocket ready for an outgoing connection
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 29d5a1c..9b7c173 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -1292,7 +1292,7 @@
* <p>After all characteristics have been queued up and verified,
* {@link #executeReliableWrite} will execute all writes. If a characteristic
* was not written correctly, calling {@link #abortReliableWrite} will
- * cancel the current transaction without commiting any values on the
+ * cancel the current transaction without committing any values on the
* remote device.
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
index ef1b0bd..13b1b4f 100644
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ b/core/java/android/bluetooth/BluetoothGattServer.java
@@ -522,7 +522,7 @@
* {@link BluetoothGattServerCallback#onConnectionStateChange} callback will be
* invoked when the connection state changes as a result of this function.
*
- * <p>The autoConnect paramter determines whether to actively connect to
+ * <p>The autoConnect parameter determines whether to actively connect to
* the remote device, or rather passively scan and finalize the connection
* when the remote device is in range/available. Generally, the first ever
* connection to a device should be direct (autoConnect set to false) and
@@ -695,7 +695,7 @@
/**
* Add a service to the list of services to be hosted.
*
- * <p>Once a service has been addded to the the list, the service and its
+ * <p>Once a service has been addded to the list, the service and its
* included characteristics will be provided by the local device.
*
* <p>If the local device has already exposed services when this function
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 758c68d..4e88625 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -203,8 +203,8 @@
/**
* Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP
* Connection-oriented Channel (CoC) server socket. This server socket must be returned by the
- * {@link BluetoothAdapter.listenUsingL2capChannel()} or {@link
- * BluetoothAdapter.listenUsingInsecureL2capChannel()}. The returned value is undefined if this
+ * {@link BluetoothAdapter#listenUsingL2capChannel()} or {@link
+ * BluetoothAdapter#listenUsingInsecureL2capChannel()}. The returned value is undefined if this
* method is called on non-L2CAP server sockets.
*
* @return the assigned PSM or LE_PSM value depending on transport
diff --git a/core/java/android/bluetooth/le/AdvertisingSetCallback.java b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
index 58a3696..51324fd 100644
--- a/core/java/android/bluetooth/le/AdvertisingSetCallback.java
+++ b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
@@ -56,7 +56,7 @@
/**
* Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet}
* indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertisingSet
- * contains the started set and it is advertising. If error occured, advertisingSet is
+ * contains the started set and it is advertising. If error occurred, advertisingSet is
* null, and status will be set to proper error code.
*
* @param advertisingSet The advertising set that was started or null if error.
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index b528e39..a086a30 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -95,7 +95,7 @@
* the SyncManager will wait until the sync adapter is not in use before requesting that
* it sync an account's data.
* <li><code>android:isAlwaysSyncable</code> defaults to false and if true tells the SyncManager
- * to intialize the isSyncable state to 1 for that sync adapter for each account that is added.
+ * to initialize the isSyncable state to 1 for that sync adapter for each account that is added.
* <li><code>android:syncAdapterSettingsAction</code> defaults to null and if supplied it
* specifies an Intent action of an activity that can be used to adjust the sync adapter's
* sync settings. The activity must live in the same package as the sync adapter.
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 089cf10..ed3d455 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -224,7 +224,7 @@
* Create an Item consisting of a single block of (possibly styled) text,
* with an alternative HTML formatted representation. You <em>must</em>
* supply a plain text representation in addition to HTML text; coercion
- * will not be done from HTML formated text into plain text.
+ * will not be done from HTML formatted text into plain text.
*/
public Item(CharSequence text, String htmlText) {
mText = text;
@@ -268,7 +268,7 @@
* Create a complex Item, containing multiple representations of
* text, HTML text, Intent, and/or URI. If providing HTML text, you
* <em>must</em> supply a plain text representation as well; coercion
- * will not be done from HTML formated text into plain text.
+ * will not be done from HTML formatted text into plain text.
*/
public Item(CharSequence text, String htmlText, Intent intent, Uri uri) {
if (htmlText != null && text == null) {
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 7dc4577..6a3fa6b2 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -637,7 +637,7 @@
/**
* The selection and arguments to use. An occurrence of '?' in the selection will be
- * replaced with the corresponding occurence of the selection argument. Any of the
+ * replaced with the corresponding occurrence of the selection argument. Any of the
* selection arguments may be overwritten by a selection argument back reference as
* specified by {@link #withSelectionBackReference}.
* This can only be used with builders of type update, delete, or assert.
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index a882434..c19909d 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1877,7 +1877,7 @@
* that services the content at uri, starting the provider if necessary. Returns
* null if there is no provider associated wih the uri. The caller must indicate that they are
* done with the provider by calling {@link ContentProviderClient#release} which will allow
- * the system to release the provider it it determines that there is no other reason for
+ * the system to release the provider if it determines that there is no other reason for
* keeping it active.
* @param uri specifies which provider should be acquired
* @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
@@ -1897,7 +1897,7 @@
* with the authority of name, starting the provider if necessary. Returns
* null if there is no provider associated wih the uri. The caller must indicate that they are
* done with the provider by calling {@link ContentProviderClient#release} which will allow
- * the system to release the provider it it determines that there is no other reason for
+ * the system to release the provider if it determines that there is no other reason for
* keeping it active.
* @param name specifies which provider should be acquired
* @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d711574..db4adcf 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -187,7 +187,7 @@
*
* <p>This was the legacy (but undocumented) behavior in and
* before Gingerbread (Android 2.3) and this flag is implied when
- * targetting such releases. For applications targetting SDK
+ * targeting such releases. For applications targeting SDK
* versions <em>greater than</em> Android 2.3, this flag must be
* explicitly set if desired.
*
@@ -2840,7 +2840,7 @@
*
* @param service Description of the service to be stopped. The Intent must be either
* fully explicit (supplying a component name) or specify a specific package
- * name it is targetted to.
+ * name it is targeted to.
*
* @return If there is a service matching the given Intent that is already
* running, then it is stopped and {@code true} is returned; else {@code false} is returned.
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 4e46d571..4ccafab 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -36,7 +36,7 @@
* perform, either through the
* {@link #CursorLoader(Context, Uri, String[], String, String[], String)} or
* creating an empty instance with {@link #CursorLoader(Context)} and filling
- * in the desired paramters with {@link #setUri(Uri)}, {@link #setSelection(String)},
+ * in the desired parameters with {@link #setUri(Uri)}, {@link #setSelection(String)},
* {@link #setSelectionArgs(String[])}, {@link #setSortOrder(String)},
* and {@link #setProjection(String[])}.
*
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index af910e0..8913748 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3955,6 +3955,12 @@
public static final String EXTRA_LTE_EARFCN_RSRP_BOOST = "LteEarfcnRsrpBoost";
/**
+ * An parcelable extra used with {@link #ACTION_SERVICE_STATE} representing the service state.
+ * @hide
+ */
+ public static final String EXTRA_SERVICE_STATE = "android.intent.extra.SERVICE_STATE";
+
+ /**
* The name of the extra used to define the text to be processed, as a
* CharSequence. Note that this may be a styled CharSequence, so you must use
* {@link Bundle#getCharSequence(String) Bundle.getCharSequence()} to retrieve it.
@@ -5523,7 +5529,7 @@
/**
* If set and this intent is being used to launch a new activity from an
* existing one, then the reply target of the existing activity will be
- * transfered to the new activity. This way the new activity can call
+ * transferred to the new activity. This way, the new activity can call
* {@link android.app.Activity#setResult} and have that result sent back to
* the reply target of the original activity.
*/
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 0469a90..36d8a37 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -479,7 +479,7 @@
/**
* Modify priority of this filter. This only affects receiver filters.
* The priority of activity filters are set in XML and cannot be changed
- * programatically. The default priority is 0. Positive values will be
+ * programmatically. The default priority is 0. Positive values will be
* before the default, lower values will be after it. Applications should
* use a value that is larger than {@link #SYSTEM_LOW_PRIORITY} and
* smaller than {@link #SYSTEM_HIGH_PRIORITY} .
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 5926af6..0a4f4eb 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1408,5 +1408,13 @@
* @attr ref android.R.styleable#AndroidManifestLayout_minHeight
*/
public final int minHeight;
+
+ /**
+ * Returns if this {@link WindowLayout} has specified bounds.
+ * @hide
+ */
+ public boolean hasSpecifiedSize() {
+ return width >= 0 || height >= 0 || widthFraction >= 0 || heightFraction >= 0;
+ }
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 225b6cf..c33f143 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -236,7 +236,7 @@
/**
* Value for {@link #flags}: true when the application knows how to
- * accomodate different screen densities. Corresponds to
+ * accommodate different screen densities. Corresponds to
* {@link android.R.styleable#AndroidManifestSupportsScreens_anyDensity
* android:anyDensity}.
*/
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 3032d16..733fbe5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5187,6 +5187,7 @@
* @param packageName The name of the package to query
* @throws IllegalArgumentException if the given package name is not installed
*/
+ @Nullable
public abstract String getInstallerPackageName(String packageName);
/**
diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java
index 8f8f676..42e7ac7 100644
--- a/core/java/android/database/sqlite/SQLiteStatement.java
+++ b/core/java/android/database/sqlite/SQLiteStatement.java
@@ -53,7 +53,7 @@
}
/**
- * Execute this SQL statement, if the the number of rows affected by execution of this SQL
+ * Execute this SQL statement, if the number of rows affected by execution of this SQL
* statement is of any importance to the caller - for example, UPDATE / DELETE SQL statements.
*
* @return the number of rows affected by this SQL statement execution.
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 486b054..d4dc181 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2090,7 +2090,7 @@
/**
* <p>Optimized for dim settings where the main light source
- * is a flame.</p>
+ * is a candle.</p>
* @see CaptureRequest#CONTROL_SCENE_MODE
*/
public static final int CONTROL_SCENE_MODE_CANDLELIGHT = 15;
diff --git a/core/java/android/hardware/location/ContextHubClient.java b/core/java/android/hardware/location/ContextHubClient.java
index 917644d..6609b76 100644
--- a/core/java/android/hardware/location/ContextHubClient.java
+++ b/core/java/android/hardware/location/ContextHubClient.java
@@ -133,6 +133,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public boolean registerIntent(@NonNull PendingIntent intent, long nanoAppId) {
// TODO: Implement this
return false;
@@ -146,6 +147,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
public boolean unregisterIntent(@NonNull PendingIntent intent) {
// TODO: Implement this
return false;
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 36f3586..f94d69b 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -749,6 +749,7 @@
*
* @see ContextHubClientCallback
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback,
@NonNull @CallbackExecutor Executor executor) {
@@ -785,6 +786,7 @@
*
* @see ContextHubClientCallback
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull ContextHubInfo hubInfo, @NonNull ContextHubClientCallback callback) {
return createClient(hubInfo, callback, new HandlerExecutor(Handler.getMain()));
@@ -811,6 +813,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo,
@NonNull ContextHubClientCallback callback,
@@ -835,6 +838,7 @@
*
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
@NonNull public ContextHubClient createClient(
@NonNull PendingIntent intent, @NonNull ContextHubInfo hubInfo,
@NonNull ContextHubClientCallback callback) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 8333b81..c496ff4 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -83,6 +83,7 @@
@SystemService(Context.CONNECTIVITY_SERVICE)
public class ConnectivityManager {
private static final String TAG = "ConnectivityManager";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
* A change in network connectivity has occurred. A default connection has either
@@ -2493,6 +2494,7 @@
* {@hide}
*/
public void reportInetCondition(int networkType, int percentage) {
+ printStackTrace();
try {
mService.reportInetCondition(networkType, percentage);
} catch (RemoteException e) {
@@ -2513,6 +2515,7 @@
*/
@Deprecated
public void reportBadNetwork(Network network) {
+ printStackTrace();
try {
// One of these will be ignored because it matches system's current state.
// The other will trigger the necessary reevaluation.
@@ -2535,6 +2538,7 @@
* Internet using {@code network} or {@code false} if not.
*/
public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
+ printStackTrace();
try {
mService.reportNetworkConnectivity(network, hasConnectivity);
} catch (RemoteException e) {
@@ -2728,7 +2732,7 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
- @UnsupportedAppUsage
+ @SystemApi
public void setAirplaneMode(boolean enable) {
try {
mService.setAirplaneMode(enable);
@@ -3073,6 +3077,7 @@
private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
int timeoutMs, int action, int legacyType, CallbackHandler handler) {
+ printStackTrace();
checkCallbackNotNull(callback);
Preconditions.checkArgument(action == REQUEST || need != null, "null NetworkCapabilities");
final NetworkRequest request;
@@ -3332,6 +3337,7 @@
* {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
*/
public void requestNetwork(NetworkRequest request, PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.pendingRequestForNetwork(request.networkCapabilities, operation);
@@ -3355,6 +3361,7 @@
* corresponding NetworkRequest you'd like to remove. Cannot be null.
*/
public void releaseNetworkRequest(PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.releasePendingNetworkRequest(operation);
@@ -3439,6 +3446,7 @@
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerNetworkCallback(NetworkRequest request, PendingIntent operation) {
+ printStackTrace();
checkPendingIntentNotNull(operation);
try {
mService.pendingListenForNetwork(request.networkCapabilities, operation);
@@ -3520,6 +3528,7 @@
* @param networkCallback The {@link NetworkCallback} used when making the request.
*/
public void unregisterNetworkCallback(NetworkCallback networkCallback) {
+ printStackTrace();
checkCallbackNotNull(networkCallback);
final List<NetworkRequest> reqs = new ArrayList<>();
// Find all requests associated to this callback and stop callback triggers immediately.
@@ -3948,4 +3957,19 @@
throw e.rethrowFromSystemServer();
}
}
+
+ private void printStackTrace() {
+ if (DEBUG) {
+ final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
+ final StringBuffer sb = new StringBuffer();
+ for (int i = 3; i < callStack.length; i++) {
+ final String stackTrace = callStack[i].toString();
+ if (stackTrace == null || stackTrace.contains("android.os")) {
+ break;
+ }
+ sb.append(" [").append(stackTrace).append("]");
+ }
+ Log.d(TAG, "StackLog:" + sb.toString());
+ }
+ }
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 26c2033..412a700 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -17,6 +17,7 @@
package android.os;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SuppressAutoDoc;
import android.annotation.SystemApi;
@@ -1112,19 +1113,37 @@
}
/** The name of this partition, e.g. "system", or "vendor" */
+ @NonNull
public String getName() {
return mName;
}
/** The build fingerprint of this partition, see {@link Build#FINGERPRINT}. */
+ @NonNull
public String getFingerprint() {
return mFingerprint;
}
/** The time (ms since epoch), at which this partition was built, see {@link Build#TIME}. */
- public long getTimeMillis() {
+ public long getBuildTimeMillis() {
return mTimeMs;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Partition)) {
+ return false;
+ }
+ Partition op = (Partition) o;
+ return mName.equals(op.mName)
+ && mFingerprint.equals(op.mFingerprint)
+ && mTimeMs == op.mTimeMs;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mFingerprint, mTimeMs);
+ }
}
/**
@@ -1133,7 +1152,8 @@
* The list includes partitions that are suitable candidates for over-the-air updates. This is
* not an exhaustive list of partitions on the device.
*/
- public static List<Partition> getPartitions() {
+ @NonNull
+ public static List<Partition> getFingerprintedPartitions() {
ArrayList<Partition> partitions = new ArrayList();
String[] names = new String[] {
diff --git a/core/java/android/os/DumpstateOptions.java b/core/java/android/os/DumpstateOptions.java
new file mode 100644
index 0000000..53037b24
--- /dev/null
+++ b/core/java/android/os/DumpstateOptions.java
@@ -0,0 +1,57 @@
+/*
+ * 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.os;
+
+/**
+ * Options passed to dumpstate service.
+ *
+ * @hide
+ */
+public final class DumpstateOptions implements Parcelable {
+ // If true the caller can get callbacks with per-section
+ // progress details.
+ private final boolean mGetSectionDetails;
+ // Name of the caller.
+ private final String mName;
+
+ public DumpstateOptions(Parcel in) {
+ mGetSectionDetails = in.readBoolean();
+ mName = in.readString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeBoolean(mGetSectionDetails);
+ out.writeString(mName);
+ }
+
+ public static final Parcelable.Creator<DumpstateOptions> CREATOR =
+ new Parcelable.Creator<DumpstateOptions>() {
+ public DumpstateOptions createFromParcel(Parcel in) {
+ return new DumpstateOptions(in);
+ }
+
+ public DumpstateOptions[] newArray(int size) {
+ return new DumpstateOptions[size];
+ }
+ };
+}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index df3aae2..5f65620 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -55,7 +55,7 @@
* Set up GraphicsEnvironment
*/
public void setup(Context context, Bundle coreSettings) {
- setupGpuLayers(context, coreSettings);
+ setupGpuLayers(context);
setupAngle(context, coreSettings);
chooseDriver(context);
}
@@ -81,54 +81,27 @@
}
/**
- * Return the debug layer app's on-disk and in-APK lib directories
- */
- private static String getDebugLayerAppPaths(Context context, String app) {
- ApplicationInfo appInfo;
- try {
- appInfo = context.getPackageManager().getApplicationInfo(
- app, PackageManager.MATCH_ALL);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Debug layer app '" + app + "' not installed");
-
- return null;
- }
-
- String abi = chooseAbi(appInfo);
-
- StringBuilder sb = new StringBuilder();
- sb.append(appInfo.nativeLibraryDir)
- .append(File.pathSeparator);
- sb.append(appInfo.sourceDir)
- .append("!/lib/")
- .append(abi);
- String paths = sb.toString();
-
- if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
-
- return paths;
- }
-
- /**
* Set up layer search paths for all apps
* If debuggable, check for additional debug settings
*/
- private void setupGpuLayers(Context context, Bundle coreSettings) {
+ private void setupGpuLayers(Context context) {
String layerPaths = "";
// Only enable additional debug functionality if the following conditions are met:
- // 1. App is debuggable or device is rooted
+ // 1. App is debuggable
// 2. ENABLE_GPU_DEBUG_LAYERS is true
// 3. Package name is equal to GPU_DEBUG_APP
- if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1)) {
+ if (isDebuggable(context)) {
- int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
+ int enable = Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
if (enable != 0) {
- String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
+ String gpuDebugApp = Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.GPU_DEBUG_APP);
String packageName = context.getPackageName();
@@ -142,22 +115,8 @@
// the layers specified by the app.
layerPaths = mDebugLayerPath + ":";
-
- // If there is a debug layer app specified, add its path.
- String gpuDebugLayerApp =
- coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
-
- if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
- Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
- String paths = getDebugLayerAppPaths(context, gpuDebugLayerApp);
- if (paths != null) {
- // Append the path so files placed in the app's base directory will
- // override the external path
- layerPaths += paths + ":";
- }
- }
-
- String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
+ String layers = Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.GPU_DEBUG_LAYERS);
Log.i(TAG, "Debug layer list: " + layers);
if (layers != null && !layers.isEmpty()) {
@@ -331,7 +290,6 @@
return null;
}
- private static native int getCanLoadSystemLibraries();
private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
private static native void setDebugLayers(String layers);
private static native void setDriverPath(String path);
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index cd3f301..5d5e5e2 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -19,6 +19,8 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
*
* Defines a message containing a description and arbitrary data object that can be
@@ -111,7 +113,13 @@
/*package*/ int flags;
- /*package*/ long when;
+ /**
+ * The targeted delivery time of this message. The time-base is
+ * {@link SystemClock#uptimeMillis}.
+ * @hide Only for use within the tests.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public long when;
/*package*/ Bundle data;
@@ -382,7 +390,7 @@
* the <em>target</em> {@link Handler} that is receiving this Message to
* dispatch it. If
* not set, the message will be dispatched to the receiving Handler's
- * {@link Handler#handleMessage(Message Handler.handleMessage())}.
+ * {@link Handler#handleMessage(Message)}.
*/
public Runnable getCallback() {
return callback;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c6e4574..acb7577 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11631,12 +11631,6 @@
public static final String GPU_DEBUG_LAYERS = "gpu_debug_layers";
/**
- * Addition app for GPU layer discovery
- * @hide
- */
- public static final String GPU_DEBUG_LAYER_APP = "gpu_debug_layer_app";
-
- /**
* Control whether the process CPU usage meter should be shown.
*
* @deprecated This functionality is no longer available as of
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index f428c79..e9f1edf 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -245,9 +245,8 @@
* passed, it's treated as an empty rectangle (0,0)-(0,0).
*/
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
- public DisplayCutout(
- Insets safeInsets, @Nullable Rect boundLeft, @Nullable Rect boundTop,
- @Nullable Rect boundRight, @Nullable Rect boundBottom) {
+ public DisplayCutout(@NonNull Insets safeInsets, @Nullable Rect boundLeft,
+ @Nullable Rect boundTop, @Nullable Rect boundRight, @Nullable Rect boundBottom) {
this(safeInsets.toRect(), boundLeft, boundTop, boundRight, boundBottom, true);
}
@@ -262,7 +261,7 @@
*/
// TODO(b/73953958): @VisibleForTesting(visibility = PRIVATE)
@Deprecated
- public DisplayCutout(Rect safeInsets, List<Rect> boundingRects) {
+ public DisplayCutout(@Nullable Rect safeInsets, @Nullable List<Rect> boundingRects) {
this(safeInsets, extractBoundsFromList(safeInsets, boundingRects),
true /* copyArguments */);
}
@@ -313,18 +312,20 @@
for (int i = 0; i < sortedBounds.length; ++i) {
sortedBounds[i] = ZERO_RECT;
}
- for (Rect bound : boundingRects) {
- // There will be at most one non-functional area per short edge of the device, and none
- // on the long edges, so either safeInsets.right or safeInsets.bottom must be 0.
- // TODO(b/117199965): Refine the logic to handle edge cases.
- if (bound.left == 0) {
- sortedBounds[BOUNDS_POSITION_LEFT] = bound;
- } else if (bound.top == 0) {
- sortedBounds[BOUNDS_POSITION_TOP] = bound;
- } else if (safeInsets.right > 0) {
- sortedBounds[BOUNDS_POSITION_RIGHT] = bound;
- } else if (safeInsets.bottom > 0) {
- sortedBounds[BOUNDS_POSITION_BOTTOM] = bound;
+ if (safeInsets != null && boundingRects != null) {
+ for (Rect bound : boundingRects) {
+ // There is at most one non-functional area per short edge of the device, but none
+ // on the long edges, so either safeInsets.right or safeInsets.bottom must be 0.
+ // TODO(b/117199965): Refine the logic to handle edge cases.
+ if (bound.left == 0) {
+ sortedBounds[BOUNDS_POSITION_LEFT] = bound;
+ } else if (bound.top == 0) {
+ sortedBounds[BOUNDS_POSITION_TOP] = bound;
+ } else if (safeInsets.right > 0) {
+ sortedBounds[BOUNDS_POSITION_RIGHT] = bound;
+ } else if (safeInsets.bottom > 0) {
+ sortedBounds[BOUNDS_POSITION_BOTTOM] = bound;
+ }
}
}
return sortedBounds;
@@ -389,6 +390,7 @@
* @return a list of bounding {@code Rect}s, one for each display cutout area. No empty Rect is
* returned.
*/
+ @NonNull
public List<Rect> getBoundingRects() {
List<Rect> result = new ArrayList<>();
for (Rect bound : getBoundingRectsAll()) {
diff --git a/core/java/android/view/TouchDelegate.java b/core/java/android/view/TouchDelegate.java
index b361ab4..06b73dd 100644
--- a/core/java/android/view/TouchDelegate.java
+++ b/core/java/android/view/TouchDelegate.java
@@ -16,8 +16,12 @@
package android.view;
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.graphics.Rect;
+import android.graphics.Region;
+import android.util.ArrayMap;
+import android.view.accessibility.AccessibilityNodeInfo.TouchDelegateInfo;
/**
* Helper class to handle situations where you want a view to have a larger touch area than its
@@ -78,6 +82,11 @@
private int mSlop;
/**
+ * Touch delegate information for accessibility
+ */
+ private TouchDelegateInfo mTouchDelegateInfo;
+
+ /**
* Constructor
*
* @param bounds Bounds in local coordinates of the containing view that should be mapped to
@@ -145,4 +154,20 @@
}
return handled;
}
+
+ /**
+ * Return a {@link TouchDelegateInfo} mapping from regions (in view coordinates) to
+ * delegated views for accessibility usage.
+ *
+ * @return A TouchDelegateInfo.
+ */
+ @NonNull
+ public TouchDelegateInfo getTouchDelegateInfo() {
+ if (mTouchDelegateInfo == null) {
+ final ArrayMap<Region, View> targetMap = new ArrayMap<>(1);
+ targetMap.put(new Region(mBounds), mDelegateView);
+ mTouchDelegateInfo = new TouchDelegateInfo(targetMap);
+ }
+ return mTouchDelegateInfo;
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 1ed6203..c18187b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8881,6 +8881,10 @@
populateAccessibilityNodeInfoDrawingOrderInParent(info);
info.setPaneTitle(mAccessibilityPaneTitle);
info.setHeading(isAccessibilityHeading());
+
+ if (mTouchDelegate != null) {
+ info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo());
+ }
}
/**
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 4d3f0fc..e129091 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -23,10 +23,12 @@
import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -39,17 +41,21 @@
import android.text.style.AccessibilityURLSpan;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LongArray;
import android.util.Pools.SynchronizedPool;
+import android.view.TouchDelegate;
import android.view.View;
import com.android.internal.R;
import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
@@ -748,6 +754,8 @@
private CollectionInfo mCollectionInfo;
private CollectionItemInfo mCollectionItemInfo;
+ private TouchDelegateInfo mTouchDelegateInfo;
+
/**
* Hide constructor from clients.
*/
@@ -810,7 +818,7 @@
public AccessibilityNodeInfo findFocus(int focus) {
enforceSealed();
enforceValidFocusType(focus);
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return null;
}
return AccessibilityInteractionClient.getInstance().findFocus(mConnectionId, mWindowId,
@@ -834,7 +842,7 @@
public AccessibilityNodeInfo focusSearch(int direction) {
enforceSealed();
enforceValidFocusDirection(direction);
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return null;
}
return AccessibilityInteractionClient.getInstance().focusSearch(mConnectionId, mWindowId,
@@ -866,7 +874,7 @@
@UnsupportedAppUsage
public boolean refresh(Bundle arguments, boolean bypassCache) {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return false;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -967,7 +975,7 @@
if (mChildNodeIds == null) {
return null;
}
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return null;
}
final long childId = mChildNodeIds.get(index);
@@ -1271,7 +1279,7 @@
*/
public AccessibilityNodeInfo getTraversalBefore() {
enforceSealed();
- return getNodeForAccessibilityId(mTraversalBefore);
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mTraversalBefore);
}
/**
@@ -1332,7 +1340,7 @@
*/
public AccessibilityNodeInfo getTraversalAfter() {
enforceSealed();
- return getNodeForAccessibilityId(mTraversalAfter);
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mTraversalAfter);
}
/**
@@ -1489,7 +1497,7 @@
*/
public boolean performAction(int action) {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return false;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1512,7 +1520,7 @@
*/
public boolean performAction(int action, Bundle arguments) {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return false;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1536,7 +1544,7 @@
*/
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByText(String text) {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return Collections.emptyList();
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1567,7 +1575,7 @@
*/
public List<AccessibilityNodeInfo> findAccessibilityNodeInfosByViewId(String viewId) {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return Collections.emptyList();
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1584,7 +1592,7 @@
*/
public AccessibilityWindowInfo getWindow() {
enforceSealed();
- if (!canPerformRequestOverConnection(mSourceNodeId)) {
+ if (!canPerformRequestOverConnection(mConnectionId, mWindowId, mSourceNodeId)) {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
@@ -1603,7 +1611,7 @@
*/
public AccessibilityNodeInfo getParent() {
enforceSealed();
- return getNodeForAccessibilityId(mParentNodeId);
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mParentNodeId);
}
/**
@@ -2783,7 +2791,7 @@
*/
public AccessibilityNodeInfo getLabelFor() {
enforceSealed();
- return getNodeForAccessibilityId(mLabelForId);
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabelForId);
}
/**
@@ -2835,7 +2843,7 @@
*/
public AccessibilityNodeInfo getLabeledBy() {
enforceSealed();
- return getNodeForAccessibilityId(mLabeledById);
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mLabeledById);
}
/**
@@ -2975,6 +2983,43 @@
}
/**
+ * Get the {@link TouchDelegateInfo} for touch delegate behavior with the represented view.
+ * It is possible for the same node to be pointed to by several regions. Use
+ * {@link TouchDelegateInfo#getRegionAt(int)} to get touch delegate target {@link Region}, and
+ * {@link TouchDelegateInfo#getTargetForRegion(Region)} for {@link AccessibilityNodeInfo} from
+ * the given region.
+ *
+ * @return {@link TouchDelegateInfo} or {@code null} if there are no touch delegates.
+ */
+ @Nullable
+ public TouchDelegateInfo getTouchDelegateInfo() {
+ if (mTouchDelegateInfo != null) {
+ mTouchDelegateInfo.setConnectionId(mConnectionId);
+ mTouchDelegateInfo.setWindowId(mWindowId);
+ }
+ return mTouchDelegateInfo;
+ }
+
+ /**
+ * Set touch delegate info if the represented view has a {@link TouchDelegate}.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an
+ * AccessibilityService.
+ * </p>
+ *
+ * @param delegatedInfo {@link TouchDelegateInfo} returned from
+ * {@link TouchDelegate#getTouchDelegateInfo()}.
+ *
+ * @throws IllegalStateException If called from an AccessibilityService.
+ */
+ public void setTouchDelegateInfo(@NonNull TouchDelegateInfo delegatedInfo) {
+ enforceNotSealed();
+ mTouchDelegateInfo = delegatedInfo;
+ }
+
+ /**
* Gets the value of a boolean property.
*
* @param property The property.
@@ -3340,6 +3385,10 @@
if (!Objects.equals(mCollectionItemInfo, DEFAULT.mCollectionItemInfo)) {
nonDefaultFields |= bitAt(fieldIndex);
}
+ fieldIndex++;
+ if (!Objects.equals(mTouchDelegateInfo, DEFAULT.mTouchDelegateInfo)) {
+ nonDefaultFields |= bitAt(fieldIndex);
+ }
int totalFields = fieldIndex;
parcel.writeLong(nonDefaultFields);
@@ -3462,6 +3511,10 @@
parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0);
}
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ mTouchDelegateInfo.writeToParcel(parcel, flags);
+ }
+
if (DEBUG) {
fieldIndex--;
if (totalFields != fieldIndex) {
@@ -3543,6 +3596,10 @@
if (mCollectionItemInfo != null) mCollectionItemInfo.recycle();
mCollectionItemInfo = (other.mCollectionItemInfo != null)
? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null;
+
+ final TouchDelegateInfo otherInfo = other.mTouchDelegateInfo;
+ mTouchDelegateInfo = (otherInfo != null)
+ ? new TouchDelegateInfo(otherInfo.mTargetMap, true) : null;
}
/**
@@ -3665,6 +3722,10 @@
parcel.readInt() == 1)
: null;
+ if (isBitSet(nonDefaultFields, fieldIndex++)) {
+ mTouchDelegateInfo = TouchDelegateInfo.CREATOR.createFromParcel(parcel);
+ }
+
mSealed = sealed;
}
@@ -3813,10 +3874,11 @@
}
}
- private boolean canPerformRequestOverConnection(long accessibilityNodeId) {
- return ((mWindowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
+ private static boolean canPerformRequestOverConnection(int connectionId,
+ int windowId, long accessibilityNodeId) {
+ return ((windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
&& (getAccessibilityViewId(accessibilityNodeId) != UNDEFINED_ITEM_ID)
- && (mConnectionId != UNDEFINED_CONNECTION_ID));
+ && (connectionId != UNDEFINED_CONNECTION_ID));
}
@Override
@@ -3919,13 +3981,14 @@
return builder.toString();
}
- private AccessibilityNodeInfo getNodeForAccessibilityId(long accessibilityId) {
- if (!canPerformRequestOverConnection(accessibilityId)) {
+ private static AccessibilityNodeInfo getNodeForAccessibilityId(int connectionId,
+ int windowId, long accessibilityId) {
+ if (!canPerformRequestOverConnection(connectionId, windowId, accessibilityId)) {
return null;
}
AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId,
- mWindowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
+ return client.findAccessibilityNodeInfoByAccessibilityId(connectionId,
+ windowId, accessibilityId, false, FLAG_PREFETCH_PREDECESSORS
| FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null);
}
@@ -4896,6 +4959,176 @@
}
/**
+ * Class with information of touch delegated views and regions from {@link TouchDelegate} for
+ * the {@link AccessibilityNodeInfo}.
+ *
+ * @see AccessibilityNodeInfo#setTouchDelegateInfo(TouchDelegateInfo)
+ */
+ public static final class TouchDelegateInfo implements Parcelable {
+ private ArrayMap<Region, Long> mTargetMap;
+ // Two ids are initialized lazily in AccessibilityNodeInfo#getTouchDelegateInfo
+ private int mConnectionId;
+ private int mWindowId;
+
+ /**
+ * Create a new instance of {@link TouchDelegateInfo}.
+ *
+ * @param targetMap A map from regions (in view coordinates) to delegated views.
+ * @throws IllegalArgumentException if targetMap is empty or {@code null} in
+ * Regions or Views.
+ */
+ public TouchDelegateInfo(@NonNull Map<Region, View> targetMap) {
+ Preconditions.checkArgument(!targetMap.isEmpty()
+ && !targetMap.containsKey(null) && !targetMap.containsValue(null));
+ mTargetMap = new ArrayMap<>(targetMap.size());
+ for (final Region region : targetMap.keySet()) {
+ final View view = targetMap.get(region);
+ mTargetMap.put(region, (long) view.getAccessibilityViewId());
+ }
+ }
+
+ /**
+ * Create a new instance from target map.
+ *
+ * @param targetMap A map from regions (in view coordinates) to delegated views'
+ * accessibility id.
+ * @param doCopy True if shallow copy targetMap.
+ * @throws IllegalArgumentException if targetMap is empty or {@code null} in
+ * Regions or Views.
+ */
+ TouchDelegateInfo(@NonNull ArrayMap<Region, Long> targetMap, boolean doCopy) {
+ Preconditions.checkArgument(!targetMap.isEmpty()
+ && !targetMap.containsKey(null) && !targetMap.containsValue(null));
+ if (doCopy) {
+ mTargetMap = new ArrayMap<>(targetMap.size());
+ mTargetMap.putAll(targetMap);
+ } else {
+ mTargetMap = targetMap;
+ }
+ }
+
+ /**
+ * Set the connection ID.
+ *
+ * @param connectionId The connection id.
+ */
+ private void setConnectionId(int connectionId) {
+ mConnectionId = connectionId;
+ }
+
+ /**
+ * Set the window ID.
+ *
+ * @param windowId The window id.
+ */
+ private void setWindowId(int windowId) {
+ mWindowId = windowId;
+ }
+
+ /**
+ * Returns the number of touch delegate target region.
+ *
+ * @return Number of touch delegate target region.
+ */
+ public int getRegionCount() {
+ return mTargetMap.size();
+ }
+
+ /**
+ * Return the {@link Region} at the given index in the {@link TouchDelegateInfo}.
+ *
+ * @param index The desired index, must be between 0 and {@link #getRegionCount()}-1.
+ * @return Returns the {@link Region} stored at the given index.
+ */
+ @NonNull
+ public Region getRegionAt(int index) {
+ return mTargetMap.keyAt(index);
+ }
+
+ /**
+ * Return the target {@link AccessibilityNodeInfo} for the given {@link Region}.
+ * <p>
+ * <strong>Note:</strong> This api can only be called from {@link AccessibilityService}.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> It is a client responsibility to recycle the
+ * received info by calling {@link AccessibilityNodeInfo#recycle()}
+ * to avoid creating of multiple instances.
+ * </p>
+ *
+ * @param region The region retrieved from {@link #getRegionAt(int)}.
+ * @return The target node associates with the given region.
+ */
+ @Nullable
+ public AccessibilityNodeInfo getTargetForRegion(@NonNull Region region) {
+ return getNodeForAccessibilityId(mConnectionId, mWindowId, mTargetMap.get(region));
+ }
+
+ /**
+ * Return the accessibility id of target node.
+ *
+ * @param region The region retrieved from {@link #getRegionAt(int)}.
+ * @return The accessibility id of target node.
+ *
+ * @hide
+ */
+ @TestApi
+ public long getAccessibilityIdForRegion(@NonNull Region region) {
+ return mTargetMap.get(region);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mTargetMap.size());
+ for (int i = 0; i < mTargetMap.size(); i++) {
+ final Region region = mTargetMap.keyAt(i);
+ final Long accessibilityId = mTargetMap.valueAt(i);
+ region.writeToParcel(dest, flags);
+ dest.writeLong(accessibilityId);
+ }
+ }
+
+ /**
+ * @see android.os.Parcelable.Creator
+ */
+ public static final Parcelable.Creator<TouchDelegateInfo> CREATOR =
+ new Parcelable.Creator<TouchDelegateInfo>() {
+ @Override
+ public TouchDelegateInfo createFromParcel(Parcel parcel) {
+ final int size = parcel.readInt();
+ if (size == 0) {
+ return null;
+ }
+ final ArrayMap<Region, Long> targetMap = new ArrayMap<>(size);
+ for (int i = 0; i < size; i++) {
+ final Region region = Region.CREATOR.createFromParcel(parcel);
+ final long accessibilityId = parcel.readLong();
+ targetMap.put(region, accessibilityId);
+ }
+ final TouchDelegateInfo touchDelegateInfo = new TouchDelegateInfo(
+ targetMap, false);
+ return touchDelegateInfo;
+ }
+
+ @Override
+ public TouchDelegateInfo[] newArray(int size) {
+ return new TouchDelegateInfo[size];
+ }
+ };
+ }
+
+ /**
* @see android.os.Parcelable.Creator
*/
public static final Parcelable.Creator<AccessibilityNodeInfo> CREATOR =
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 08ed9d1..ca2ccaf 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -48,7 +48,6 @@
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.SparseArray;
-import android.view.Display;
import android.view.InputChannel;
import android.view.InputEvent;
import android.view.InputEventSender;
@@ -266,7 +265,7 @@
* @hide
*/
public static void ensureDefaultInstanceForDefaultDisplayIfNecessary() {
- forContextInternal(Display.DEFAULT_DISPLAY, Looper.getMainLooper());
+ getInstanceInternal();
}
private static final Object sLock = new Object();
@@ -280,17 +279,6 @@
static InputMethodManager sInstance;
/**
- * Global map between display to {@link InputMethodManager}.
- *
- * <p>Currently this map works like a so-called leaky singleton. Once an instance is registered
- * for the associated display ID, that instance will never be garbage collected.</p>
- *
- * <p>TODO(Bug 116699479): Implement instance clean up mechanism.</p>
- */
- @GuardedBy("sLock")
- private static final SparseArray<InputMethodManager> sInstanceMap = new SparseArray<>();
-
- /**
* @hide Flag for IInputMethodManager.windowGainedFocus: a view in
* the window has input focus.
*/
@@ -347,8 +335,6 @@
// Our generic input connection if the current target does not have its own.
final IInputContext mIInputContext;
- private final int mDisplayId;
-
/**
* True if this input method client is active, initially false.
*/
@@ -466,29 +452,6 @@
return afm != null && afm.isAutofillUiShowing();
}
- /**
- * Checks the consistency between {@link InputMethodManager} state and {@link View} state.
- *
- * @param view {@link View} to be checked
- * @return {@code true} if {@code view} is not {@code null} and there is a {@link Context}
- * mismatch between {@link InputMethodManager} and {@code view}
- */
- private boolean shouldDispatchToViewContext(@Nullable View view) {
- if (view == null) {
- return false;
- }
- final int viewDisplayId = getDisplayId(view.getContext());
- if (viewDisplayId != mDisplayId) {
- Log.w(TAG, "b/117267690: Context mismatch found. view=" + view + " belongs to"
- + " displayId=" + viewDisplayId
- + " but InputMethodManager belongs to displayId=" + mDisplayId
- + ". Use the right InputMethodManager instance to avoid performance overhead.",
- new Throwable());
- return true;
- }
- return false;
- }
-
private static boolean canStartInput(View servedView) {
// We can start input ether the servedView has window focus
// or the activity is showing autofill ui.
@@ -770,57 +733,33 @@
});
}
- InputMethodManager(int displayId, Looper looper) throws ServiceNotFoundException {
+ InputMethodManager(Looper looper) throws ServiceNotFoundException {
mService = getIInputMethodManager();
mMainLooper = looper;
mH = new H(looper);
- mDisplayId = displayId;
mIInputContext = new ControlledInputConnectionWrapper(looper,
mDummyInputConnection, this);
}
- private static int getDisplayId(Context context) {
- final Display display = context.getDisplay();
- return display != null ? display.getDisplayId() : Display.DEFAULT_DISPLAY;
- }
-
/**
- * Retrieve an instance for the given {@link Context}, creating it if it doesn't already exist.
+ * Retrieve the global {@link InputMethodManager} instance, creating it if it doesn't already
+ * exist.
*
- * @param context {@link Context} for which IME APIs need to work
- * @return {@link InputMethodManager} instance
+ * @return global {@link InputMethodManager} instance
* @hide
*/
- @Nullable
- public static InputMethodManager forContext(Context context) {
- final int displayId = getDisplayId(context);
- // For better backward compatibility, we always use Looper.getMainLooper() for the default
- // display case.
- final Looper looper = displayId == Display.DEFAULT_DISPLAY
- ? Looper.getMainLooper() : context.getMainLooper();
- return forContextInternal(displayId, looper);
- }
-
- @Nullable
- private static InputMethodManager forContextInternal(int displayId, Looper looper) {
- final boolean isDefaultDisplay = displayId == Display.DEFAULT_DISPLAY;
+ public static InputMethodManager getInstanceInternal() {
synchronized (sLock) {
- InputMethodManager instance = sInstanceMap.get(displayId);
- if (instance != null) {
- return instance;
+ if (sInstance == null) {
+ try {
+ final InputMethodManager imm = new InputMethodManager(Looper.getMainLooper());
+ imm.mService.addClient(imm.mClient, imm.mIInputContext);
+ sInstance = imm;
+ } catch (ServiceNotFoundException | RemoteException e) {
+ throw new IllegalStateException(e);
+ }
}
- try {
- instance = new InputMethodManager(displayId, looper);
- instance.mService.addClient(instance.mClient, instance.mIInputContext, displayId);
- } catch (ServiceNotFoundException | RemoteException e) {
- throw new IllegalStateException(e);
- }
- // For backward compatibility, store the instance also to sInstance for default display.
- if (sInstance == null && isDefaultDisplay) {
- sInstance = instance;
- }
- sInstanceMap.put(displayId, instance);
- return instance;
+ return sInstance;
}
}
@@ -977,11 +916,6 @@
* input method.
*/
public boolean isActive(View view) {
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(view)) {
- return view.getContext().getSystemService(InputMethodManager.class).isActive(view);
- }
-
checkFocus();
synchronized (mH) {
return (mServedView == view
@@ -1072,13 +1006,6 @@
}
public void displayCompletions(View view, CompletionInfo[] completions) {
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(view)) {
- view.getContext().getSystemService(InputMethodManager.class)
- .displayCompletions(view, completions);
- return;
- }
-
checkFocus();
synchronized (mH) {
if (mServedView != view && (mServedView == null
@@ -1097,13 +1024,6 @@
}
public void updateExtractedText(View view, int token, ExtractedText text) {
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(view)) {
- view.getContext().getSystemService(InputMethodManager.class)
- .updateExtractedText(view, token, text);
- return;
- }
-
checkFocus();
synchronized (mH) {
if (mServedView != view && (mServedView == null
@@ -1145,12 +1065,6 @@
* 0 or have the {@link #SHOW_IMPLICIT} bit set.
*/
public boolean showSoftInput(View view, int flags) {
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(view)) {
- return view.getContext().getSystemService(InputMethodManager.class)
- .showSoftInput(view, flags);
- }
-
return showSoftInput(view, flags, null);
}
@@ -1213,12 +1127,6 @@
* {@link #RESULT_HIDDEN}.
*/
public boolean showSoftInput(View view, int flags, ResultReceiver resultReceiver) {
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(view)) {
- return view.getContext().getSystemService(InputMethodManager.class)
- .showSoftInput(view, flags, resultReceiver);
- }
-
checkFocus();
synchronized (mH) {
if (mServedView != view && (mServedView == null
@@ -1382,12 +1290,6 @@
* @param view The view whose text has changed.
*/
public void restartInput(View view) {
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(view)) {
- view.getContext().getSystemService(InputMethodManager.class).restartInput(view);
- return;
- }
-
checkFocus();
synchronized (mH) {
if (mServedView != view && (mServedView == null
@@ -1812,13 +1714,6 @@
*/
public void updateSelection(View view, int selStart, int selEnd,
int candidatesStart, int candidatesEnd) {
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(view)) {
- view.getContext().getSystemService(InputMethodManager.class)
- .updateSelection(view, selStart, selEnd, candidatesStart, candidatesEnd);
- return;
- }
-
checkFocus();
synchronized (mH) {
if ((mServedView != view && (mServedView == null
@@ -1856,12 +1751,6 @@
* Notify the event when the user tapped or clicked the text view.
*/
public void viewClicked(View view) {
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(view)) {
- view.getContext().getSystemService(InputMethodManager.class).viewClicked(view);
- return;
- }
-
final boolean focusChanged = mServedView != mNextServedView;
checkFocus();
synchronized (mH) {
@@ -1926,13 +1815,6 @@
*/
@Deprecated
public void updateCursor(View view, int left, int top, int right, int bottom) {
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(view)) {
- view.getContext().getSystemService(InputMethodManager.class)
- .updateCursor(view, left, top, right, bottom);
- return;
- }
-
checkFocus();
synchronized (mH) {
if ((mServedView != view && (mServedView == null
@@ -1964,13 +1846,6 @@
if (view == null || cursorAnchorInfo == null) {
return;
}
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(view)) {
- view.getContext().getSystemService(InputMethodManager.class)
- .updateCursorAnchorInfo(view, cursorAnchorInfo);
- return;
- }
-
checkFocus();
synchronized (mH) {
if ((mServedView != view &&
@@ -2016,13 +1891,6 @@
* @param data Any data to include with the command.
*/
public void sendAppPrivateCommand(View view, String action, Bundle data) {
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(view)) {
- view.getContext().getSystemService(InputMethodManager.class)
- .sendAppPrivateCommand(view, action, data);
- return;
- }
-
checkFocus();
synchronized (mH) {
if ((mServedView != view && (mServedView == null
@@ -2194,13 +2062,6 @@
*/
public void dispatchKeyEventFromInputMethod(@Nullable View targetView,
@NonNull KeyEvent event) {
- // Re-dispatch if there is a context mismatch.
- if (shouldDispatchToViewContext(targetView)) {
- targetView.getContext().getSystemService(InputMethodManager.class)
- .dispatchKeyEventFromInputMethod(targetView, event);
- return;
- }
-
synchronized (mH) {
ViewRootImpl viewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
if (viewRootImpl == null) {
@@ -2690,7 +2551,6 @@
sb.append(",windowFocus=" + view.hasWindowFocus());
sb.append(",autofillUiShowing=" + isAutofillUIShowing(view));
sb.append(",window=" + view.getWindowToken());
- sb.append(",displayId=" + getDisplayId(view.getContext()));
sb.append(",temporaryDetach=" + view.isTemporarilyDetached());
return sb.toString();
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9d06680..f74c234 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3521,7 +3521,7 @@
Typeface mFontTypeface = null;
boolean mFontFamilyExplicit = false;
int mTypefaceIndex = -1;
- int mStyleIndex = -1;
+ int mTextStyle = 0;
int mFontWeight = -1;
boolean mAllCaps = false;
int mShadowColor = 0;
@@ -3547,7 +3547,7 @@
+ " mFontTypeface:" + mFontTypeface + "\n"
+ " mFontFamilyExplicit:" + mFontFamilyExplicit + "\n"
+ " mTypefaceIndex:" + mTypefaceIndex + "\n"
- + " mStyleIndex:" + mStyleIndex + "\n"
+ + " mTextStyle:" + mTextStyle + "\n"
+ " mFontWeight:" + mFontWeight + "\n"
+ " mAllCaps:" + mAllCaps + "\n"
+ " mShadowColor:" + mShadowColor + "\n"
@@ -3672,7 +3672,7 @@
attributes.mFontFamilyExplicit = true;
break;
case com.android.internal.R.styleable.TextAppearance_textStyle:
- attributes.mStyleIndex = appearance.getInt(attr, attributes.mStyleIndex);
+ attributes.mTextStyle = appearance.getInt(attr, attributes.mTextStyle);
break;
case com.android.internal.R.styleable.TextAppearance_textFontWeight:
attributes.mFontWeight = appearance.getInt(attr, attributes.mFontWeight);
@@ -3742,7 +3742,7 @@
attributes.mFontFamily = null;
}
setTypefaceFromAttrs(attributes.mFontTypeface, attributes.mFontFamily,
- attributes.mTypefaceIndex, attributes.mStyleIndex, attributes.mFontWeight);
+ attributes.mTypefaceIndex, attributes.mTextStyle, attributes.mFontWeight);
if (attributes.mShadowColor != 0) {
setShadowLayer(attributes.mShadowRadius, attributes.mShadowDx, attributes.mShadowDy,
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 33b9ff7..017da55 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5330,6 +5330,7 @@
if (DEBUG_HISTORY) Slog.v(TAG, "Phone started scanning to: "
+ Integer.toHexString(mHistoryCur.states));
mPhoneSignalScanningTimer.startRunningLocked(elapsedRealtime);
+ StatsLog.write(StatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin);
}
}
@@ -5341,6 +5342,7 @@
+ Integer.toHexString(mHistoryCur.states));
newHistory = true;
mPhoneSignalScanningTimer.stopRunningLocked(elapsedRealtime);
+ StatsLog.write(StatsLog.PHONE_SERVICE_STATE_CHANGED, state, simState, strengthBin);
}
}
diff --git a/core/java/com/android/internal/os/LooperStats.java b/core/java/com/android/internal/os/LooperStats.java
index e4724ff..8dc97fe 100644
--- a/core/java/com/android/internal/os/LooperStats.java
+++ b/core/java/com/android/internal/os/LooperStats.java
@@ -66,6 +66,7 @@
session = session == null ? new DispatchSession() : session;
session.startTimeMicro = getElapsedRealtimeMicro();
session.cpuStartMicro = getThreadTimeMicro();
+ session.systemUptimeMillis = getSystemUptimeMillis();
return session;
}
@@ -85,12 +86,18 @@
entry.messageCount++;
if (session != DispatchSession.NOT_SAMPLED) {
entry.recordedMessageCount++;
- long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
- long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
+ final long latency = getElapsedRealtimeMicro() - session.startTimeMicro;
+ final long cpuUsage = getThreadTimeMicro() - session.cpuStartMicro;
entry.totalLatencyMicro += latency;
entry.maxLatencyMicro = Math.max(entry.maxLatencyMicro, latency);
entry.cpuUsageMicro += cpuUsage;
entry.maxCpuUsageMicro = Math.max(entry.maxCpuUsageMicro, cpuUsage);
+ if (msg.getWhen() > 0) {
+ final long delay = Math.max(0L, session.systemUptimeMillis - msg.getWhen());
+ entry.delayMillis += delay;
+ entry.maxDelayMillis = Math.max(entry.maxDelayMillis, delay);
+ entry.recordedDelayMessageCount++;
+ }
}
}
}
@@ -206,6 +213,10 @@
return SystemClock.elapsedRealtimeNanos() / 1000;
}
+ protected long getSystemUptimeMillis() {
+ return SystemClock.uptimeMillis();
+ }
+
protected boolean shouldCollectDetailedData() {
return ThreadLocalRandom.current().nextInt() % mSamplingInterval == 0;
}
@@ -214,6 +225,7 @@
static final DispatchSession NOT_SAMPLED = new DispatchSession();
public long startTimeMicro;
public long cpuStartMicro;
+ public long systemUptimeMillis;
}
private static class Entry {
@@ -228,6 +240,9 @@
public long maxLatencyMicro;
public long cpuUsageMicro;
public long maxCpuUsageMicro;
+ public long recordedDelayMessageCount;
+ public long delayMillis;
+ public long maxDelayMillis;
Entry(Message msg, boolean isInteractive) {
this.workSourceUid = msg.workSourceUid;
@@ -251,6 +266,9 @@
maxLatencyMicro = 0;
cpuUsageMicro = 0;
maxCpuUsageMicro = 0;
+ delayMillis = 0;
+ maxDelayMillis = 0;
+ recordedDelayMessageCount = 0;
}
static int idFor(Message msg, boolean isInteractive) {
@@ -281,6 +299,9 @@
public final long maxLatencyMicros;
public final long cpuUsageMicros;
public final long maxCpuUsageMicros;
+ public final long maxDelayMillis;
+ public final long delayMillis;
+ public final long recordedDelayMessageCount;
ExportedEntry(Entry entry) {
this.workSourceUid = entry.workSourceUid;
@@ -301,6 +322,9 @@
this.maxLatencyMicros = entry.maxLatencyMicro;
this.cpuUsageMicros = entry.cpuUsageMicro;
this.maxCpuUsageMicros = entry.maxCpuUsageMicro;
+ this.delayMillis = entry.delayMillis;
+ this.maxDelayMillis = entry.maxDelayMillis;
+ this.recordedDelayMessageCount = entry.recordedDelayMessageCount;
}
}
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index dceacda..5f1243f 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -31,8 +31,7 @@
* applications.
*/
interface IInputMethodManager {
- void addClient(in IInputMethodClient client, in IInputContext inputContext,
- int untrustedDisplayId);
+ void addClient(in IInputMethodClient client, in IInputContext inputContext);
// TODO: Use ParceledListSlice instead
List<InputMethodInfo> getInputMethodList();
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index ec8e8da..101fd41 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -51,9 +51,6 @@
ResultCode.ERROR_INVALID_USER,
ResultCode.ERROR_NULL_EDITOR_INFO,
ResultCode.ERROR_NOT_IME_TARGET_WINDOW,
- ResultCode.ERROR_NO_EDITOR,
- ResultCode.ERROR_DISPLAY_ID_MISMATCH,
- ResultCode.ERROR_INVALID_DISPLAY_ID,
})
public @interface ResultCode {
/**
@@ -142,22 +139,13 @@
* The client should try to restart input when its {@link android.view.Window} is focused
* again.</p>
*
- * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int, int)
+ * @see com.android.server.wm.WindowManagerInternal#isInputMethodClientFocus(int, int)
*/
int ERROR_NOT_IME_TARGET_WINDOW = 11;
/**
* Indicates that focused view in the current window is not an editor.
*/
int ERROR_NO_EDITOR = 12;
- /**
- * Indicates that there is a mismatch in display ID between IME client and focused Window.
- */
- int ERROR_DISPLAY_ID_MISMATCH = 13;
- /**
- * Indicates that current IME client is no longer allowed to access to the associated
- * display.
- */
- int ERROR_INVALID_DISPLAY_ID = 14;
}
@ResultCode
@@ -283,10 +271,6 @@
return "ERROR_NULL_EDITOR_INFO";
case ResultCode.ERROR_NOT_IME_TARGET_WINDOW:
return "ERROR_NOT_IME_TARGET_WINDOW";
- case ResultCode.ERROR_DISPLAY_ID_MISMATCH:
- return "ERROR_DISPLAY_ID_MISMATCH";
- case ResultCode.ERROR_INVALID_DISPLAY_ID:
- return "ERROR_INVALID_DISPLAY_ID";
default:
return "Unknown(" + result + ")";
}
@@ -332,15 +316,4 @@
*/
public static final InputBindResult INVALID_USER = error(ResultCode.ERROR_INVALID_USER);
- /**
- * Predefined error object for {@link ResultCode#ERROR_DISPLAY_ID_MISMATCH}.
- */
- public static final InputBindResult DISPLAY_ID_MISMATCH =
- error(ResultCode.ERROR_DISPLAY_ID_MISMATCH);
-
- /**
- * Predefined error object for {@link ResultCode#ERROR_INVALID_DISPLAY_ID}.
- */
- public static final InputBindResult INVALID_DISPLAY_ID =
- error(ResultCode.ERROR_INVALID_DISPLAY_ID);
}
diff --git a/core/java/com/android/internal/widget/AlertDialogLayout.java b/core/java/com/android/internal/widget/AlertDialogLayout.java
index 9bf0948..7a01749 100644
--- a/core/java/com/android/internal/widget/AlertDialogLayout.java
+++ b/core/java/com/android/internal/widget/AlertDialogLayout.java
@@ -18,6 +18,7 @@
import android.annotation.AttrRes;
import android.annotation.Nullable;
+import android.annotation.UnsupportedAppUsage;
import android.annotation.StyleRes;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -50,6 +51,7 @@
super(context);
}
+ @UnsupportedAppUsage
public AlertDialogLayout(@Nullable Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
index ab8be33..0ca6743 100644
--- a/core/java/com/android/internal/widget/ButtonBarLayout.java
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -16,6 +16,7 @@
package com.android.internal.widget;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
@@ -40,6 +41,7 @@
private int mMinimumHeight = 0;
+ @UnsupportedAppUsage
public ButtonBarLayout(Context context, AttributeSet attrs) {
super(context, attrs);
diff --git a/core/java/com/android/internal/widget/DialogTitle.java b/core/java/com/android/internal/widget/DialogTitle.java
index 7ea3d6b..405436c 100644
--- a/core/java/com/android/internal/widget/DialogTitle.java
+++ b/core/java/com/android/internal/widget/DialogTitle.java
@@ -16,6 +16,7 @@
package com.android.internal.widget;
+import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Layout;
@@ -37,6 +38,7 @@
super(context, attrs, defStyleAttr);
}
+ @UnsupportedAppUsage
public DialogTitle(Context context, AttributeSet attrs) {
super(context, attrs);
}
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 0a787b9..d68e8f8 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -331,13 +331,11 @@
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
- // Allow Product to customize system configs around libs, features, permissions and apps
- int productPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PERMISSIONS |
- ALLOW_APP_CONFIGS | ALLOW_PRIVAPP_PERMISSIONS;
+ // Allow Product to customize all system configs
readPermissions(Environment.buildPath(
- Environment.getProductDirectory(), "etc", "sysconfig"), productPermissionFlag);
+ Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);
readPermissions(Environment.buildPath(
- Environment.getProductDirectory(), "etc", "permissions"), productPermissionFlag);
+ Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);
// Allow /product_services to customize system configs around libs, features, permissions
// and apps.
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 92235ad..b70485d 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -23,10 +23,6 @@
namespace {
-int getCanLoadSystemLibraries_native() {
- return android::GraphicsEnv::getInstance().getCanLoadSystemLibraries();
-}
-
void setDriverPath(JNIEnv* env, jobject clazz, jstring path) {
ScopedUtfChars pathChars(env, path);
android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());
@@ -55,7 +51,6 @@
}
const JNINativeMethod g_methods[] = {
- { "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
{ "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
{ "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V", reinterpret_cast<void*>(setAngleInfo_native) },
{ "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 47dbc07..a02602e 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -397,10 +397,9 @@
// Ordered GPU debug layer list
// i.e. <layer1>:<layer2>:...:<layerN>
optional SettingProto debug_layers = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+
// App will load ANGLE instead of native GLES drivers.
optional SettingProto angle_enabled_app = 3;
- // App that can provide layer libraries.
- optional SettingProto debug_layer_app = 4;
}
optional Gpu gpu = 59;
diff --git a/proto/src/stats_enums.proto b/core/proto/android/stats/enums.proto
similarity index 91%
rename from proto/src/stats_enums.proto
rename to core/proto/android/stats/enums.proto
index 6c892cf..2320a01 100644
--- a/proto/src/stats_enums.proto
+++ b/core/proto/android/stats/enums.proto
@@ -16,8 +16,7 @@
syntax = "proto2";
-package android.os.statsd;
-option java_package = "com.android.os";
+package android.stats;
option java_outer_classname = "StatsEnums";
enum EventType {
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
index 32975a5..fba2e51 100644
--- a/core/proto/android/telephony/enums.proto
+++ b/core/proto/android/telephony/enums.proto
@@ -61,3 +61,64 @@
SIGNAL_STRENGTH_GOOD = 3;
SIGNAL_STRENGTH_GREAT = 4;
}
+
+
+enum ServiceStateEnum {
+ /**
+ * Normal operation condition, the phone is registered
+ * with an operator either in home network or in roaming.
+ */
+ SERVICE_STATE_IN_SERVICE = 0;
+
+ /**
+ * Phone is not registered with any operator, the phone
+ * can be currently searching a new operator to register to, or not
+ * searching to registration at all, or registration is denied, or radio
+ * signal is not available.
+ */
+ SERVICE_STATE_OUT_OF_SERVICE = 1;
+
+ /**
+ * The phone is registered and locked. Only emergency numbers are allowed. {@more}
+ */
+ SERVICE_STATE_EMERGENCY_ONLY = 2;
+
+ /**
+ * Radio of telephony is explicitly powered off.
+ */
+ SERVICE_STATE_POWER_OFF = 3;
+}
+
+enum SimStateEnum {
+ SIM_STATE_UNKNOWN = 0;
+ /** SIM card state: no SIM card is available in the device */
+ SIM_STATE_ABSENT = 1;
+ /** SIM card state: Locked: requires the user's SIM PIN to unlock */
+ SIM_STATE_PIN_REQUIRED = 2;
+ /** SIM card state: Locked: requires the user's SIM PUK to unlock */
+ SIM_STATE_PUK_REQUIRED = 3;
+ /** SIM card state: Locked: requires a network PIN to unlock */
+ SIM_STATE_NETWORK_LOCKED = 4;
+ /** SIM card state: Ready */
+ SIM_STATE_READY = 5;
+ /** SIM card state: SIM Card is NOT READY */
+ SIM_STATE_NOT_READY = 6;
+ /** SIM card state: SIM Card Error, permanently disabled */
+ SIM_STATE_PERM_DISABLED = 7;
+ /** SIM card state: SIM Card Error, present but faulty */
+ SIM_STATE_CARD_IO_ERROR = 8;
+ /** SIM card state: SIM Card restricted, present but not usable due to
+ * carrier restrictions.
+ */
+ SIM_STATE_CARD_RESTRICTED = 9;
+ /**
+ * SIM card state: Loaded: SIM card applications have been loaded
+ * @hide
+ */
+ SIM_STATE_LOADED = 10;
+ /**
+ * SIM card state: SIM Card is present
+ * @hide
+ */
+ SIM_STATE_PRESENT = 11;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f3f012d..401ffa3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -138,7 +138,6 @@
<protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
<protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
- <protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" />
<protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<protected-broadcast android:name="android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED" />
@@ -1546,6 +1545,7 @@
<!-- Allows SetupWizard to call methods in Networking services
<p>Not for use by any other third-party or privileged applications.
+ @SystemApi
@hide This should only be used by SetupWizard.
-->
<permission android:name="android.permission.NETWORK_SETUP_WIZARD"
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index fb78b3b..7b3d940 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -109,12 +109,12 @@
<!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements,
visual voicemail code for Orange: 21101 -->
- <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101|20366" />
+ <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101|20366|555|2051" />
<!-- United Kingdom (Great Britain): 4-6 digits, common codes [5-8]xxxx, plus EU:
http://www.short-codes.com/media/Co-regulatoryCodeofPracticeforcommonshortcodes170206.pdf,
visual voicemail code for EE: 887 -->
- <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|2020|35890|61002|61202|887|83669|34664|40406|60174|7726|37726" />
+ <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|2020|35890|61002|61202|887|83669|34664|40406|60174|7726|37726|88555|9017|9018" />
<!-- Georgia: 4 digits, known premium codes listed -->
<shortcode country="ge" pattern="\\d{4}" premium="801[234]|888[239]" />
@@ -189,11 +189,14 @@
<!-- The Netherlands, 4 digits, known premium codes listed, plus EU -->
<shortcode country="nl" pattern="\\d{4}" premium="4466|5040" free="116\\d{3}|2223|6225|2223" />
+ <!-- Nigeria -->
+ <shortcode country="ng" pattern="\\d{1,5}" free="2441" />
+
<!-- Norway: 4-5 digits (not confirmed), known premium codes listed -->
<shortcode country="no" pattern="\\d{4,5}" premium="2201|222[67]" free="2171" />
<!-- New Zealand: 3-4 digits, known premium codes listed -->
- <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="3067|3068|4053" />
+ <shortcode country="nz" pattern="\\d{3,4}" premium="3903|8995|4679" free="1737|2141|3067|3068|3110|4006|4053|4061|4062|4202|4300|4334|4412|4575|5626|8006|8681" />
<!-- Peru: 4-5 digits (not confirmed), known premium codes listed -->
<shortcode country="pe" pattern="\\d{4,5}" free="9963" />
@@ -209,7 +212,7 @@
<!-- Portugal: 5 digits, plus EU:
http://clients.txtnation.com/entries/158326-portugal-premium-sms-short-code-regulations -->
- <shortcode country="pt" premium="6[1289]\\d{3}" free="116\\d{3}|1262" />
+ <shortcode country="pt" premium="6[1289]\\d{3}" free="116\\d{3}|1262|12666" />
<!-- Qatar: 1-5 digits (standard system default, not country specific) -->
<shortcode country="qa" pattern="\\d{1,5}" free="92451" />
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index e0d5393..307e2e8 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -67,10 +67,6 @@
# Disable AAPT2 because the hacks below depend on the AAPT rules implementation
LOCAL_USE_AAPT2 := false
-# When AAPT2 is enabled it will need --warn-manifest-validation to fix:
-# frameworks/base/core/tests/coretests/AndroidManifest.xml:26: error: unknown element <meta-data> found.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-# LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
# Rules to copy all the test apks to the intermediate raw resource directory
diff --git a/core/tests/coretests/apks/install_multi_package/Android.mk b/core/tests/coretests/apks/install_multi_package/Android.mk
index 9727593..3f163de 100644
--- a/core/tests/coretests/apks/install_multi_package/Android.mk
+++ b/core/tests/coretests/apks/install_multi_package/Android.mk
@@ -8,10 +8,6 @@
LOCAL_PACKAGE_NAME := install_multi_package
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml:46: error: unexpected element <package> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(FrameworkCoreTests_BUILD_PACKAGE)
#include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_bad/Android.mk b/core/tests/coretests/apks/install_verifier_bad/Android.mk
index 679327c..745b4d3 100644
--- a/core/tests/coretests/apks/install_verifier_bad/Android.mk
+++ b/core/tests/coretests/apks/install_verifier_bad/Android.mk
@@ -6,9 +6,5 @@
LOCAL_PACKAGE_NAME := install_verifier_bad
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_verifier_bad/AndroidManifest.xml:19: error: unexpected element <package-verifier> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_verifier_good/Android.mk b/core/tests/coretests/apks/install_verifier_good/Android.mk
index 7d621b3..150fd8d 100644
--- a/core/tests/coretests/apks/install_verifier_good/Android.mk
+++ b/core/tests/coretests/apks/install_verifier_good/Android.mk
@@ -6,9 +6,5 @@
LOCAL_PACKAGE_NAME := install_verifier_good
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/core/tests/coretests/apks/install_verifier_good/AndroidManifest.xml:19: error: unexpected element <package-verifier> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
index 584257b..e248a77 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -45,7 +45,7 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
-import libcore.io.IoUtils;
+import libcore.testing.io.TestIoUtils;
import org.junit.After;
import org.junit.Assert;
@@ -63,7 +63,7 @@
@Before
public void setUp() {
- mTmpDir = IoUtils.createTemporaryDirectory("DexMetadataHelperTest");
+ mTmpDir = TestIoUtils.createTemporaryDirectory("DexMetadataHelperTest");
}
@After
diff --git a/core/tests/coretests/src/android/os/FileUtilsTest.java b/core/tests/coretests/src/android/os/FileUtilsTest.java
index 20fe162..80281b6 100644
--- a/core/tests/coretests/src/android/os/FileUtilsTest.java
+++ b/core/tests/coretests/src/android/os/FileUtilsTest.java
@@ -48,7 +48,6 @@
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
-import libcore.io.IoUtils;
import libcore.io.Streams;
import com.google.android.collect.Sets;
@@ -95,7 +94,7 @@
@After
public void tearDown() throws Exception {
- IoUtils.deleteContents(mDir);
+ FileUtils.deleteContents(mDir);
FileUtils.deleteContents(mTarget);
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 632c37f..60abd94 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -450,7 +450,6 @@
Settings.Global.GPU_DEBUG_APP,
Settings.Global.GPU_DEBUG_LAYERS,
Settings.Global.ANGLE_ENABLED_APP,
- Settings.Global.GPU_DEBUG_LAYER_APP,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT,
Settings.Global.INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS,
diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
index f8e3b4d..872b71a 100644
--- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java
+++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java
@@ -117,7 +117,7 @@
@Test
public void testFormatSameDayTime() {
// This test assumes a default DateFormat.is24Hour setting.
- DateFormat.is24Hour = null;
+ DateFormat.set24HourTimePref(null);
Date date = new Date(109, 0, 19, 3, 30, 15);
long fixedTime = date.getTime();
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index c8d994c..8e4f2cd 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -103,6 +103,18 @@
equalTo(new Rect[]{ZERO_RECT, boundTop, ZERO_RECT, boundBottom}));
}
+ @Test
+ public void testExtractBoundsFromList_nullBoundingRects() {
+ Rect safeInsets = new Rect(0, 0, 0, 0);
+ assertThat(extractBoundsFromList(safeInsets, null /* boundingRects */),
+ equalTo(new Rect[]{ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT}));
+ }
+
+ @Test
+ public void testExtractBoundsFromList_nullSafeInsets() {
+ assertThat(extractBoundsFromList(null /* safeInsets */, Collections.emptyList()),
+ equalTo(new Rect[]{ZERO_RECT, ZERO_RECT, ZERO_RECT, ZERO_RECT}));
+ }
@Test
public void hasCutout() throws Exception {
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
index 69d2828..506e544 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java
@@ -45,7 +45,7 @@
// The number of fields tested in the corresponding CTS AccessibilityNodeInfoTest:
// See fullyPopulateAccessibilityNodeInfo, assertEqualsAccessibilityNodeInfo,
// and assertAccessibilityNodeInfoCleared in that class.
- private static final int NUM_MARSHALLED_PROPERTIES = 33;
+ private static final int NUM_MARSHALLED_PROPERTIES = 34;
/**
* The number of properties that are purposely not marshalled
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 0c8dd9d..f637b7c 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -77,9 +77,13 @@
Message message = mHandlerFirst.obtainMessage(1000);
message.workSourceUid = 1000;
+ message.when = looperStats.getSystemUptimeMillis();
+
+ looperStats.tickUptime(30);
Object token = looperStats.messageDispatchStarting();
looperStats.tickRealtime(100);
looperStats.tickThreadTime(10);
+ looperStats.tickUptime(200);
looperStats.messageDispatched(token, message);
List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
@@ -98,6 +102,10 @@
assertThat(entry.maxLatencyMicros).isEqualTo(100);
assertThat(entry.cpuUsageMicros).isEqualTo(10);
assertThat(entry.maxCpuUsageMicros).isEqualTo(10);
+ assertThat(entry.recordedDelayMessageCount).isEqualTo(1);
+ assertThat(entry.delayMillis).isEqualTo(30);
+ assertThat(entry.maxDelayMillis).isEqualTo(30);
+
}
@Test
@@ -215,6 +223,56 @@
}
@Test
+ public void testDispatchDelayIsRecorded() {
+ TestableLooperStats looperStats = new TestableLooperStats(1, 100);
+
+ // Dispatched right on time.
+ Message message1 = mHandlerFirst.obtainMessage(1000);
+ message1.when = looperStats.getSystemUptimeMillis();
+ Object token1 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token1, message1);
+
+ // Dispatched 100ms late.
+ Message message2 = mHandlerFirst.obtainMessage(1000);
+ message2.when = looperStats.getSystemUptimeMillis() - 100;
+ Object token2 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token2, message2);
+
+ // No target dispatching time.
+ Message message3 = mHandlerFirst.obtainMessage(1000);
+ message3.when = 0;
+ Object token3 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token3, message3);
+
+ // Dispatched too soon (should never happen).
+ Message message4 = mHandlerFirst.obtainMessage(1000);
+ message4.when = looperStats.getSystemUptimeMillis() + 200;
+ Object token4 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token4, message4);
+
+ // Dispatched 300ms late.
+ Message message5 = mHandlerFirst.obtainMessage(1000);
+ message5.when = looperStats.getSystemUptimeMillis() - 300;
+ Object token5 = looperStats.messageDispatchStarting();
+ looperStats.tickUptime(10);
+ looperStats.messageDispatched(token5, message5);
+
+ List<LooperStats.ExportedEntry> entries = looperStats.getEntries();
+ assertThat(entries).hasSize(1);
+
+ LooperStats.ExportedEntry entry = entries.get(0);
+ assertThat(entry.messageCount).isEqualTo(5);
+ assertThat(entry.recordedMessageCount).isEqualTo(5);
+ assertThat(entry.recordedDelayMessageCount).isEqualTo(4);
+ assertThat(entry.delayMillis).isEqualTo(400);
+ assertThat(entry.maxDelayMillis).isEqualTo(300);
+ }
+
+ @Test
public void testDataNotCollectedBeforeDeviceStateSet() {
TestableLooperStats looperStats = new TestableLooperStats(1, 100);
looperStats.setDeviceState(null);
@@ -385,6 +443,7 @@
private int mCount;
private long mRealtimeMicros;
private long mThreadTimeMicros;
+ private long mUptimeMillis;
private int mSamplingInterval;
TestableLooperStats(int samplingInterval, int sizeCap) {
@@ -401,6 +460,10 @@
mThreadTimeMicros += micros;
}
+ void tickUptime(long millis) {
+ mUptimeMillis += millis;
+ }
+
@Override
protected long getElapsedRealtimeMicro() {
return INITIAL_MICROS + mRealtimeMicros;
@@ -412,6 +475,11 @@
}
@Override
+ protected long getSystemUptimeMillis() {
+ return INITIAL_MICROS / 1000 + mUptimeMillis;
+ }
+
+ @Override
protected boolean shouldCollectDetailedData() {
return mCount++ % mSamplingInterval == 0;
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index ed24543..44f8737 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -325,6 +325,7 @@
<permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
<permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.REAL_GET_TASKS"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<permission name="android.permission.REGISTER_CALL_PROVIDER"/>
<permission name="android.permission.REGISTER_CONNECTION_MANAGER"/>
<permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index 8414d6a..b65fb9c 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -2525,9 +2525,7 @@
gamma == 1.0 ? DoubleUnaryOperator.identity() :
x -> Math.pow(x < 0.0 ? 0.0 : x, gamma),
min, max, id);
- mTransferParameters = gamma == 1.0 ?
- new TransferParameters(0.0, 0.0, 1.0, 1.0 + Math.ulp(1.0f), gamma) :
- new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma);
+ mTransferParameters = new TransferParameters(1.0, 0.0, 0.0, 0.0, gamma);
}
/**
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 7efe522..f41cc7e 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -21,7 +21,6 @@
import android.annotation.IdRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.Context;
@@ -570,7 +569,7 @@
* Version of createWithResource that takes Resources. Do not use.
* @hide
*/
- @SystemApi
+ @UnsupportedAppUsage
public static Icon createWithResource(Resources res, @DrawableRes int resId) {
if (res == null) {
throw new IllegalArgumentException("Resource must not be null.");
diff --git a/keystore/OWNERS b/keystore/OWNERS
new file mode 100644
index 0000000..a63ca46
--- /dev/null
+++ b/keystore/OWNERS
@@ -0,0 +1,4 @@
+jbires@google.com
+jdanis@google.com
+robbarnes@google.com
+swillden@google.com
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 74cab92..98af3eb 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -50,6 +50,7 @@
"LocaleData.cpp",
"misc.cpp",
"ObbFile.cpp",
+ "PosixUtils.cpp",
"ResourceTypes.cpp",
"ResourceUtils.cpp",
"StreamingZipInflater.cpp",
@@ -157,6 +158,7 @@
srcs: [
"tests/BackupData_test.cpp",
"tests/ObbFile_test.cpp",
+ "tests/PosixUtils_test.cpp",
],
shared_libs: common_test_libs + ["libui"],
},
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 9c1629b..04cc5bb 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -67,10 +67,10 @@
}
bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
- bool invalidate_caches) {
+ bool invalidate_caches, bool filter_incompatible_configs) {
apk_assets_ = apk_assets;
BuildDynamicRefTable();
- RebuildFilterList();
+ RebuildFilterList(filter_incompatible_configs);
if (invalidate_caches) {
InvalidateCaches(static_cast<uint32_t>(-1));
}
@@ -825,7 +825,7 @@
return 0u;
}
-void AssetManager2::RebuildFilterList() {
+void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) {
for (PackageGroup& group : package_groups_) {
for (ConfiguredPackage& impl : group.packages_) {
// Destroy it.
@@ -841,7 +841,7 @@
for (auto iter = spec->types; iter != iter_end; ++iter) {
ResTable_config this_config;
this_config.copyFromDtoH((*iter)->config);
- if (this_config.match(configuration_)) {
+ if (!filter_incompatible_configs || this_config.match(configuration_)) {
group.configurations.push_back(this_config);
group.types.push_back(*iter);
}
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index c2740c9..68d216d 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -203,6 +203,39 @@
return true;
}
+LoadedPackage::iterator::iterator(const LoadedPackage* lp, size_t ti, size_t ei)
+ : loadedPackage_(lp),
+ typeIndex_(ti),
+ entryIndex_(ei),
+ typeIndexEnd_(lp->resource_ids_.size() + 1) {
+ while (typeIndex_ < typeIndexEnd_ && loadedPackage_->resource_ids_[typeIndex_] == 0) {
+ typeIndex_++;
+ }
+}
+
+LoadedPackage::iterator& LoadedPackage::iterator::operator++() {
+ while (typeIndex_ < typeIndexEnd_) {
+ if (entryIndex_ + 1 < loadedPackage_->resource_ids_[typeIndex_]) {
+ entryIndex_++;
+ break;
+ }
+ entryIndex_ = 0;
+ typeIndex_++;
+ if (typeIndex_ < typeIndexEnd_ && loadedPackage_->resource_ids_[typeIndex_] != 0) {
+ break;
+ }
+ }
+ return *this;
+}
+
+uint32_t LoadedPackage::iterator::operator*() const {
+ if (typeIndex_ >= typeIndexEnd_) {
+ return 0;
+ }
+ return make_resid(loadedPackage_->package_id_, typeIndex_ + loadedPackage_->type_id_offset_,
+ entryIndex_);
+}
+
const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk,
uint16_t entry_index) {
uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index);
@@ -488,6 +521,7 @@
std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type_spec->id - 1];
if (builder_ptr == nullptr) {
builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
+ loaded_package->resource_ids_.set(type_spec->id, entry_count);
} else {
LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
type_spec->id);
diff --git a/libs/androidfw/PosixUtils.cpp b/libs/androidfw/PosixUtils.cpp
new file mode 100644
index 0000000..df0dd7c
--- /dev/null
+++ b/libs/androidfw/PosixUtils.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#ifdef _WIN32
+// nothing to see here
+#else
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "android-base/logging.h"
+
+#include "androidfw/PosixUtils.h"
+
+namespace {
+
+std::unique_ptr<std::string> ReadFile(int fd) {
+ std::unique_ptr<std::string> str(new std::string());
+ char buf[1024];
+ ssize_t r;
+ while ((r = read(fd, buf, sizeof(buf))) > 0) {
+ str->append(buf, r);
+ }
+ if (r != 0) {
+ return nullptr;
+ }
+ return str;
+}
+
+}
+
+namespace android {
+namespace util {
+
+std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv) {
+ int stdout[2]; // stdout[0] read, stdout[1] write
+ if (pipe(stdout) != 0) {
+ PLOG(ERROR) << "pipe";
+ return nullptr;
+ }
+
+ int stderr[2]; // stdout[0] read, stdout[1] write
+ if (pipe(stderr) != 0) {
+ PLOG(ERROR) << "pipe";
+ close(stdout[0]);
+ close(stdout[1]);
+ return nullptr;
+ }
+
+ char const** argv0 = (char const**)malloc(sizeof(char*) * (argv.size() + 1));
+ for (size_t i = 0; i < argv.size(); i++) {
+ argv0[i] = argv[i].c_str();
+ }
+ argv0[argv.size()] = nullptr;
+ switch (fork()) {
+ case -1: // error
+ free(argv0);
+ PLOG(ERROR) << "fork";
+ return nullptr;
+ case 0: // child
+ close(stdout[0]);
+ if (dup2(stdout[1], STDOUT_FILENO) == -1) {
+ abort();
+ }
+ close(stderr[0]);
+ if (dup2(stderr[1], STDERR_FILENO) == -1) {
+ abort();
+ }
+ execvp(argv0[0], const_cast<char* const*>(argv0));
+ PLOG(ERROR) << "execv";
+ abort();
+ default: // parent
+ free(argv0);
+ close(stdout[1]);
+ close(stderr[1]);
+ int status;
+ wait(&status);
+ if (!WIFEXITED(status)) {
+ return nullptr;
+ }
+ std::unique_ptr<ProcResult> result(new ProcResult());
+ result->status = status;
+ const auto out = ReadFile(stdout[0]);
+ result->stdout = out ? *out : "";
+ close(stdout[0]);
+ const auto err = ReadFile(stderr[0]);
+ result->stderr = err ? *err : "";
+ close(stderr[0]);
+ return result;
+ }
+}
+
+} // namespace util
+} // namespace android
+#endif
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index ad31f69..2f0ee01 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -96,7 +96,12 @@
// Only pass invalidate_caches=false when it is known that the structure
// change in ApkAssets is due to a safe addition of resources with completely
// new resource IDs.
- bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true);
+ //
+ // Only pass in filter_incompatible_configs=false when you want to load all
+ // configurations (including incompatible ones) such as when constructing an
+ // idmap.
+ bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true,
+ bool filter_incompatible_configs = true);
inline const std::vector<const ApkAssets*> GetApkAssets() const {
return apk_assets_;
@@ -274,7 +279,7 @@
// Triggers the re-construction of lists of types that match the set configuration.
// This should always be called when mutating the AssetManager's configuration or ApkAssets set.
- void RebuildFilterList();
+ void RebuildFilterList(bool filter_incompatible_configs = true);
// AssetManager2::GetBag(resid) wraps this function to track which resource ids have already
// been seen while traversing bag parents.
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 35ae5fc..349b379 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -78,6 +78,55 @@
class LoadedPackage {
public:
+ class iterator {
+ public:
+ iterator& operator=(const iterator& rhs) {
+ loadedPackage_ = rhs.loadedPackage_;
+ typeIndex_ = rhs.typeIndex_;
+ entryIndex_ = rhs.entryIndex_;
+ return *this;
+ }
+
+ bool operator==(const iterator& rhs) const {
+ return loadedPackage_ == rhs.loadedPackage_ &&
+ typeIndex_ == rhs.typeIndex_ &&
+ entryIndex_ == rhs.entryIndex_;
+ }
+
+ bool operator!=(const iterator& rhs) const {
+ return !(*this == rhs);
+ }
+
+ iterator operator++(int) {
+ size_t prevTypeIndex_ = typeIndex_;
+ size_t prevEntryIndex_ = entryIndex_;
+ operator++();
+ return iterator(loadedPackage_, prevTypeIndex_, prevEntryIndex_);
+ }
+
+ iterator& operator++();
+
+ uint32_t operator*() const;
+
+ private:
+ friend class LoadedPackage;
+
+ iterator(const LoadedPackage* lp, size_t ti, size_t ei);
+
+ const LoadedPackage* loadedPackage_;
+ size_t typeIndex_;
+ size_t entryIndex_;
+ const size_t typeIndexEnd_; // STL style end, so one past the last element
+ };
+
+ iterator begin() const {
+ return iterator(this, 0, 0);
+ }
+
+ iterator end() const {
+ return iterator(this, resource_ids_.size() + 1, 0);
+ }
+
static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk,
const LoadedIdmap* loaded_idmap, bool system,
bool load_as_shared_library);
@@ -182,6 +231,7 @@
bool overlay_ = false;
ByteBucketArray<TypeSpecPtr> type_specs_;
+ ByteBucketArray<uint32_t> resource_ids_;
std::vector<DynamicPackageEntry> dynamic_package_map_;
};
diff --git a/libs/androidfw/include/androidfw/PosixUtils.h b/libs/androidfw/include/androidfw/PosixUtils.h
new file mode 100644
index 0000000..8fc3ee2
--- /dev/null
+++ b/libs/androidfw/include/androidfw/PosixUtils.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace util {
+
+struct ProcResult {
+ int status;
+ std::string stdout;
+ std::string stderr;
+};
+
+// Fork, exec and wait for an external process. Return nullptr if the process could not be launched,
+// otherwise a ProcResult containing the external process' exit status and captured stdout and
+// stderr.
+std::unique_ptr<ProcResult> ExecuteBinary(const std::vector<std::string>& argv);
+
+} // namespace util
+} // namespace android
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index cae632d..ffa4836 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -278,4 +278,52 @@
// sizeof(Res_value) might not be backwards compatible.
TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
+TEST(LoadedArscTest, ResourceIdentifierIterator) {
+ std::string contents;
+ ASSERT_TRUE(
+ ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
+
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ ASSERT_NE(nullptr, loaded_arsc);
+
+ const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+ ASSERT_EQ(1u, packages.size());
+ EXPECT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName());
+
+ const auto& loaded_package = packages[0];
+ auto iter = loaded_package->begin();
+ auto end = loaded_package->end();
+
+ ASSERT_NE(end, iter);
+ ASSERT_EQ(0x7f010000u, *iter++);
+ ASSERT_EQ(0x7f010001u, *iter++);
+ ASSERT_EQ(0x7f020000u, *iter++);
+ ASSERT_EQ(0x7f020001u, *iter++);
+ ASSERT_EQ(0x7f030000u, *iter++);
+ ASSERT_EQ(0x7f030001u, *iter++);
+ ASSERT_EQ(0x7f030002u, *iter++); // note: string without default, excluded by aapt2 dump
+ ASSERT_EQ(0x7f040000u, *iter++);
+ ASSERT_EQ(0x7f040001u, *iter++);
+ ASSERT_EQ(0x7f040002u, *iter++);
+ ASSERT_EQ(0x7f040003u, *iter++);
+ ASSERT_EQ(0x7f040004u, *iter++);
+ ASSERT_EQ(0x7f040005u, *iter++);
+ ASSERT_EQ(0x7f040006u, *iter++);
+ ASSERT_EQ(0x7f040007u, *iter++);
+ ASSERT_EQ(0x7f040008u, *iter++);
+ ASSERT_EQ(0x7f040009u, *iter++);
+ ASSERT_EQ(0x7f04000au, *iter++);
+ ASSERT_EQ(0x7f04000bu, *iter++);
+ ASSERT_EQ(0x7f04000cu, *iter++);
+ ASSERT_EQ(0x7f04000du, *iter++);
+ ASSERT_EQ(0x7f050000u, *iter++);
+ ASSERT_EQ(0x7f050001u, *iter++);
+ ASSERT_EQ(0x7f060000u, *iter++);
+ ASSERT_EQ(0x7f070000u, *iter++);
+ ASSERT_EQ(0x7f070001u, *iter++);
+ ASSERT_EQ(0x7f070002u, *iter++);
+ ASSERT_EQ(0x7f070003u, *iter++);
+ ASSERT_EQ(end, iter);
+}
+
} // namespace android
diff --git a/libs/androidfw/tests/PosixUtils_test.cpp b/libs/androidfw/tests/PosixUtils_test.cpp
new file mode 100644
index 0000000..cf97f87
--- /dev/null
+++ b/libs/androidfw/tests/PosixUtils_test.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include <utility>
+
+#include "androidfw/PosixUtils.h"
+
+#include "TestHelpers.h"
+
+using ::testing::IsNull;
+using ::testing::NotNull;
+
+namespace android {
+namespace util {
+
+TEST(PosixUtilsTest, AbsolutePathToBinary) {
+ const auto result = ExecuteBinary({"/bin/date", "--help"});
+ ASSERT_THAT(result, NotNull());
+ ASSERT_EQ(result->status, 0);
+ ASSERT_EQ(result->stdout.find("usage: date "), 0);
+}
+
+TEST(PosixUtilsTest, RelativePathToBinary) {
+ const auto result = ExecuteBinary({"date", "--help"});
+ ASSERT_THAT(result, NotNull());
+ ASSERT_EQ(result->status, 0);
+ ASSERT_EQ(result->stdout.find("usage: date "), 0);
+}
+
+TEST(PosixUtilsTest, BadParameters) {
+ const auto result = ExecuteBinary({"/bin/date", "--this-parameter-is-not-supported"});
+ ASSERT_THAT(result, NotNull());
+ ASSERT_NE(result->status, 0);
+}
+
+TEST(PosixUtilsTest, NoSuchBinary) {
+ const auto result = ExecuteBinary({"/this/binary/does/not/exist"});
+ ASSERT_THAT(result, IsNull());
+}
+
+} // android
+} // util
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 6d10c2d..b1968ba 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2380,10 +2380,12 @@
}
/**
+ * Return the package that implements the {@link #NETWORK_PROVIDER} functionality.
+ *
* @hide
*/
@SystemApi
- public String getNetworkProviderPackage() {
+ public @Nullable String getNetworkProviderPackage() {
try {
return mService.getNetworkProviderPackage();
} catch (RemoteException e) {
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 2395b24..b96a585 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -3252,7 +3252,7 @@
int thumbnailLength = jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder);
// The following code limits the size of thumbnail size not to overflow EXIF data area.
- thumbnailLength = Math.min(thumbnailLength, in.available() - thumbnailOffset);
+ thumbnailLength = Math.min(thumbnailLength, in.getLength() - thumbnailOffset);
if (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_RAF
|| mMimeType == IMAGE_TYPE_RW2) {
thumbnailOffset += mExifOffset;
@@ -3981,6 +3981,10 @@
public double readDouble() throws IOException {
return Double.longBitsToDouble(readLong());
}
+
+ public int getLength() {
+ return mLength;
+ }
}
// An output stream to write EXIF data area, which can be written in either little or big endian
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 0e5cbe4..5604ffd 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -3620,6 +3620,17 @@
&& getState() == PLAYER_STATE_ERROR) {
status = CALL_STATUS_INVALID_OPERATION;
} else {
+ if (mMediaCallType == CALL_COMPLETED_SEEK_TO) {
+ synchronized (mTaskLock) {
+ if (!mPendingTasks.isEmpty()) {
+ Task nextTask = mPendingTasks.get(0);
+ if (nextTask.mMediaCallType == mMediaCallType) {
+ throw new CommandSkippedException(
+ "consecutive seekTo is skipped except last one");
+ }
+ }
+ }
+ }
process();
}
} catch (IllegalStateException e) {
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
index cdaabdc..d0ca04b 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java
@@ -184,7 +184,6 @@
if (shouldScan(mBluetoothFilters)) {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BluetoothDevice.ACTION_FOUND);
- intentFilter.addAction(BluetoothDevice.ACTION_DISAPPEARED);
mBluetoothBroadcastReceiver = new BluetoothBroadcastReceiver();
registerReceiver(mBluetoothBroadcastReceiver, intentFilter);
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index e645adc..03eb0d9 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -67,10 +67,6 @@
LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# out/target/common/obj/APPS/CtsShimPriv_intermediates/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
@@ -113,10 +109,6 @@
LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/packages/CtsShim/build/shim/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
diff --git a/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
index 164fc5a..9855565 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/CutoutAvoidingToolbar.kt
@@ -26,15 +26,16 @@
private var _insets: WindowInsets? = null
constructor(context: Context) : super(context) {
- init(null, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- init(attrs, 0)
}
- constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
- init(attrs, defStyle)
+ constructor(
+ context: Context,
+ attrs: AttributeSet,
+ defStyle: Int
+ ) : super(context, attrs, defStyle) {
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
@@ -81,8 +82,4 @@
requestLayout()
}
}
-
- private fun init(attrs: AttributeSet?, defStyle: Int) {
- }
-
}
diff --git a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
index a4a3d3d..fc7e8b0 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/Painting.kt
@@ -17,7 +17,6 @@
package com.android.egg.paint
import android.content.Context
-import android.content.res.Resources
import android.graphics.*
import android.provider.Settings
import android.util.AttributeSet
@@ -26,7 +25,6 @@
import android.view.View
import android.view.WindowInsets
import java.util.concurrent.TimeUnit
-import android.util.Log
import android.provider.Settings.System
import org.json.JSONObject
@@ -86,11 +84,11 @@
}
var bitmap: Bitmap? = null
- var paperColor : Int = 0xFFFFFFFF.toInt()
+ var paperColor: Int = 0xFFFFFFFF.toInt()
private var _paintCanvas: Canvas? = null
private val _bitmapLock = Object()
-
+
private var _drawPaint = Paint(Paint.ANTI_ALIAS_FLAG)
private var _lastX = 0f
private var _lastY = 0f
@@ -113,7 +111,9 @@
FADE_TO_BLACK_CF
synchronized(_bitmapLock) {
- c.drawBitmap(bitmap, 0f, 0f, pt)
+ bitmap?.let {
+ c.drawBitmap(bitmap!!, 0f, 0f, pt)
+ }
}
invalidate()
}
@@ -122,18 +122,22 @@
}
constructor(context: Context) : super(context) {
- init(null, 0)
+ init()
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- init(attrs, 0)
+ init()
}
- constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
- init(attrs, defStyle)
+ constructor(
+ context: Context,
+ attrs: AttributeSet,
+ defStyle: Int
+ ) : super(context, attrs, defStyle) {
+ init()
}
- private fun init(attrs: AttributeSet?, defStyle: Int) {
+ private fun init() {
loadDevicePressureData()
}
@@ -264,7 +268,7 @@
super.onDraw(canvas)
bitmap?.let {
- canvas.drawBitmap(bitmap, 0f, 0f, _drawPaint);
+ canvas.drawBitmap(bitmap!!, 0f, 0f, _drawPaint)
}
}
@@ -330,8 +334,8 @@
}
if (bits.width != oldBits.height || bits.height != oldBits.width) {
matrix.postScale(
- bits.width.toFloat()/oldBits.height,
- bits.height.toFloat()/oldBits.width)
+ bits.width.toFloat() / oldBits.height,
+ bits.height.toFloat() / oldBits.width)
}
c.matrix = matrix
}
@@ -350,9 +354,10 @@
val invertPaint = Paint()
invertPaint.colorFilter = INVERT_CF
synchronized(_bitmapLock) {
- _paintCanvas?.drawBitmap(bitmap, 0f, 0f, invertPaint)
+ bitmap?.let {
+ _paintCanvas?.drawBitmap(bitmap!!, 0f, 0f, invertPaint)
+ }
}
invalidate()
}
}
-
diff --git a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
index 86b11e7..460fa3a 100644
--- a/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
+++ b/packages/EasterEgg/src/com/android/egg/paint/ToolbarView.kt
@@ -17,19 +17,10 @@
package com.android.egg.paint
import android.content.Context
-import android.graphics.Canvas
-import android.graphics.Color
-import android.graphics.Paint
-import android.graphics.Rect
-import android.graphics.drawable.Drawable
-import android.text.TextPaint
-import android.transition.ChangeBounds
import android.transition.Transition
import android.transition.TransitionListenerAdapter
-import android.transition.TransitionManager
import android.util.AttributeSet
import android.view.*
-import android.view.animation.OvershootInterpolator
import android.widget.FrameLayout
class ToolbarView : FrameLayout {
@@ -44,15 +35,16 @@
}
constructor(context: Context) : super(context) {
- init(null, 0)
}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
- init(attrs, 0)
}
- constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {
- init(attrs, defStyle)
+ constructor(
+ context: Context,
+ attrs: AttributeSet,
+ defStyle: Int
+ ) : super(context, attrs, defStyle) {
}
override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
@@ -70,8 +62,4 @@
return super.onApplyWindowInsets(insets)
}
-
- private fun init(attrs: AttributeSet?, defStyle: Int) {
- }
-
}
diff --git a/packages/PrintSpooler/Android.bp b/packages/PrintSpooler/Android.bp
new file mode 100644
index 0000000..c40a817
--- /dev/null
+++ b/packages/PrintSpooler/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2013 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_app {
+ name: "PrintSpooler",
+
+ resource_dirs: ["res"],
+
+ srcs: [
+ "src/**/*.java",
+ "src/com/android/printspooler/renderer/IPdfRenderer.aidl",
+ "src/com/android/printspooler/renderer/IPdfEditor.aidl",
+ ],
+
+ platform_apis: true,
+
+ jni_libs: ["libprintspooler_jni"],
+ static_libs: [
+ "android-support-v7-recyclerview",
+ "android-support-compat",
+ "android-support-media-compat",
+ "android-support-core-utils",
+ "android-support-core-ui",
+ "android-support-fragment",
+ "android-support-annotations",
+ ],
+}
diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk
deleted file mode 100644
index e356f38..0000000
--- a/packages/PrintSpooler/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_USE_AAPT2 := true
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += \
- src/com/android/printspooler/renderer/IPdfRenderer.aidl \
- src/com/android/printspooler/renderer/IPdfEditor.aidl
-
-LOCAL_PACKAGE_NAME := PrintSpooler
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_JNI_SHARED_LIBRARIES := libprintspooler_jni
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- android-support-v7-recyclerview \
- android-support-compat \
- android-support-media-compat \
- android-support-core-utils \
- android-support-core-ui \
- android-support-fragment
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-annotations
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintSpooler/tests/Android.mk b/packages/PrintSpooler/tests/Android.mk
deleted file mode 100644
index 83e00ce..0000000
--- a/packages/PrintSpooler/tests/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.bp b/packages/PrintSpooler/tests/outofprocess/Android.bp
new file mode 100644
index 0000000..e88074e
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "PrintSpoolerOutOfProcessTests",
+
+ srcs: ["src/**/*.java"],
+
+ libs: ["android.test.runner.stubs"],
+ static_libs: [
+ "android-support-test",
+ "ub-uiautomator",
+ "mockito-target-minus-junit4",
+ "print-test-util-lib",
+ ],
+
+ sdk_version: "test_current",
+ test_suites: ["device-tests"],
+}
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk
deleted file mode 100644
index 161a600..0000000
--- a/packages/PrintSpooler/tests/outofprocess/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4 print-test-util-lib
-
-LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java
index c26295c..8bf8fce 100644
--- a/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java
+++ b/packages/SettingsLib/SettingsSpinner/src/com/android/settingslib/widget/settingsspinner/SettingsSpinnerAdapter.java
@@ -24,7 +24,7 @@
/**
* An ArrayAdapter which was used by {@link SettingsSpinner} with settings style.
*/
-public class SettingsSpinnerAdapter<CharSequence> extends ArrayAdapter {
+public class SettingsSpinnerAdapter<T> extends ArrayAdapter<T> {
/**
* Constructs a new SettingsSpinnerAdapter with the given context.
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index da1354b..8745a33 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -662,9 +662,6 @@
dumpSetting(s, p,
Settings.Global.ANGLE_ENABLED_APP,
GlobalSettingsProto.Gpu.ANGLE_ENABLED_APP);
- dumpSetting(s, p,
- Settings.Global.GPU_DEBUG_LAYER_APP,
- GlobalSettingsProto.Gpu.DEBUG_LAYER_APP);
p.end(gpuToken);
final long hdmiToken = p.start(GlobalSettingsProto.HDMI);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ce503b3..dcc6cba 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -27,6 +27,7 @@
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
index 839b90b..ba4eb5f 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/SensorManagerPlugin.java
@@ -67,9 +67,25 @@
class TriggerEvent {
Sensor mSensor;
+ int mVendorType;
- public TriggerEvent(Sensor sensor) {
+ /**
+ * Creates a trigger event
+ * @param sensor The type of sensor, e.g. TYPE_WAKE_LOCK_SCREEN
+ * @param vendorType The vendor type, which should be unique for each type of sensor,
+ * e.g. SINGLE_TAP = 1, DOUBLE_TAP = 2, etc.
+ */
+ public TriggerEvent(Sensor sensor, int vendorType) {
mSensor = sensor;
+ mVendorType = vendorType;
+ }
+
+ public Sensor getSensor() {
+ return mSensor;
+ }
+
+ public int getVendorType() {
+ return mVendorType;
}
}
}
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 7a38899..f138685 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -24,8 +24,7 @@
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
- android:background="@color/notification_guts_bg_color"
- android:theme="@*android:style/Theme.DeviceDefault.Light">
+ android:background="@color/notification_guts_bg_color">
<!-- Package Info -->
<RelativeLayout
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index f0436de..d033057 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -49,11 +49,6 @@
android:paddingEnd="@dimen/status_bar_padding_end"
android:orientation="horizontal"
>
- <ViewStub
- android:id="@+id/operator_name"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout="@layout/operator_name" />
<FrameLayout
android:layout_height="match_parent"
android:layout_width="0dp"
@@ -70,6 +65,12 @@
android:layout_width="match_parent"
android:clipChildren="false"
>
+ <ViewStub
+ android:id="@+id/operator_name"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout="@layout/operator_name" />
+
<com.android.systemui.statusbar.policy.Clock
android:id="@+id/clock"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e1c71fa..42e19aa 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -761,6 +761,8 @@
<string name="quick_settings_cast_device_default_description">Ready to cast</string>
<!-- QuickSettings: Cast detail panel, text when there are no items [CHAR LIMIT=NONE] -->
<string name="quick_settings_cast_detail_empty_text">No devices available</string>
+ <!-- QuickSettings: Cast unavailable, text when not connected to WiFi [CHAR LIMIT=NONE] -->
+ <string name="quick_settings_cast_no_wifi">Wi\u2011Fi not connected</string>
<!-- QuickSettings: Brightness dialog title [CHAR LIMIT=NONE] -->
<string name="quick_settings_brightness_dialog_title">Brightness</string>
<!-- QuickSettings: Brightness dialog auto brightness button [CHAR LIMIT=NONE] -->
@@ -1999,6 +2001,9 @@
<!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_open_details">Open details.</string>
+ <!-- accessibility label for quick settings items that are currently disabled. Must have a reason [CHAR LIMIT=NONE] -->
+ <string name="accessibility_quick_settings_not_available">Unvailable due to <xliff:g name="reason" id="reason" example="Wifi not available">%s</xliff:g></string>
+
<!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
<string name="accessibility_quick_settings_open_settings">Open <xliff:g name="page" example="Bluetooth">%s</xliff:g> settings.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 4d24d82..3007b6e 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -736,14 +736,19 @@
switch (gravity) {
case Gravity.TOP:
out.set(displayCutout.getBoundingRectTop());
+ break;
case Gravity.LEFT:
out.set(displayCutout.getBoundingRectLeft());
+ break;
case Gravity.BOTTOM:
out.set(displayCutout.getBoundingRectBottom());
+ break;
case Gravity.RIGHT:
out.set(displayCutout.getBoundingRectRight());
+ break;
+ default:
+ out.setEmpty();
}
- out.setEmpty();
}
private void localBounds(Rect out) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 43dd412..77f7ad4f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -423,7 +423,7 @@
}
/**
- * A Sensor that is injected via plugin, for better ContextHub interface.
+ * A Sensor that is injected via plugin.
*/
private class PluginTriggerSensor extends TriggerSensor {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index ed78048..921db69 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -46,6 +46,7 @@
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastController.CastDevice;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.NetworkController;
import java.util.LinkedHashMap;
import java.util.Set;
@@ -58,16 +59,18 @@
private final CastController mController;
private final CastDetailAdapter mDetailAdapter;
private final KeyguardMonitor mKeyguard;
+ private final NetworkController mNetworkController;
private final Callback mCallback = new Callback();
private final ActivityStarter mActivityStarter;
private Dialog mDialog;
- private boolean mRegistered;
+ private boolean mWifiConnected;
public CastTile(QSHost host) {
super(host);
mController = Dependency.get(CastController.class);
mDetailAdapter = new CastDetailAdapter();
mKeyguard = Dependency.get(KeyguardMonitor.class);
+ mNetworkController = Dependency.get(NetworkController.class);
mActivityStarter = Dependency.get(ActivityStarter.class);
}
@@ -87,10 +90,12 @@
if (listening) {
mController.addCallback(mCallback);
mKeyguard.addCallback(mCallback);
+ mNetworkController.addCallback(mSignalCallback);
} else {
mController.setDiscovering(false);
mController.removeCallback(mCallback);
mKeyguard.removeCallback(mCallback);
+ mNetworkController.removeCallback(mSignalCallback);
}
}
@@ -112,6 +117,9 @@
@Override
protected void handleClick() {
+ if (getState().state == Tile.STATE_UNAVAILABLE) {
+ return;
+ }
if (mKeyguard.isSecure() && !mKeyguard.canSkipBouncer()) {
mActivityStarter.postQSRunnableDismissingKeyguard(() -> {
showDetail(true);
@@ -164,13 +172,22 @@
if (!state.value && connecting) {
state.label = mContext.getString(R.string.quick_settings_connecting);
}
- state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
: R.drawable.ic_qs_cast_off);
+ if (mWifiConnected) {
+ state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+ state.secondaryLabel = "";
+ state.contentDescription = state.contentDescription + ","
+ + mContext.getString(R.string.accessibility_quick_settings_open_details);
+ state.expandedAccessibilityClassName = Button.class.getName();
+ } else {
+ state.state = Tile.STATE_UNAVAILABLE;
+ String noWifi = mContext.getString(R.string.quick_settings_cast_no_wifi);
+ state.secondaryLabel = noWifi;
+ state.contentDescription = state.contentDescription + ", " + mContext.getString(
+ R.string.accessibility_quick_settings_not_available, noWifi);
+ }
mDetailAdapter.updateItems(devices);
- state.expandedAccessibilityClassName = Button.class.getName();
- state.contentDescription = state.contentDescription + ","
- + mContext.getString(R.string.accessibility_quick_settings_open_details);
}
@Override
@@ -192,6 +209,22 @@
: mContext.getString(R.string.quick_settings_cast_device_default_name);
}
+ private final NetworkController.SignalCallback mSignalCallback =
+ new NetworkController.SignalCallback() {
+ @Override
+ public void setWifiIndicators(boolean enabled,
+ NetworkController.IconState statusIcon,
+ NetworkController.IconState qsIcon, boolean activityIn, boolean activityOut,
+ String description, boolean isTransient, String statusLabel) {
+ // statusIcon.visible has the connected status information
+ boolean enabledAndConnected = enabled && qsIcon.visible;
+ if (enabledAndConnected != mWifiConnected) {
+ mWifiConnected = enabledAndConnected;
+ refreshState();
+ }
+ }
+ };
+
private final class Callback implements CastController.Callback, KeyguardMonitor.Callback {
@Override
public void onCastDevicesChanged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 2450e44..24665ea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -491,6 +491,10 @@
@Override
public void onStateChanged(int newState) {
super.onStateChanged(newState);
+ if (mFullscreenUserSwitcher == null) {
+ return; // Not using the full screen user switcher.
+ }
+
if (newState == StatusBarState.FULLSCREEN_USER_SWITCHER) {
if (!mFullscreenUserSwitcher.isVisible()) {
// Current execution path continues to set state after this, thus we deffer the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 9acaf21..c66bbb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -48,6 +48,7 @@
private final NotificationStackScrollLayout mStackScroller;
private final HeadsUpStatusBarView mHeadsUpStatusBarView;
private final View mClockView;
+ private final View mOperatorNameView;
private final DarkIconDispatcher mDarkIconDispatcher;
private final NotificationPanelView mPanelView;
private final Consumer<ExpandableNotificationRow>
@@ -65,8 +66,10 @@
private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
-> updatePanelTranslation();
+ private boolean mAnimationsEnabled = true;
Point mPoint;
+
public HeadsUpAppearanceController(
NotificationIconAreaController notificationIconAreaController,
HeadsUpManagerPhone headsUpManager,
@@ -75,7 +78,8 @@
statusbarView.findViewById(R.id.heads_up_status_bar_view),
statusbarView.findViewById(R.id.notification_stack_scroller),
statusbarView.findViewById(R.id.notification_panel),
- statusbarView.findViewById(R.id.clock));
+ statusbarView.findViewById(R.id.clock),
+ statusbarView.findViewById(R.id.operator_name_frame));
}
@VisibleForTesting
@@ -85,7 +89,8 @@
HeadsUpStatusBarView headsUpStatusBarView,
NotificationStackScrollLayout stackScroller,
NotificationPanelView panelView,
- View clockView) {
+ View clockView,
+ View operatorNameView) {
mNotificationIconAreaController = notificationIconAreaController;
mHeadsUpManager = headsUpManager;
mHeadsUpManager.addListener(this);
@@ -101,6 +106,7 @@
mStackScroller.addOnLayoutChangeListener(mStackScrollLayoutChangeListener);
mStackScroller.setHeadsUpAppearanceController(this);
mClockView = clockView;
+ mOperatorNameView = operatorNameView;
mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
mDarkIconDispatcher.addDarkReceiver(this);
@@ -230,20 +236,52 @@
mShown = isShown;
if (isShown) {
mHeadsUpStatusBarView.setVisibility(View.VISIBLE);
- CrossFadeHelper.fadeIn(mHeadsUpStatusBarView, CONTENT_FADE_DURATION /* duration */,
- CONTENT_FADE_DELAY /* delay */);
- CrossFadeHelper.fadeOut(mClockView, CONTENT_FADE_DURATION/* duration */,
- 0 /* delay */, () -> mClockView.setVisibility(View.INVISIBLE));
+ show(mHeadsUpStatusBarView);
+ hide(mClockView, View.INVISIBLE);
+ if (mOperatorNameView != null) {
+ hide(mOperatorNameView, View.INVISIBLE);
+ }
} else {
- CrossFadeHelper.fadeIn(mClockView, CONTENT_FADE_DURATION /* duration */,
- CONTENT_FADE_DELAY /* delay */);
- CrossFadeHelper.fadeOut(mHeadsUpStatusBarView, CONTENT_FADE_DURATION/* duration */,
- 0 /* delay */, () -> mHeadsUpStatusBarView.setVisibility(View.GONE));
-
+ show(mClockView);
+ if (mOperatorNameView != null) {
+ show(mOperatorNameView);
+ }
+ hide(mHeadsUpStatusBarView, View.GONE);
}
}
}
+ /**
+ * Hides the view and sets the state to endState when finished.
+ *
+ * @param view The view to hide.
+ * @param endState One of {@link View#INVISIBLE} or {@link View#GONE}.
+ * @see View#setVisibility(int)
+ *
+ */
+ private void hide(View view, int endState) {
+ if (mAnimationsEnabled) {
+ CrossFadeHelper.fadeOut(view, CONTENT_FADE_DURATION /* duration */,
+ 0 /* delay */, () -> view.setVisibility(endState));
+ } else {
+ view.setVisibility(endState);
+ }
+ }
+
+ private void show(View view) {
+ if (mAnimationsEnabled) {
+ CrossFadeHelper.fadeIn(view, CONTENT_FADE_DURATION /* duration */,
+ CONTENT_FADE_DELAY /* delay */);
+ } else {
+ view.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @VisibleForTesting
+ void setAnimationsEnabled(boolean enabled) {
+ mAnimationsEnabled = enabled;
+ }
+
@VisibleForTesting
public boolean isShown() {
return mShown;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 2a4595b..8ac8677 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -361,6 +361,8 @@
} else if (fraction == EXPANSION_HIDDEN && oldExpansion != EXPANSION_HIDDEN) {
onFullyHidden();
mExpansionCallback.onFullyHidden();
+ } else if (fraction != EXPANSION_VISIBLE && oldExpansion == EXPANSION_VISIBLE) {
+ mExpansionCallback.onStartingToHide();
}
}
@@ -481,6 +483,7 @@
public interface BouncerExpansionCallback {
void onFullyShown();
+ void onStartingToHide();
void onFullyHidden();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 7c84df9..e85ff8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -519,7 +519,14 @@
mStatusIconContainer.setAlpha(alpha);
mStatusIconContainer.setVisibility(visibility);
- mSystemIconsContainer.setTranslationX(-mCurrentBurnInOffsetX * mDarkAmount);
+ float iconsX = -mCurrentBurnInOffsetX;
+ if (mMultiUserSwitch.getVisibility() == VISIBLE) {
+ // Squared alpha to add a nice easing curve and avoid overlap during animation.
+ mMultiUserAvatar.setAlpha(alpha * alpha);
+ iconsX += mMultiUserAvatar.getPaddingLeft() + mMultiUserAvatar.getWidth()
+ + mMultiUserAvatar.getPaddingRight();
+ }
+ mSystemIconsContainer.setTranslationX(iconsX * mDarkAmount);
mSystemIconsContainer.setTranslationY(mCurrentBurnInOffsetY * mDarkAmount);
updateIconsAndTextColors();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 3db1456..ac3608b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -84,6 +84,11 @@
}
@Override
+ public void onStartingToHide() {
+ updateStates();
+ }
+
+ @Override
public void onFullyHidden() {
updateStates();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
new file mode 100644
index 0000000..d9412ec
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.systemui.qs.tiles;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.service.quicksettings.Tile;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.qs.QSTileHost;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.NetworkController;
+
+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.util.HashSet;
+import java.util.Set;
+
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class CastTileTest extends SysuiTestCase {
+
+ @Mock
+ private CastController mController;
+ @Mock
+ private ActivityStarter mActivityStarter;
+ @Mock
+ private KeyguardMonitor mKeyguard;
+ @Mock
+ private NetworkController mNetworkController;
+ @Mock
+ private QSTileHost mHost;
+ @Mock
+ NetworkController.SignalCallback mCallback;
+
+ private TestableLooper mTestableLooper;
+ private CastTile mCastTile;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mTestableLooper = TestableLooper.get(this);
+
+ mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper());
+ mController = mDependency.injectMockDependency(CastController.class);
+ mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
+ mKeyguard = mDependency.injectMockDependency(KeyguardMonitor.class);
+ mNetworkController = mDependency.injectMockDependency(NetworkController.class);
+
+ when(mHost.getContext()).thenReturn(mContext);
+
+ mCastTile = new CastTile(mHost);
+
+ // We are not setting the mocks to listening, so we trigger a first refresh state to
+ // set the initial state
+ mCastTile.refreshState();
+
+ mCastTile.handleSetListening(true);
+ ArgumentCaptor<NetworkController.SignalCallback> signalCallbackArgumentCaptor =
+ ArgumentCaptor.forClass(NetworkController.SignalCallback.class);
+ verify(mNetworkController).addCallback(signalCallbackArgumentCaptor.capture());
+ mCallback = signalCallbackArgumentCaptor.getValue();
+
+ }
+
+ @Test
+ public void testStateUnavailable_wifiDisabled() {
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(false, 0, "");
+ mCallback.setWifiIndicators(false, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
+ }
+
+ @Test
+ public void testStateUnavailable_wifiNotConnected() {
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(false, 0, "");
+ mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_UNAVAILABLE, mCastTile.getState().state);
+ }
+
+ @Test
+ public void testStateActive_wifiEnabledAndCasting() {
+ CastController.CastDevice device = mock(CastController.CastDevice.class);
+ device.state = CastController.CastDevice.STATE_CONNECTED;
+ Set<CastController.CastDevice> devices = new HashSet<>();
+ devices.add(device);
+ when(mController.getCastDevices()).thenReturn(devices);
+
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(true, 0, "");
+ mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_ACTIVE, mCastTile.getState().state);
+ }
+
+ @Test
+ public void testStateInactive_wifiEnabledNotCasting() {
+ NetworkController.IconState qsIcon =
+ new NetworkController.IconState(true, 0, "");
+ mCallback.setWifiIndicators(true, mock(NetworkController.IconState.class),
+ qsIcon, false,false, "",
+ false, "");
+ mTestableLooper.processAllMessages();
+
+ assertEquals(Tile.STATE_INACTIVE, mCastTile.getState().state);
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
index a4004ae..10b0d83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceControllerTest.java
@@ -54,6 +54,7 @@
private ExpandableNotificationRow mFirst;
private HeadsUpStatusBarView mHeadsUpStatusBarView;
private HeadsUpManagerPhone mHeadsUpManager;
+ private View mOperatorNameView;
@Before
public void setUp() throws Exception {
@@ -63,13 +64,15 @@
mHeadsUpStatusBarView = new HeadsUpStatusBarView(mContext, mock(View.class),
mock(TextView.class));
mHeadsUpManager = mock(HeadsUpManagerPhone.class);
+ mOperatorNameView = new View(mContext);
mHeadsUpAppearanceController = new HeadsUpAppearanceController(
mock(NotificationIconAreaController.class),
mHeadsUpManager,
mHeadsUpStatusBarView,
mStackScroller,
mPanelView,
- new View(mContext));
+ new View(mContext),
+ mOperatorNameView);
mHeadsUpAppearanceController.setExpandedHeight(0.0f, 0.0f);
}
@@ -116,6 +119,22 @@
}
@Test
+ public void testOperatorNameViewUpdated() {
+ mHeadsUpAppearanceController.setAnimationsEnabled(false);
+
+ mFirst.setPinned(true);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
+ when(mHeadsUpManager.getTopEntry()).thenReturn(mFirst.getEntry());
+ mHeadsUpAppearanceController.onHeadsUpPinned(mFirst);
+ Assert.assertEquals(View.INVISIBLE, mOperatorNameView.getVisibility());
+
+ mFirst.setPinned(false);
+ when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
+ mHeadsUpAppearanceController.onHeadsUpUnPinned(mFirst);
+ Assert.assertEquals(View.VISIBLE, mOperatorNameView.getVisibility());
+ }
+
+ @Test
public void testHeaderReadFromOldController() {
mHeadsUpAppearanceController.setExpandedHeight(1.0f, 1.0f);
@@ -125,6 +144,7 @@
mHeadsUpStatusBarView,
mStackScroller,
mPanelView,
+ new View(mContext),
new View(mContext));
newController.readFrom(mHeadsUpAppearanceController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index a7954f2..020682b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -170,13 +170,17 @@
mBouncer.ensureView();
mBouncer.setExpansion(0.5f);
- mBouncer.setExpansion(1);
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
verify(mFalsingManager).onBouncerHidden();
verify(mExpansionCallback).onFullyHidden();
- mBouncer.setExpansion(0);
+ mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
verify(mFalsingManager).onBouncerShown();
verify(mExpansionCallback).onFullyShown();
+
+ verify(mExpansionCallback, never()).onStartingToHide();
+ mBouncer.setExpansion(0.9f);
+ verify(mExpansionCallback).onStartingToHide();
}
@Test
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 5e87707..d86de5d 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6549,6 +6549,21 @@
// Subtype: The importance of a notification has been changed
ADJUSTMENT_KEY_IMPORTANCE = 1580;
+ // OPEN: Settings > Network & internet > Mobile network > Choose network
+ // CATEGORY: SETTINGS
+ // OS: Q
+ MOBILE_NETWORK_SELECT = 1581;
+
+ // OPEN: Settings > Network & internet > Mobile network > Mobile Data > Dialog
+ // CATEGORY: SETTINGS
+ // OS: Q
+ MOBILE_DATA_DIALOG = 1582;
+
+ // OPEN: Settings > Network & internet > Mobile network > Data roaming > Dialog
+ // CATEGORY: SETTINGS
+ // OS: Q
+ MOBILE_ROAMING_DIALOG = 1583;
+
// ---- End Q Constants, all Q constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/core/Android.bp b/services/core/Android.bp
index d9519e0..2fa2941 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -4,6 +4,7 @@
aidl: {
include_dirs: [
"frameworks/native/aidl/binder",
+ "frameworks/native/cmds/dumpstate/binder",
"system/core/storaged/binder",
"system/netd/server/binder",
"system/vold/binder",
@@ -11,6 +12,7 @@
},
srcs: [
"java/**/*.java",
+ ":dumpstate_aidl",
":netd_aidl",
":netd_metrics_aidl",
":installd_aidl",
@@ -44,6 +46,7 @@
"android.hardware.configstore-V1.0-java",
"android.hardware.contexthub-V1.0-java",
"android.hidl.manager-V1.0-java",
+ "netd_aidl_interface-java",
],
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5e8ffb7..4b77c69 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1798,7 +1798,8 @@
private void sendStickyBroadcast(Intent intent) {
synchronized (this) {
- if (!mSystemReady) {
+ if (!mSystemReady
+ && intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
mInitialBroadcast = new Intent(intent);
}
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -1847,8 +1848,6 @@
mInitialBroadcast = null;
}
}
- // load the global proxy at startup
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
// Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
// for user to unlock device too.
@@ -3089,7 +3088,7 @@
break;
}
case EVENT_APPLY_GLOBAL_HTTP_PROXY: {
- handleDeprecatedGlobalHttpProxy();
+ mProxyTracker.loadDeprecatedGlobalHttpProxy();
break;
}
case EVENT_PROXY_HAS_CHANGED: {
@@ -3483,29 +3482,6 @@
}
}
- private void handleDeprecatedGlobalHttpProxy() {
- final String proxy = Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.HTTP_PROXY);
- if (!TextUtils.isEmpty(proxy)) {
- String data[] = proxy.split(":");
- if (data.length == 0) {
- return;
- }
-
- final String proxyHost = data[0];
- int proxyPort = 8080;
- if (data.length > 1) {
- try {
- proxyPort = Integer.parseInt(data[1]);
- } catch (NumberFormatException e) {
- return;
- }
- }
- final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
- setGlobalProxy(p);
- }
- }
-
private static class SettingsObserver extends ContentObserver {
final private HashMap<Uri, Integer> mUriEventMap;
final private Context mContext;
@@ -5537,15 +5513,7 @@
if (networkAgent.isVPN()) {
// Temporarily disable the default proxy (not global).
- synchronized (mProxyTracker.mProxyLock) {
- if (!mProxyTracker.mDefaultProxyDisabled) {
- mProxyTracker.mDefaultProxyDisabled = true;
- if (mProxyTracker.mGlobalProxy == null
- && mProxyTracker.mDefaultProxy != null) {
- mProxyTracker.sendProxyBroadcast(null);
- }
- }
- }
+ mProxyTracker.setDefaultProxyEnabled(false);
// TODO: support proxy per network.
}
@@ -5567,15 +5535,7 @@
} else if (state == NetworkInfo.State.DISCONNECTED) {
networkAgent.asyncChannel.disconnect();
if (networkAgent.isVPN()) {
- synchronized (mProxyTracker.mProxyLock) {
- if (mProxyTracker.mDefaultProxyDisabled) {
- mProxyTracker.mDefaultProxyDisabled = false;
- if (mProxyTracker.mGlobalProxy == null
- && mProxyTracker.mDefaultProxy != null) {
- mProxyTracker.sendProxyBroadcast(mProxyTracker.mDefaultProxy);
- }
- }
- }
+ mProxyTracker.setDefaultProxyEnabled(true);
updateUids(networkAgent, networkAgent.networkCapabilities, null);
}
disconnectAndDestroyNetwork(networkAgent);
diff --git a/services/core/java/com/android/server/LooperStatsService.java b/services/core/java/com/android/server/LooperStatsService.java
index 96ce6a4..6677541 100644
--- a/services/core/java/com/android/server/LooperStatsService.java
+++ b/services/core/java/com/android/server/LooperStatsService.java
@@ -109,14 +109,28 @@
"max_latency_micros",
"total_cpu_micros",
"max_cpu_micros",
+ "recorded_delay_message_count",
+ "total_delay_millis",
+ "max_delay_millis",
"exception_count"));
pw.println(header);
for (LooperStats.ExportedEntry entry : entries) {
- pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n", entry.workSourceUid,
- entry.threadName, entry.handlerClassName, entry.messageName,
- entry.isInteractive, entry.messageCount, entry.recordedMessageCount,
- entry.totalLatencyMicros, entry.maxLatencyMicros, entry.cpuUsageMicros,
- entry.maxCpuUsageMicros, entry.exceptionCount);
+ pw.printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
+ entry.workSourceUid,
+ entry.threadName,
+ entry.handlerClassName,
+ entry.messageName,
+ entry.isInteractive,
+ entry.messageCount,
+ entry.recordedMessageCount,
+ entry.totalLatencyMicros,
+ entry.maxLatencyMicros,
+ entry.cpuUsageMicros,
+ entry.maxCpuUsageMicros,
+ entry.recordedDelayMessageCount,
+ entry.delayMillis,
+ entry.maxDelayMillis,
+ entry.exceptionCount);
}
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index de930f7..cf39e95 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -57,6 +57,7 @@
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
+import android.net.TetherStatsParcel;
import android.net.INetworkManagementEventObserver;
import android.net.ITetheringStatsProvider;
import android.net.InterfaceConfiguration;
@@ -1844,31 +1845,30 @@
return new NetworkStats(SystemClock.elapsedRealtime(), 0);
}
- final PersistableBundle bundle;
+ final TetherStatsParcel[] tetherStatsVec;
try {
- bundle = mNetdService.tetherGetStats();
+ tetherStatsVec = mNetdService.tetherGetStats();
} catch (RemoteException | ServiceSpecificException e) {
throw new IllegalStateException("problem parsing tethering stats: ", e);
}
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(),
- bundle.size());
+ tetherStatsVec.length);
final NetworkStats.Entry entry = new NetworkStats.Entry();
- for (String iface : bundle.keySet()) {
- long[] statsArray = bundle.getLongArray(iface);
+ for (TetherStatsParcel tetherStats : tetherStatsVec) {
try {
- entry.iface = iface;
+ entry.iface = tetherStats.iface;
entry.uid = UID_TETHERING;
entry.set = SET_DEFAULT;
entry.tag = TAG_NONE;
- entry.rxBytes = statsArray[INetd.TETHER_STATS_RX_BYTES];
- entry.rxPackets = statsArray[INetd.TETHER_STATS_RX_PACKETS];
- entry.txBytes = statsArray[INetd.TETHER_STATS_TX_BYTES];
- entry.txPackets = statsArray[INetd.TETHER_STATS_TX_PACKETS];
+ entry.rxBytes = tetherStats.rxBytes;
+ entry.rxPackets = tetherStats.rxPackets;
+ entry.txBytes = tetherStats.txBytes;
+ entry.txPackets = tetherStats.txPackets;
stats.combineValues(entry);
} catch (ArrayIndexOutOfBoundsException e) {
- throw new IllegalStateException("invalid tethering stats for " + iface, e);
+ throw new IllegalStateException("invalid tethering stats " + e);
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index fb8894b..591ec00 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -49,6 +49,7 @@
import android.telephony.TelephonyManager;
import android.telephony.VoLteServiceState;
import android.util.LocalLog;
+import android.util.StatsLog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
@@ -1719,8 +1720,12 @@
try {
if (state == TelephonyManager.CALL_STATE_IDLE) {
mBatteryStats.notePhoneOff();
+ StatsLog.write(StatsLog.PHONE_STATE_CHANGED,
+ StatsLog.PHONE_STATE_CHANGED__STATE__OFF);
} else {
mBatteryStats.notePhoneOn();
+ StatsLog.write(StatsLog.PHONE_STATE_CHANGED,
+ StatsLog.PHONE_STATE_CHANGED__STATE__ON);
}
} catch (RemoteException e) {
/* The remote entity disappeared, we can safely ignore the exception. */
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index a648b09a..95a8e2a 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -1087,7 +1087,7 @@
if (top == null) {
return false;
}
- mSupervisor.moveFocusableActivityToTop(top, reason);
+ top.moveFocusableActivityToTop(reason);
return true;
}
diff --git a/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java b/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
deleted file mode 100644
index f44ee7a..0000000
--- a/services/core/java/com/android/server/am/ActivityLaunchParamsModifier.java
+++ /dev/null
@@ -1,65 +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.am;
-
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-
-import com.android.server.am.LaunchParamsController.LaunchParams;
-import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
-
-/**
- * An implementation of {@link LaunchParamsModifier}, which applies the launch bounds specified
- * inside {@link ActivityOptions#getLaunchBounds()}.
- */
-public class ActivityLaunchParamsModifier implements LaunchParamsModifier {
- private final ActivityStackSupervisor mSupervisor;
-
- ActivityLaunchParamsModifier(ActivityStackSupervisor activityStackSupervisor) {
- mSupervisor = activityStackSupervisor;
- }
-
- @Override
- public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
- ActivityRecord activity, ActivityRecord source, ActivityOptions options,
- LaunchParams currentParams, LaunchParams outParams) {
- // We only care about figuring out bounds for activities.
- if (activity == null) {
- return RESULT_SKIP;
- }
-
- // Activity must be resizeable in the specified task.
- if (!(mSupervisor.canUseActivityOptionsLaunchBounds(options)
- && (activity.isResizeable() || (task != null && task.isResizeable())))) {
- return RESULT_SKIP;
- }
-
- final Rect bounds = options.getLaunchBounds();
-
- // Bounds weren't valid.
- if (bounds == null || bounds.isEmpty()) {
- return RESULT_SKIP;
- }
-
- outParams.mBounds.set(bounds);
-
- // When this is the most explicit position specification so we should not allow further
- // modification of the position.
- return RESULT_DONE;
- }
-}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 37167c6..acf7a73 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -10184,6 +10184,7 @@
synchronized (this) {
sb.append("Process: ").append(processName).append("\n");
sb.append("PID: ").append(process.pid).append("\n");
+ sb.append("UID: ").append(process.uid).append("\n");
int flags = process.info.flags;
IPackageManager pm = AppGlobals.getPackageManager();
sb.append("Flags: 0x").append(Integer.toHexString(flags)).append("\n");
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 18cdb05..7080e2b 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -110,7 +110,7 @@
* data for Tron, logcat, event logs and {@link android.app.WaitResult}.
*
* Tests:
- * atest SystemMetricsFunctionalTests
+ * atest CtsActivityManagerDeviceTestCases:ActivityMetricsLoggerTests
*/
class ActivityMetricsLogger {
@@ -351,18 +351,24 @@
+ " processRunning=" + processRunning
+ " processSwitch=" + processSwitch);
- // If we are already in an existing transition, only update the activity name, but not the
- // other attributes.
final int windowingMode = launchedActivity != null
? launchedActivity.getWindowingMode()
: WINDOWING_MODE_UNDEFINED;
-
+ final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
if (mCurrentTransitionStartTime == INVALID_START_TIME) {
+ // No transition is active ignore this launch.
return;
}
- final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
+ if (launchedActivity != null && launchedActivity.nowVisible) {
+ // Launched activity is already visible. We cannot measure windows drawn delay.
+ reset(true /* abort */, info);
+ return;
+ }
+
if (launchedActivity != null && info != null) {
+ // If we are already in an existing transition, only update the activity name, but not
+ // the other attributes.
info.launchedActivity = launchedActivity;
return;
}
@@ -371,7 +377,6 @@
mWindowingModeTransitionInfo.size() > 0 && info == null;
if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
|| windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
-
// Failed to launch or it was not a process switch, so we don't care about the timing.
reset(true /* abort */, info);
return;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index fe10baf..6bdceb2 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -84,11 +84,13 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
@@ -215,6 +217,7 @@
private static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
+ private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
// TODO(b/67864419): Remove once recents component is overridden
private static final String LEGACY_RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
@@ -1348,6 +1351,42 @@
return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
}
+ /** Move activity with its stack to front and make the stack focused. */
+ boolean moveFocusableActivityToTop(String reason) {
+ if (!isFocusable()) {
+ if (DEBUG_FOCUS) {
+ Slog.d(TAG_FOCUS, "moveActivityStackToFront: unfocusable activity=" + this);
+ }
+ return false;
+ }
+
+ final TaskRecord task = getTask();
+ final ActivityStack stack = getStack();
+ if (stack == null) {
+ Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: activity="
+ + this + " task=" + task);
+ return false;
+ }
+
+ if (mStackSupervisor.getTopResumedActivity() == this) {
+ if (DEBUG_FOCUS) {
+ Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this);
+ }
+ return false;
+ }
+
+ if (DEBUG_FOCUS) {
+ Slog.d(TAG_FOCUS, "moveActivityStackToFront: activity=" + this);
+ }
+
+ stack.moveToFront(reason, task);
+ // Report top activity change to tracking services and WM
+ if (mStackSupervisor.getTopResumedActivity() == this) {
+ // TODO(b/111361570): Support multiple focused apps in WM
+ service.setResumedActivityUncheckLocked(this, reason);
+ }
+ return true;
+ }
/**
* @return true if the activity contains windows that have
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6388423..864bf2d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -227,7 +227,7 @@
}
@Override
- protected ConfigurationContainer getChildAt(int index) {
+ protected TaskRecord getChildAt(int index) {
return mTaskHistory.get(index);
}
@@ -3450,8 +3450,10 @@
final String myReason = reason + " adjustFocus";
if (next == r) {
- mStackSupervisor.moveFocusableActivityToTop(mStackSupervisor.topRunningActivityLocked(),
- myReason);
+ final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
+ if (top != null) {
+ top.moveFocusableActivityToTop(myReason);
+ }
return;
}
@@ -4662,7 +4664,9 @@
// Set focus to the top running activity of this stack.
final ActivityRecord r = topRunningActivityLocked();
- mStackSupervisor.moveFocusableActivityToTop(r, reason);
+ if (r != null) {
+ r.moveFocusableActivityToTop(reason);
+ }
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
if (noAnimation) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0477d73..8c8146c 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -53,8 +53,8 @@
import static android.view.Display.INVALID_DISPLAY;
import static android.view.Display.TYPE_VIRTUAL;
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
+
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
@@ -63,7 +63,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_FOCUS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
@@ -99,6 +98,7 @@
import static com.android.server.am.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
import static com.android.server.am.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+
import static java.lang.Integer.MAX_VALUE;
import android.Manifest;
@@ -199,7 +199,6 @@
public class ActivityStackSupervisor extends ConfigurationContainer implements DisplayListener,
RecentTasks.Callbacks, RootWindowContainerListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
- private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
private static final String TAG_IDLE = TAG + POSTFIX_IDLE;
private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -783,7 +782,7 @@
// Only resume home activity if isn't finishing.
if (r != null && !r.finishing) {
- moveFocusableActivityToTop(r, myReason);
+ r.moveFocusableActivityToTop(myReason);
return resumeFocusedStacksTopActivitiesLocked(r.getStack(), prev, null);
}
return mService.startHomeActivityLocked(mCurrentUser, myReason, displayId);
@@ -3359,41 +3358,6 @@
mService.getTaskChangeNotificationController().notifyActivityPinned(r);
}
- /** Move activity with its stack to front and make the stack focused. */
- // TODO(b/111363427): Move this method to ActivityRecord.
- boolean moveFocusableActivityToTop(ActivityRecord r, String reason) {
- if (r == null || !r.isFocusable()) {
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
- "moveActivityStackToFront: unfocusable r=" + r);
- return false;
- }
-
- final TaskRecord task = r.getTask();
- final ActivityStack stack = r.getStack();
- if (stack == null) {
- Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: r="
- + r + " task=" + task);
- return false;
- }
-
- if (r == getTopResumedActivity()) {
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
- "moveActivityStackToFront: already on top, r=" + r);
- return false;
- }
-
- if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
- "moveActivityStackToFront: r=" + r);
-
- stack.moveToFront(reason, task);
- // Report top activity change to tracking services and WM
- if (r == getTopResumedActivity()) {
- // TODO(b/111361570): Support multiple focused apps in WM
- mService.setResumedActivityUncheckLocked(r, reason);
- }
- return true;
- }
-
ActivityRecord findTaskLocked(ActivityRecord r, int preferredDisplayId) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
mTmpFindTaskResult.clear();
@@ -4456,10 +4420,6 @@
if (!task.canBeLaunchedOnDisplay(actualDisplayId)) {
throw new IllegalStateException("Task resolved to incompatible display");
}
- // The task might have landed on a display different from requested.
- // TODO(multi-display): Find proper stack for the task on the default display.
- mService.setTaskWindowingMode(task.taskId,
- WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, true /* toTop */);
if (preferredDisplayId != actualDisplayId) {
Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplayId);
// Display a warning toast that we failed to put a task on a secondary display.
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 2bd22e8..33f949f 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1477,7 +1477,7 @@
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
- result = setTaskFromReuseOrCreateNewTask(taskToAffiliate, topStack);
+ result = setTaskFromReuseOrCreateNewTask(taskToAffiliate);
} else if (mSourceRecord != null) {
result = setTaskFromSourceRecord();
} else if (mInTask != null) {
@@ -1606,13 +1606,18 @@
mVoiceSession = voiceSession;
mVoiceInteractor = voiceInteractor;
- mPreferredDisplayId = getPreferedDisplayId(mSourceRecord, mStartActivity, options);
-
mLaunchParams.reset();
mSupervisor.getLaunchParamsController().calculate(inTask, null /*layout*/, r, sourceRecord,
options, mLaunchParams);
+ if (mLaunchParams.hasPreferredDisplay()) {
+ mPreferredDisplayId = mLaunchParams.mPreferredDisplayId;
+ } else {
+ mPreferredDisplayId = DEFAULT_DISPLAY;
+ }
+ ensureValidPreferredDisplayId(r);
+
mLaunchMode = r.launchMode;
mLaunchFlags = adjustLaunchFlagsToDocumentMode(
@@ -1704,6 +1709,24 @@
mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
}
+ /**
+ * Ensure preferred display ID matches the starting activity.
+ */
+ private void ensureValidPreferredDisplayId(ActivityRecord startingActivity) {
+ // Check if the Activity is a VR activity. If so, the activity should be launched in
+ // main display.
+ if (startingActivity != null && startingActivity.requestedVrComponent != null) {
+ mPreferredDisplayId = DEFAULT_DISPLAY;
+ }
+
+ // Get the virtual display ID from ActivityStackManagerService. If that's set we should
+ // always use that.
+ final int displayId = mService.mVr2dDisplayId;
+ if (displayId != INVALID_DISPLAY) {
+ mPreferredDisplayId = displayId;
+ }
+ }
+
private void sendNewTaskResultRequestIfNeeded() {
final ActivityStack sourceStack = mStartActivity.resultTo != null
? mStartActivity.resultTo.getStack() : null;
@@ -1883,44 +1906,6 @@
}
/**
- * Returns the ID of the display to use for a new activity. If the device is in VR mode,
- * then return the Vr mode's virtual display ID. If not, if the activity was started with
- * a launchDisplayId, use that. Otherwise, if the source activity has a explicit display ID
- * set, use that to launch the activity.
- */
- private int getPreferedDisplayId(
- ActivityRecord sourceRecord, ActivityRecord startingActivity, ActivityOptions options) {
- // Check if the Activity is a VR activity. If so, the activity should be launched in
- // main display.
- if (startingActivity != null && startingActivity.requestedVrComponent != null) {
- return DEFAULT_DISPLAY;
- }
-
- // Get the virtual display id from ActivityManagerService.
- int displayId = mService.mVr2dDisplayId;
- if (displayId != INVALID_DISPLAY) {
- if (DEBUG_STACK) {
- Slog.d(TAG, "getSourceDisplayId :" + displayId);
- }
- return displayId;
- }
-
- // If the caller requested a display, prefer that display.
- final int launchDisplayId =
- (options != null) ? options.getLaunchDisplayId() : INVALID_DISPLAY;
- if (launchDisplayId != INVALID_DISPLAY) {
- return launchDisplayId;
- }
-
- displayId = sourceRecord != null ? sourceRecord.getDisplayId() : INVALID_DISPLAY;
- // If the activity has a displayId set explicitly, launch it on the same displayId.
- if (displayId != INVALID_DISPLAY) {
- return displayId;
- }
- return DEFAULT_DISPLAY;
- }
-
- /**
* Figure out which task and activity to bring to front when we have found an existing matching
* activity record in history. May also clear the task if needed.
* @param intentActivity Existing matching activity.
@@ -2125,8 +2110,7 @@
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
}
- private int setTaskFromReuseOrCreateNewTask(
- TaskRecord taskToAffiliate, ActivityStack topStack) {
+ private int setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions);
// Do no move the target stack to front yet, as we might bail if
@@ -2431,17 +2415,6 @@
}
}
if (stack == null) {
- // We first try to put the task in the first dynamic stack on home display.
- final ActivityDisplay display = mSupervisor.getDefaultDisplay();
- for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- stack = display.getChildAt(stackNdx);
- if (!stack.isOnHomeDisplay()) {
- if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
- "computeStackFocus: Setting focused stack=" + stack);
- return stack;
- }
- }
- // If there is no suitable dynamic stack then we figure out which static stack to use.
stack = mSupervisor.getLaunchStack(r, aOptions, task, ON_TOP);
}
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 8e3eeae..4dd5a99 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -1707,7 +1707,7 @@
return;
}
final ActivityRecord r = stack.topRunningActivityLocked();
- if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedStack")) {
+ if (r != null && r.moveFocusableActivityToTop("setFocusedStack")) {
mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
}
}
@@ -1728,7 +1728,7 @@
return;
}
final ActivityRecord r = task.topRunningActivityLocked();
- if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedTask")) {
+ if (r != null && r.moveFocusableActivityToTop("setFocusedTask")) {
mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
}
}
@@ -5554,7 +5554,7 @@
throw new IllegalArgumentException(
"setFocusedActivity: No activity record matching token=" + token);
}
- if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedActivity")) {
+ if (r.moveFocusableActivityToTop("setFocusedActivity")) {
mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
}
}
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 2ca1344..09c152e 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -56,10 +56,6 @@
sGlobalSettingToTypeMap.put(Settings.Global.DEBUG_VIEW_ATTRIBUTES, int.class);
sGlobalSettingToTypeMap.put(Settings.Global.ANGLE_ENABLED_APP, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYERS, String.class);
- sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_LAYER_APP, String.class);
// add other global settings here...
}
diff --git a/services/core/java/com/android/server/am/LaunchParamsController.java b/services/core/java/com/android/server/am/LaunchParamsController.java
index 6415c3e..218d908 100644
--- a/services/core/java/com/android/server/am/LaunchParamsController.java
+++ b/services/core/java/com/android/server/am/LaunchParamsController.java
@@ -16,6 +16,13 @@
package com.android.server.am;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.view.Display.INVALID_DISPLAY;
+
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
+import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
+
import android.annotation.IntDef;
import android.app.ActivityOptions;
import android.content.pm.ActivityInfo.WindowLayout;
@@ -26,13 +33,6 @@
import java.util.ArrayList;
import java.util.List;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.view.Display.INVALID_DISPLAY;
-
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
-
/**
* {@link LaunchParamsController} calculates the {@link LaunchParams} by coordinating between
* registered {@link LaunchParamsModifier}s.
@@ -58,11 +58,7 @@
*/
void registerDefaultModifiers(ActivityStackSupervisor supervisor) {
// {@link TaskLaunchParamsModifier} handles window layout preferences.
- registerModifier(new TaskLaunchParamsModifier());
-
- // {@link ActivityLaunchParamsModifier} is the most specific modifier and thus should be
- // registered last (applied first) out of the defaults.
- registerModifier(new ActivityLaunchParamsModifier(supervisor));
+ registerModifier(new TaskLaunchParamsModifier(supervisor));
}
/**
@@ -226,27 +222,41 @@
@IntDef({RESULT_SKIP, RESULT_DONE, RESULT_CONTINUE})
@interface Result {}
- // Returned when the modifier does not want to influence the bounds calculation
+ /** Returned when the modifier does not want to influence the bounds calculation */
int RESULT_SKIP = 0;
- // Returned when the modifier has changed the bounds and would like its results to be the
- // final bounds applied.
+ /**
+ * Returned when the modifier has changed the bounds and would like its results to be the
+ * final bounds applied.
+ */
int RESULT_DONE = 1;
- // Returned when the modifier has changed the bounds but is okay with other modifiers
- // influencing the bounds.
+ /**
+ * Returned when the modifier has changed the bounds but is okay with other modifiers
+ * influencing the bounds.
+ */
int RESULT_CONTINUE = 2;
/**
- * Called when asked to calculate {@link LaunchParams}.
- * @param task The {@link TaskRecord} currently being positioned.
- * @param layout The specified {@link WindowLayout}.
- * @param activity The {@link ActivityRecord} currently being positioned.
- * @param source The {@link ActivityRecord} activity was started from.
- * @param options The {@link ActivityOptions} specified for the activity.
- * @param currentParams The current {@link LaunchParams}. This can differ from the initial
- * params as it represents the modified params up to this point.
- * @param outParams The resulting {@link LaunchParams} after all calculations.
- * @return A {@link Result} representing the result of the
- * {@link LaunchParams} calculation.
+ * Returns the launch params that the provided activity launch params should be overridden
+ * to. {@link LaunchParamsModifier} can use this for various purposes, including: 1)
+ * Providing default bounds if the launch bounds have not been provided. 2) Repositioning
+ * the task so it doesn't get placed over an existing task. 3) Resizing the task so that its
+ * dimensions match the activity's requested orientation.
+ *
+ * @param task Can be: 1) the target task in which the source activity wants to
+ * launch the target activity; 2) a newly created task that Android
+ * gives a chance to override its launching bounds; 3) {@code null} if
+ * this is called to override an activity's launching bounds.
+ * @param layout Desired layout when activity is first launched.
+ * @param activity Activity that is being started. This can be {@code null} on
+ * re-parenting an activity to a new task (e.g. for
+ * Picture-In-Picture). Tasks being created because an activity was
+ * launched should have this be non-null.
+ * @param source the Activity that launched a new task. Could be {@code null}.
+ * @param options {@link ActivityOptions} used to start the activity with.
+ * @param currentParams launching params after the process of last {@link
+ * LaunchParamsModifier}.
+ * @param outParams the result params to be set.
+ * @return see {@link LaunchParamsModifier.Result}
*/
@Result
int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
diff --git a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
index 92f1cc3..fd34d18 100644
--- a/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/am/TaskLaunchParamsModifier.java
@@ -16,304 +16,770 @@
package com.android.server.am;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityOptions;
+import android.app.WindowConfiguration;
import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
import android.graphics.Rect;
+import android.os.Build;
import android.util.Slog;
import android.view.Gravity;
-import com.android.internal.annotations.VisibleForTesting;
+
import com.android.server.am.LaunchParamsController.LaunchParams;
import com.android.server.am.LaunchParamsController.LaunchParamsModifier;
import java.util.ArrayList;
+import java.util.List;
/**
- * Determines where a launching task should be positioned and sized on the display.
- *
- * The modifier is fairly simple. For the new task it tries default position based on the gravity
- * and compares corners of the task with corners of existing tasks. If some two pairs of corners are
- * sufficiently close enough, it shifts the bounds of the new task and tries again. When it exhausts
- * all possible shifts, it gives up and puts the task in the original position.
- *
- * Note that the only gravities of concern are the corners and the center.
+ * The class that defines the default launch params for tasks.
*/
class TaskLaunchParamsModifier implements LaunchParamsModifier {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskLaunchParamsModifier" : TAG_AM;
+ private static final boolean DEBUG = false;
- // Determines how close window frames/corners have to be to call them colliding.
- private static final int BOUNDS_CONFLICT_MIN_DISTANCE = 4;
+ // A mask for SUPPORTS_SCREEN that indicates the activity supports resize.
+ private static final int SUPPORTS_SCREEN_RESIZEABLE_MASK =
+ ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
+ | ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS
+ | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS
+ | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS
+ | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES
+ | ApplicationInfo.FLAG_SUPPORTS_XLARGE_SCREENS;
- // Task will receive dimensions based on available dimensions divided by this.
- private static final int WINDOW_SIZE_DENOMINATOR = 2;
+ // Screen size of Nexus 5x
+ private static final int DEFAULT_PORTRAIT_PHONE_WIDTH_DP = 412;
+ private static final int DEFAULT_PORTRAIT_PHONE_HEIGHT_DP = 732;
- // Task will receive margins based on available dimensions divided by this.
- private static final int MARGIN_SIZE_DENOMINATOR = 4;
+ // Allowance of size matching.
+ private static final int EPSILON = 2;
- // If task bounds collide with some other, we will step and try again until we find a good
- // position. The step will be determined by using dimensions and dividing it by this.
+ // Cascade window offset.
+ private static final int CASCADING_OFFSET_DP = 75;
+
+ // Threshold how close window corners have to be to call them colliding.
+ private static final int BOUNDS_CONFLICT_THRESHOLD = 4;
+
+ // Divide display size by this number to get each step to adjust bounds to avoid conflict.
private static final int STEP_DENOMINATOR = 16;
// We always want to step by at least this.
private static final int MINIMAL_STEP = 1;
- // Used to indicate if positioning algorithm is allowed to restart from the beginning, when it
- // reaches the end of stack bounds.
- private static final boolean ALLOW_RESTART = true;
+ private final ActivityStackSupervisor mSupervisor;
+ private final Rect mTmpBounds = new Rect();
+ private final int[] mTmpDirections = new int[2];
- private static final int SHIFT_POLICY_DIAGONAL_DOWN = 1;
- private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2;
- private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3;
+ private StringBuilder mLogBuilder;
- private final Rect mAvailableRect = new Rect();
- private final Rect mTmpProposal = new Rect();
- private final Rect mTmpOriginal = new Rect();
+ TaskLaunchParamsModifier(ActivityStackSupervisor supervisor) {
+ mSupervisor = supervisor;
+ }
- /**
- * Tries to set task's bound in a way that it won't collide with any other task. By colliding
- * we mean that two tasks have left-top corner very close to each other, so one might get
- * obfuscated by the other one.
- */
@Override
public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
ActivityRecord activity, ActivityRecord source, ActivityOptions options,
LaunchParams currentParams, LaunchParams outParams) {
- // We can only apply positioning if we're in a freeform stack.
- if (task == null || task.getStack() == null || !task.inFreeformWindowingMode()) {
- return RESULT_SKIP;
+ initLogBuilder(task, activity);
+ final int result = calculate(task, layout, activity, source, options, currentParams,
+ outParams);
+ outputLog();
+ return result;
+ }
+
+ private int calculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+ ActivityRecord activity, ActivityRecord source, ActivityOptions options,
+ LaunchParams currentParams, LaunchParams outParams) {
+ // STEP 1: Determine the display to launch the activity/task.
+ final int displayId = getPreferredLaunchDisplay(options, source, currentParams);
+ outParams.mPreferredDisplayId = displayId;
+ ActivityDisplay display = mSupervisor.getActivityDisplay(displayId);
+ if (DEBUG) {
+ appendLog("display-id=" + outParams.mPreferredDisplayId + " display-windowing-mode="
+ + display.getWindowingMode());
}
- final ArrayList<TaskRecord> tasks = task.getStack().getAllTasks();
-
- mAvailableRect.set(task.getParent().getBounds());
-
- final Rect resultBounds = outParams.mBounds;
-
- if (layout == null) {
- positionCenter(tasks, mAvailableRect, getFreeformWidth(mAvailableRect),
- getFreeformHeight(mAvailableRect), resultBounds);
- return RESULT_CONTINUE;
+ final ActivityRecord root;
+ if (task != null) {
+ root = (task.getRootActivity() == null ? activity : task.getRootActivity());
+ } else {
+ root = activity;
}
-
- int width = getFinalWidth(layout, mAvailableRect);
- int height = getFinalHeight(layout, mAvailableRect);
- int verticalGravity = layout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
- int horizontalGravity = layout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
- if (verticalGravity == Gravity.TOP) {
- if (horizontalGravity == Gravity.RIGHT) {
- positionTopRight(tasks, mAvailableRect, width, height, resultBounds);
+ // STEP 2: Resolve launch windowing mode.
+ // STEP 2.1: Determine if any parameter has specified initial bounds. That might be the
+ // launch bounds from activity options, or size/gravity passed in layout. It also treat the
+ // launch windowing mode in options as a suggestion for future resolution.
+ int launchMode = options != null ? options.getLaunchWindowingMode()
+ : WINDOWING_MODE_UNDEFINED;
+ // hasInitialBounds is set if either activity options or layout has specified bounds. If
+ // that's set we'll skip some adjustments later to avoid overriding the initial bounds.
+ boolean hasInitialBounds = false;
+ final boolean canApplyFreeformPolicy =
+ canApplyFreeformWindowPolicy(display, root, launchMode);
+ if (mSupervisor.canUseActivityOptionsLaunchBounds(options) && canApplyFreeformPolicy) {
+ hasInitialBounds = true;
+ launchMode = launchMode == WINDOWING_MODE_UNDEFINED
+ ? WINDOWING_MODE_FREEFORM
+ : launchMode;
+ outParams.mBounds.set(options.getLaunchBounds());
+ if (DEBUG) appendLog("activity-options-bounds=" + outParams.mBounds);
+ } else if (launchMode == WINDOWING_MODE_PINNED) {
+ // System controls PIP window's bounds, so don't apply launch bounds.
+ if (DEBUG) appendLog("empty-window-layout-for-pip");
+ } else if (launchMode == WINDOWING_MODE_FULLSCREEN) {
+ if (DEBUG) appendLog("activity-options-fullscreen=" + outParams.mBounds);
+ } else if (layout != null && canApplyFreeformPolicy) {
+ getLayoutBounds(display, root, layout, mTmpBounds);
+ if (!mTmpBounds.isEmpty()) {
+ launchMode = WINDOWING_MODE_FREEFORM;
+ outParams.mBounds.set(mTmpBounds);
+ hasInitialBounds = true;
+ if (DEBUG) appendLog("bounds-from-layout=" + outParams.mBounds);
} else {
- positionTopLeft(tasks, mAvailableRect, width, height, resultBounds);
+ if (DEBUG) appendLog("empty-window-layout");
}
- } else if (verticalGravity == Gravity.BOTTOM) {
- if (horizontalGravity == Gravity.RIGHT) {
- positionBottomRight(tasks, mAvailableRect, width, height, resultBounds);
- } else {
- positionBottomLeft(tasks, mAvailableRect, width, height, resultBounds);
+ }
+
+ // STEP 2.2: Check if previous modifier or the controller (referred as "callers" below) has
+ // some opinions on launch mode and launch bounds. If they have opinions and there is no
+ // initial bounds set in parameters. Note the check on display ID is also input param
+ // related because we always defer to callers' suggestion if there is no specific display ID
+ // in options or from source activity.
+ //
+ // If opinions from callers don't need any further resolution, we try to honor that as is as
+ // much as possible later.
+
+ // Flag to indicate if current param needs no further resolution. It's true it current
+ // param isn't freeform mode, or it already has launch bounds.
+ boolean fullyResolvedCurrentParam = false;
+ // We inherit launch params from previous modifiers or LaunchParamsController if options,
+ // layout and display conditions are not contradictory to their suggestions. It's important
+ // to carry over their values because LaunchParamsController doesn't automatically do that.
+ if (!currentParams.isEmpty() && !hasInitialBounds
+ && (!currentParams.hasPreferredDisplay()
+ || displayId == currentParams.mPreferredDisplayId)) {
+ if (currentParams.hasWindowingMode()) {
+ launchMode = currentParams.mWindowingMode;
+ fullyResolvedCurrentParam = (launchMode != WINDOWING_MODE_FREEFORM);
+ if (DEBUG) {
+ appendLog("inherit-" + WindowConfiguration.windowingModeToString(launchMode));
+ }
+ }
+
+ if (!currentParams.mBounds.isEmpty()) {
+ outParams.mBounds.set(currentParams.mBounds);
+ fullyResolvedCurrentParam = true;
+ if (DEBUG) appendLog("inherit-bounds=" + outParams.mBounds);
+ }
+ }
+
+ // STEP 2.3: Adjust launch parameters as needed for freeform display. We enforce the policy
+ // that legacy (pre-D) apps and those apps that can't handle multiple screen density well
+ // are forced to be maximized. The rest of this step is to define the default policy when
+ // there is no initial bounds or a fully resolved current params from callers. Right now we
+ // launch all possible tasks/activities that can handle freeform into freeform mode.
+ if (display.inFreeformWindowingMode()) {
+ if (launchMode == WINDOWING_MODE_PINNED) {
+ if (DEBUG) appendLog("picture-in-picture");
+ } else if (isTaskForcedMaximized(root)) {
+ // We're launching an activity that probably can't handle resizing nicely, so force
+ // it to be maximized even someone suggests launching it in freeform using launch
+ // options.
+ launchMode = WINDOWING_MODE_FULLSCREEN;
+ outParams.mBounds.setEmpty();
+ if (DEBUG) appendLog("forced-maximize");
+ } else if (fullyResolvedCurrentParam) {
+ // Don't adjust launch mode if that's inherited, except when we're launching an
+ // activity that should be forced to maximize.
+ if (DEBUG) appendLog("skip-adjustment-fully-resolved-params");
+ } else if (launchMode != WINDOWING_MODE_FREEFORM
+ && (isNOrGreater(root) || isPreNResizeable(root))) {
+ // We're launching a pre-N and post-D activity that supports resizing, or a post-N
+ // activity. They can handle freeform nicely so launch them in freeform.
+ // Use undefined because we know we're in a freeform display.
+ launchMode = WINDOWING_MODE_UNDEFINED;
+ if (DEBUG) appendLog("should-be-freeform");
}
} else {
- // Some fancy gravity setting that we don't support yet. We just put the activity in the
- // center.
- Slog.w(TAG, "Received unsupported gravity: " + layout.gravity
- + ", positioning in the center instead.");
- positionCenter(tasks, mAvailableRect, width, height, resultBounds);
+ if (DEBUG) appendLog("non-freeform-display");
+ }
+ // If launch mode matches display windowing mode, let it inherit from display.
+ outParams.mWindowingMode = launchMode == display.getWindowingMode()
+ ? WINDOWING_MODE_UNDEFINED : launchMode;
+
+ // STEP 3: Determine final launch bounds based on resolved windowing mode and activity
+ // requested orientation. We set bounds to empty for fullscreen mode and keep bounds as is
+ // for all other windowing modes that's not freeform mode. One can read comments in
+ // relevant methods to further understand this step.
+ //
+ // We skip making adjustments if the params are fully resolved from previous results and
+ // trust that they are valid.
+ if (!fullyResolvedCurrentParam) {
+ final int resolvedMode = (launchMode != WINDOWING_MODE_UNDEFINED) ? launchMode
+ : display.getWindowingMode();
+ if (source != null && source.inFreeformWindowingMode()
+ && resolvedMode == WINDOWING_MODE_FREEFORM
+ && outParams.mBounds.isEmpty()
+ && source.getDisplayId() == display.mDisplayId) {
+ // Set bounds to be not very far from source activity.
+ cascadeBounds(source.getBounds(), display, outParams.mBounds);
+ }
+ getTaskBounds(root, display, layout, resolvedMode, hasInitialBounds, outParams.mBounds);
}
return RESULT_CONTINUE;
}
- @VisibleForTesting
- static int getFreeformStartLeft(Rect bounds) {
- return bounds.left + bounds.width() / MARGIN_SIZE_DENOMINATOR;
- }
-
- @VisibleForTesting
- static int getFreeformStartTop(Rect bounds) {
- return bounds.top + bounds.height() / MARGIN_SIZE_DENOMINATOR;
- }
-
- @VisibleForTesting
- static int getFreeformWidth(Rect bounds) {
- return bounds.width() / WINDOW_SIZE_DENOMINATOR;
- }
-
- @VisibleForTesting
- static int getFreeformHeight(Rect bounds) {
- return bounds.height() / WINDOW_SIZE_DENOMINATOR;
- }
-
- @VisibleForTesting
- static int getHorizontalStep(Rect bounds) {
- return Math.max(bounds.width() / STEP_DENOMINATOR, MINIMAL_STEP);
- }
-
- @VisibleForTesting
- static int getVerticalStep(Rect bounds) {
- return Math.max(bounds.height() / STEP_DENOMINATOR, MINIMAL_STEP);
- }
-
-
-
- private int getFinalWidth(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
- int width = getFreeformWidth(availableRect);
- if (windowLayout.width > 0) {
- width = windowLayout.width;
+ private int getPreferredLaunchDisplay(@Nullable ActivityOptions options,
+ ActivityRecord source, LaunchParams currentParams) {
+ int displayId = INVALID_DISPLAY;
+ final int optionLaunchId = options != null ? options.getLaunchDisplayId() : INVALID_DISPLAY;
+ if (optionLaunchId != INVALID_DISPLAY) {
+ if (DEBUG) appendLog("display-from-option=" + optionLaunchId);
+ displayId = optionLaunchId;
}
- if (windowLayout.widthFraction > 0) {
- width = (int) (availableRect.width() * windowLayout.widthFraction);
+
+ if (displayId == INVALID_DISPLAY && source != null) {
+ final int sourceDisplayId = source.getDisplayId();
+ if (DEBUG) appendLog("display-from-source=" + sourceDisplayId);
+ displayId = sourceDisplayId;
}
- return width;
- }
- private int getFinalHeight(ActivityInfo.WindowLayout windowLayout, Rect availableRect) {
- int height = getFreeformHeight(availableRect);
- if (windowLayout.height > 0) {
- height = windowLayout.height;
+ if (displayId != INVALID_DISPLAY && mSupervisor.getActivityDisplay(displayId) == null) {
+ displayId = INVALID_DISPLAY;
}
- if (windowLayout.heightFraction > 0) {
- height = (int) (availableRect.height() * windowLayout.heightFraction);
+ displayId = (displayId == INVALID_DISPLAY) ? currentParams.mPreferredDisplayId : displayId;
+
+ displayId = (displayId == INVALID_DISPLAY) ? DEFAULT_DISPLAY : displayId;
+
+ return displayId;
+ }
+
+ private boolean canApplyFreeformWindowPolicy(@NonNull ActivityDisplay display,
+ @NonNull ActivityRecord root, int launchMode) {
+ return display.inFreeformWindowingMode() || launchMode == WINDOWING_MODE_FREEFORM
+ || root.isResizeable();
+ }
+
+ private void getLayoutBounds(@NonNull ActivityDisplay display, @NonNull ActivityRecord root,
+ @NonNull ActivityInfo.WindowLayout windowLayout, @NonNull Rect outBounds) {
+ final int verticalGravity = windowLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+ final int horizontalGravity = windowLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+ if (!windowLayout.hasSpecifiedSize() && verticalGravity == 0 && horizontalGravity == 0) {
+ outBounds.setEmpty();
+ return;
}
- return height;
- }
- private void positionBottomLeft(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.left, availableRect.bottom - height,
- availableRect.left + width, availableRect.bottom);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT,
- result);
- }
+ final Rect bounds = display.getBounds();
+ final int defaultWidth = bounds.width();
+ final int defaultHeight = bounds.height();
- private void positionBottomRight(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.right - width, availableRect.bottom - height,
- availableRect.right, availableRect.bottom);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT,
- result);
- }
-
- private void positionTopLeft(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.left, availableRect.top,
- availableRect.left + width, availableRect.top + height);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT,
- result);
- }
-
- private void positionTopRight(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- mTmpProposal.set(availableRect.right - width, availableRect.top,
- availableRect.right, availableRect.top + height);
- position(tasks, availableRect, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT,
- result);
- }
-
- private void positionCenter(ArrayList<TaskRecord> tasks, Rect availableRect, int width,
- int height, Rect result) {
- final int defaultFreeformLeft = getFreeformStartLeft(availableRect);
- final int defaultFreeformTop = getFreeformStartTop(availableRect);
- mTmpProposal.set(defaultFreeformLeft, defaultFreeformTop,
- defaultFreeformLeft + width, defaultFreeformTop + height);
- position(tasks, availableRect, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN,
- result);
- }
-
- private void position(ArrayList<TaskRecord> tasks, Rect availableRect,
- Rect proposal, boolean allowRestart, int shiftPolicy, Rect result) {
- mTmpOriginal.set(proposal);
- boolean restarted = false;
- while (boundsConflict(proposal, tasks)) {
- // Unfortunately there is already a task at that spot, so we need to look for some
- // other place.
- shiftStartingPoint(proposal, availableRect, shiftPolicy);
- if (shiftedTooFar(proposal, availableRect, shiftPolicy)) {
- // We don't want the task to go outside of the stack, because it won't look
- // nice. Depending on the starting point we either restart, or immediately give up.
- if (!allowRestart) {
- proposal.set(mTmpOriginal);
- break;
- }
- // We must have started not from the top. Let's restart from there because there
- // might be some space there.
- proposal.set(availableRect.left, availableRect.top,
- availableRect.left + proposal.width(),
- availableRect.top + proposal.height());
- restarted = true;
+ int width;
+ int height;
+ if (!windowLayout.hasSpecifiedSize()) {
+ outBounds.setEmpty();
+ getTaskBounds(root, display, windowLayout, WINDOWING_MODE_FREEFORM,
+ /* hasInitialBounds */ false, outBounds);
+ width = outBounds.width();
+ height = outBounds.height();
+ } else {
+ width = defaultWidth;
+ if (windowLayout.width > 0 && windowLayout.width < defaultWidth) {
+ width = windowLayout.width;
+ } else if (windowLayout.widthFraction > 0 && windowLayout.widthFraction < 1.0f) {
+ width = (int) (width * windowLayout.widthFraction);
}
- if (restarted && (proposal.left > getFreeformStartLeft(availableRect)
- || proposal.top > getFreeformStartTop(availableRect))) {
- // If we restarted and crossed the initial position, let's not struggle anymore.
- // The user already must have ton of tasks visible, we can just smack the new
- // one in the center.
- proposal.set(mTmpOriginal);
- break;
+
+ height = defaultHeight;
+ if (windowLayout.height > 0 && windowLayout.height < defaultHeight) {
+ height = windowLayout.height;
+ } else if (windowLayout.heightFraction > 0 && windowLayout.heightFraction < 1.0f) {
+ height = (int) (height * windowLayout.heightFraction);
}
}
- result.set(proposal);
- }
- private boolean shiftedTooFar(Rect start, Rect availableRect, int shiftPolicy) {
- switch (shiftPolicy) {
- case SHIFT_POLICY_HORIZONTAL_LEFT:
- return start.left < availableRect.left;
- case SHIFT_POLICY_HORIZONTAL_RIGHT:
- return start.right > availableRect.right;
- default: // SHIFT_POLICY_DIAGONAL_DOWN
- return start.right > availableRect.right || start.bottom > availableRect.bottom;
+ final float fractionOfHorizontalOffset;
+ switch (horizontalGravity) {
+ case Gravity.LEFT:
+ fractionOfHorizontalOffset = 0f;
+ break;
+ case Gravity.RIGHT:
+ fractionOfHorizontalOffset = 1f;
+ break;
+ default:
+ fractionOfHorizontalOffset = 0.5f;
}
- }
- private void shiftStartingPoint(Rect posposal, Rect availableRect, int shiftPolicy) {
- final int defaultFreeformStepHorizontal = getHorizontalStep(availableRect);
- final int defaultFreeformStepVertical = getVerticalStep(availableRect);
-
- switch (shiftPolicy) {
- case SHIFT_POLICY_HORIZONTAL_LEFT:
- posposal.offset(-defaultFreeformStepHorizontal, 0);
+ final float fractionOfVerticalOffset;
+ switch (verticalGravity) {
+ case Gravity.TOP:
+ fractionOfVerticalOffset = 0f;
break;
- case SHIFT_POLICY_HORIZONTAL_RIGHT:
- posposal.offset(defaultFreeformStepHorizontal, 0);
+ case Gravity.BOTTOM:
+ fractionOfVerticalOffset = 1f;
break;
- default: // SHIFT_POLICY_DIAGONAL_DOWN:
- posposal.offset(defaultFreeformStepHorizontal, defaultFreeformStepVertical);
- break;
+ default:
+ fractionOfVerticalOffset = 0.5f;
}
+
+ outBounds.set(0, 0, width, height);
+ final int xOffset = (int) (fractionOfHorizontalOffset * (defaultWidth - width));
+ final int yOffset = (int) (fractionOfVerticalOffset * (defaultHeight - height));
+ outBounds.offset(xOffset, yOffset);
}
- private static boolean boundsConflict(Rect proposal, ArrayList<TaskRecord> tasks) {
- for (int i = tasks.size() - 1; i >= 0; i--) {
- final TaskRecord task = tasks.get(i);
- if (!task.mActivities.isEmpty() && !task.matchParentBounds()) {
- final Rect bounds = task.getOverrideBounds();
- if (closeLeftTopCorner(proposal, bounds) || closeRightTopCorner(proposal, bounds)
- || closeLeftBottomCorner(proposal, bounds)
- || closeRightBottomCorner(proposal, bounds)) {
- return true;
- }
+ /**
+ * Returns if task is forced to maximize.
+ *
+ * There are several cases where we force a task to maximize:
+ * 1) Root activity is targeting pre-Donut, which by default can't handle multiple screen
+ * densities, so resizing will likely cause issues;
+ * 2) Root activity doesn't declare any flag that it supports any screen density, so resizing
+ * may also cause issues;
+ * 3) Root activity is not resizeable, for which we shouldn't allow user resize it.
+ *
+ * @param root the root activity to check against.
+ * @return {@code true} if it should be forced to maximize; {@code false} otherwise.
+ */
+ private boolean isTaskForcedMaximized(@NonNull ActivityRecord root) {
+ if (root.appInfo.targetSdkVersion < Build.VERSION_CODES.DONUT
+ || (root.appInfo.flags & SUPPORTS_SCREEN_RESIZEABLE_MASK) == 0) {
+ return true;
+ }
+
+ return !root.isResizeable();
+ }
+
+ private boolean isNOrGreater(@NonNull ActivityRecord root) {
+ return root.appInfo.targetSdkVersion >= Build.VERSION_CODES.N;
+ }
+
+ /**
+ * Resolves activity requested orientation to 4 categories:
+ * 1) {@link ActivityInfo#SCREEN_ORIENTATION_LOCKED} indicating app wants to lock down
+ * orientation;
+ * 2) {@link ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE} indicating app wants to be in landscape;
+ * 3) {@link ActivityInfo#SCREEN_ORIENTATION_PORTRAIT} indicating app wants to be in portrait;
+ * 4) {@link ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED} indicating app can handle any
+ * orientation.
+ *
+ * @param activity the activity to check
+ * @return corresponding resolved orientation value.
+ */
+ private int resolveOrientation(@NonNull ActivityRecord activity) {
+ int orientation = activity.info.screenOrientation;
+ switch (orientation) {
+ case SCREEN_ORIENTATION_NOSENSOR:
+ case SCREEN_ORIENTATION_LOCKED:
+ orientation = SCREEN_ORIENTATION_LOCKED;
+ break;
+ case SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
+ case SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
+ case SCREEN_ORIENTATION_USER_LANDSCAPE:
+ case SCREEN_ORIENTATION_LANDSCAPE:
+ if (DEBUG) appendLog("activity-requested-landscape");
+ orientation = SCREEN_ORIENTATION_LANDSCAPE;
+ break;
+ case SCREEN_ORIENTATION_SENSOR_PORTRAIT:
+ case SCREEN_ORIENTATION_REVERSE_PORTRAIT:
+ case SCREEN_ORIENTATION_USER_PORTRAIT:
+ case SCREEN_ORIENTATION_PORTRAIT:
+ if (DEBUG) appendLog("activity-requested-portrait");
+ orientation = SCREEN_ORIENTATION_PORTRAIT;
+ break;
+ default:
+ orientation = SCREEN_ORIENTATION_UNSPECIFIED;
+ }
+
+ return orientation;
+ }
+
+ private boolean isPreNResizeable(ActivityRecord root) {
+ return root.appInfo.targetSdkVersion < Build.VERSION_CODES.N && root.isResizeable();
+ }
+
+ private void cascadeBounds(@NonNull Rect srcBounds, @NonNull ActivityDisplay display,
+ @NonNull Rect outBounds) {
+ outBounds.set(srcBounds);
+ float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+ final int defaultOffset = (int) (CASCADING_OFFSET_DP * density + 0.5f);
+
+ display.getBounds(mTmpBounds);
+ final int dx = Math.min(defaultOffset, Math.max(0, mTmpBounds.right - srcBounds.right));
+ final int dy = Math.min(defaultOffset, Math.max(0, mTmpBounds.bottom - srcBounds.bottom));
+ outBounds.offset(dx, dy);
+ }
+
+ private void getTaskBounds(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+ @NonNull ActivityInfo.WindowLayout layout, int resolvedMode, boolean hasInitialBounds,
+ @NonNull Rect inOutBounds) {
+ if (resolvedMode == WINDOWING_MODE_FULLSCREEN) {
+ // We don't handle letterboxing here. Letterboxing will be handled by valid checks
+ // later.
+ inOutBounds.setEmpty();
+ if (DEBUG) appendLog("maximized-bounds");
+ return;
+ }
+
+ if (resolvedMode != WINDOWING_MODE_FREEFORM) {
+ // We don't apply freeform bounds adjustment to other windowing modes.
+ if (DEBUG) {
+ appendLog("skip-bounds-" + WindowConfiguration.windowingModeToString(resolvedMode));
+ }
+ return;
+ }
+
+ final int orientation = resolveOrientation(root, display, inOutBounds);
+ if (orientation != SCREEN_ORIENTATION_PORTRAIT
+ && orientation != SCREEN_ORIENTATION_LANDSCAPE) {
+ throw new IllegalStateException(
+ "Orientation must be one of portrait or landscape, but it's "
+ + ActivityInfo.screenOrientationToString(orientation));
+ }
+
+ // First we get the default size we want.
+ getDefaultFreeformSize(display, layout, orientation, mTmpBounds);
+ if (hasInitialBounds || sizeMatches(inOutBounds, mTmpBounds)) {
+ // We're here because either input parameters specified initial bounds, or the suggested
+ // bounds have the same size of the default freeform size. We should use the suggested
+ // bounds if possible -- so if app can handle the orientation we just use it, and if not
+ // we transpose the suggested bounds in-place.
+ if (orientation == orientationFromBounds(inOutBounds)) {
+ if (DEBUG) appendLog("freeform-size-orientation-match=" + inOutBounds);
+ } else {
+ // Meh, orientation doesn't match. Let's rotate inOutBounds in-place.
+ centerBounds(display, inOutBounds.height(), inOutBounds.width(), inOutBounds);
+ if (DEBUG) appendLog("freeform-orientation-mismatch=" + inOutBounds);
+ }
+ } else {
+ // We are here either because there is no suggested bounds, or the suggested bounds is
+ // a cascade from source activity. We should use the default freeform size and center it
+ // to the center of suggested bounds (or the display if no suggested bounds). The
+ // default size might be too big to center to source activity bounds in display, so we
+ // may need to move it back to the display.
+ centerBounds(display, mTmpBounds.width(), mTmpBounds.height(), inOutBounds);
+ adjustBoundsToFitInDisplay(display, inOutBounds);
+ if (DEBUG) appendLog("freeform-size-mismatch=" + inOutBounds);
+ }
+
+ // Lastly we adjust bounds to avoid conflicts with other tasks as much as possible.
+ adjustBoundsToAvoidConflict(display, inOutBounds);
+ }
+
+ private int resolveOrientation(@NonNull ActivityRecord root, @NonNull ActivityDisplay display,
+ @NonNull Rect bounds) {
+ int orientation = resolveOrientation(root);
+
+ if (orientation == SCREEN_ORIENTATION_LOCKED) {
+ orientation = bounds.isEmpty() ? display.getConfiguration().orientation
+ : orientationFromBounds(bounds);
+ if (DEBUG) {
+ appendLog(bounds.isEmpty() ? "locked-orientation-from-display=" + orientation
+ : "locked-orientation-from-bounds=" + bounds);
}
}
+
+ if (orientation == SCREEN_ORIENTATION_UNSPECIFIED) {
+ orientation = bounds.isEmpty() ? SCREEN_ORIENTATION_PORTRAIT
+ : orientationFromBounds(bounds);
+ if (DEBUG) {
+ appendLog(bounds.isEmpty() ? "default-portrait"
+ : "orientation-from-bounds=" + bounds);
+ }
+ }
+
+ return orientation;
+ }
+
+ private void getDefaultFreeformSize(@NonNull ActivityDisplay display,
+ @NonNull ActivityInfo.WindowLayout layout, int orientation, @NonNull Rect bounds) {
+ // Default size, which is letterboxing/pillarboxing in display. That's to say the large
+ // dimension of default size is the small dimension of display size, and the small dimension
+ // of default size is calculated to keep the same aspect ratio as the display's.
+ Rect displayBounds = display.getBounds();
+ final int portraitHeight = Math.min(displayBounds.width(), displayBounds.height());
+ final int otherDimension = Math.max(displayBounds.width(), displayBounds.height());
+ final int portraitWidth = (portraitHeight * portraitHeight) / otherDimension;
+ final int defaultWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitHeight
+ : portraitWidth;
+ final int defaultHeight = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? portraitWidth
+ : portraitHeight;
+
+ // Get window size based on Nexus 5x screen, we assume that this is enough to show content
+ // of activities.
+ final float density = (float) display.getConfiguration().densityDpi / DENSITY_DEFAULT;
+ final int phonePortraitWidth = (int) (DEFAULT_PORTRAIT_PHONE_WIDTH_DP * density + 0.5f);
+ final int phonePortraitHeight = (int) (DEFAULT_PORTRAIT_PHONE_HEIGHT_DP * density + 0.5f);
+ final int phoneWidth = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? phonePortraitHeight
+ : phonePortraitWidth;
+ final int phoneHeight = (orientation == SCREEN_ORIENTATION_LANDSCAPE) ? phonePortraitWidth
+ : phonePortraitHeight;
+
+ // Minimum layout requirements.
+ final int layoutMinWidth = (layout == null) ? -1 : layout.minWidth;
+ final int layoutMinHeight = (layout == null) ? -1 : layout.minHeight;
+
+ // Final result.
+ final int width = Math.min(defaultWidth, Math.max(phoneWidth, layoutMinWidth));
+ final int height = Math.min(defaultHeight, Math.max(phoneHeight, layoutMinHeight));
+
+ bounds.set(0, 0, width, height);
+ }
+
+ /**
+ * Gets centered bounds of width x height. If inOutBounds is not empty, the result bounds
+ * centers at its center or display's center if inOutBounds is empty.
+ */
+ private void centerBounds(@NonNull ActivityDisplay display, int width, int height,
+ @NonNull Rect inOutBounds) {
+ if (inOutBounds.isEmpty()) {
+ display.getBounds(inOutBounds);
+ }
+ final int left = inOutBounds.centerX() - width / 2;
+ final int top = inOutBounds.centerY() - height / 2;
+ inOutBounds.set(left, top, left + width, top + height);
+ }
+
+ private void adjustBoundsToFitInDisplay(@NonNull ActivityDisplay display,
+ @NonNull Rect inOutBounds) {
+ final Rect displayBounds = display.getBounds();
+
+ if (displayBounds.width() < inOutBounds.width()
+ || displayBounds.height() < inOutBounds.height()) {
+ // There is no way for us to fit the bounds in the display without changing width
+ // or height. Don't even try it.
+ return;
+ }
+
+ final int dx;
+ if (inOutBounds.right > displayBounds.right) {
+ // Right edge is out of display.
+ dx = displayBounds.right - inOutBounds.right;
+ } else if (inOutBounds.left < displayBounds.left) {
+ // Left edge is out of display.
+ dx = displayBounds.left - inOutBounds.left;
+ } else {
+ // Vertical edges are all in display.
+ dx = 0;
+ }
+
+ final int dy;
+ if (inOutBounds.top < displayBounds.top) {
+ // Top edge is out of display.
+ dy = displayBounds.top - inOutBounds.top;
+ } else if (inOutBounds.bottom > displayBounds.bottom) {
+ // Bottom edge is out of display.
+ dy = displayBounds.bottom - inOutBounds.bottom;
+ } else {
+ // Horizontal edges are all in display.
+ dy = 0;
+ }
+ inOutBounds.offset(dx, dy);
+ }
+
+ /**
+ * Adjusts input bounds to avoid conflict with existing tasks in the display.
+ *
+ * If the input bounds conflict with existing tasks, this method scans the bounds in a series of
+ * directions to find a location where the we can put the bounds in display without conflict
+ * with any other tasks.
+ *
+ * It doesn't try to adjust bounds that's not fully in the given display.
+ *
+ * @param display the display which tasks are to check
+ * @param inOutBounds the bounds used to input initial bounds and output result bounds
+ */
+ private void adjustBoundsToAvoidConflict(@NonNull ActivityDisplay display,
+ @NonNull Rect inOutBounds) {
+ final Rect displayBounds = display.getBounds();
+ if (!displayBounds.contains(inOutBounds)) {
+ // The initial bounds are already out of display. The scanning algorithm below doesn't
+ // work so well with them.
+ return;
+ }
+
+ final List<TaskRecord> tasksToCheck = new ArrayList<>();
+ for (int i = 0; i < display.getChildCount(); ++i) {
+ ActivityStack<?> stack = display.getChildAt(i);
+ if (!stack.inFreeformWindowingMode()) {
+ continue;
+ }
+
+ for (int j = 0; j < stack.getChildCount(); ++j) {
+ tasksToCheck.add(stack.getChildAt(j));
+ }
+ }
+
+ if (!boundsConflict(tasksToCheck, inOutBounds)) {
+ // Current proposal doesn't conflict with any task. Early return to avoid unnecessary
+ // calculation.
+ return;
+ }
+
+ calculateCandidateShiftDirections(displayBounds, inOutBounds);
+ for (int direction : mTmpDirections) {
+ if (direction == Gravity.NO_GRAVITY) {
+ // We exhausted candidate directions, give up.
+ break;
+ }
+
+ mTmpBounds.set(inOutBounds);
+ while (boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) {
+ shiftBounds(direction, displayBounds, mTmpBounds);
+ }
+
+ if (!boundsConflict(tasksToCheck, mTmpBounds) && displayBounds.contains(mTmpBounds)) {
+ // Found a candidate. Just use this.
+ inOutBounds.set(mTmpBounds);
+ if (DEBUG) appendLog("avoid-bounds-conflict=" + inOutBounds);
+ return;
+ }
+
+ // Didn't find a conflict free bounds here. Try the next candidate direction.
+ }
+
+ // We failed to find a conflict free location. Just keep the original result.
+ }
+
+ /**
+ * Determines scanning directions and their priorities to avoid bounds conflict.
+ *
+ * @param availableBounds bounds that the result must be in
+ * @param initialBounds initial bounds when start scanning
+ */
+ private void calculateCandidateShiftDirections(@NonNull Rect availableBounds,
+ @NonNull Rect initialBounds) {
+ for (int i = 0; i < mTmpDirections.length; ++i) {
+ mTmpDirections[i] = Gravity.NO_GRAVITY;
+ }
+
+ final int oneThirdWidth = (2 * availableBounds.left + availableBounds.right) / 3;
+ final int twoThirdWidth = (availableBounds.left + 2 * availableBounds.right) / 3;
+ final int centerX = initialBounds.centerX();
+ if (centerX < oneThirdWidth) {
+ // Too close to left, just scan to the right.
+ mTmpDirections[0] = Gravity.RIGHT;
+ return;
+ } else if (centerX > twoThirdWidth) {
+ // Too close to right, just scan to the left.
+ mTmpDirections[0] = Gravity.LEFT;
+ return;
+ }
+
+ final int oneThirdHeight = (2 * availableBounds.top + availableBounds.bottom) / 3;
+ final int twoThirdHeight = (availableBounds.top + 2 * availableBounds.bottom) / 3;
+ final int centerY = initialBounds.centerY();
+ if (centerY < oneThirdHeight || centerY > twoThirdHeight) {
+ // Too close to top or bottom boundary and we're in the middle horizontally, scan
+ // horizontally in both directions.
+ mTmpDirections[0] = Gravity.RIGHT;
+ mTmpDirections[1] = Gravity.LEFT;
+ return;
+ }
+
+ // We're in the center region both horizontally and vertically. Scan in both directions of
+ // primary diagonal.
+ mTmpDirections[0] = Gravity.BOTTOM | Gravity.RIGHT;
+ mTmpDirections[1] = Gravity.TOP | Gravity.LEFT;
+ }
+
+ private boolean boundsConflict(@NonNull List<TaskRecord> tasks, @NonNull Rect bounds) {
+ for (TaskRecord task : tasks) {
+ final Rect taskBounds = task.getBounds();
+ final boolean leftClose = Math.abs(taskBounds.left - bounds.left)
+ < BOUNDS_CONFLICT_THRESHOLD;
+ final boolean topClose = Math.abs(taskBounds.top - bounds.top)
+ < BOUNDS_CONFLICT_THRESHOLD;
+ final boolean rightClose = Math.abs(taskBounds.right - bounds.right)
+ < BOUNDS_CONFLICT_THRESHOLD;
+ final boolean bottomClose = Math.abs(taskBounds.bottom - bounds.bottom)
+ < BOUNDS_CONFLICT_THRESHOLD;
+
+ if ((leftClose && topClose) || (leftClose && bottomClose) || (rightClose && topClose)
+ || (rightClose && bottomClose)) {
+ return true;
+ }
+ }
+
return false;
}
- private static final boolean closeLeftTopCorner(Rect first, Rect second) {
- return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private void shiftBounds(int direction, @NonNull Rect availableRect,
+ @NonNull Rect inOutBounds) {
+ final int horizontalOffset;
+ switch (direction & Gravity.HORIZONTAL_GRAVITY_MASK) {
+ case Gravity.LEFT:
+ horizontalOffset = -Math.max(MINIMAL_STEP,
+ availableRect.width() / STEP_DENOMINATOR);
+ break;
+ case Gravity.RIGHT:
+ horizontalOffset = Math.max(MINIMAL_STEP, availableRect.width() / STEP_DENOMINATOR);
+ break;
+ default:
+ horizontalOffset = 0;
+ }
+
+ final int verticalOffset;
+ switch (direction & Gravity.VERTICAL_GRAVITY_MASK) {
+ case Gravity.TOP:
+ verticalOffset = -Math.max(MINIMAL_STEP, availableRect.height() / STEP_DENOMINATOR);
+ break;
+ case Gravity.BOTTOM:
+ verticalOffset = Math.max(MINIMAL_STEP, availableRect.height() / STEP_DENOMINATOR);
+ break;
+ default:
+ verticalOffset = 0;
+ }
+
+ inOutBounds.offset(horizontalOffset, verticalOffset);
}
- private static final boolean closeRightTopCorner(Rect first, Rect second) {
- return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private void initLogBuilder(TaskRecord task, ActivityRecord activity) {
+ if (DEBUG) {
+ mLogBuilder = new StringBuilder("TaskLaunchParamsModifier:task=" + task
+ + " activity=" + activity);
+ }
}
- private static final boolean closeLeftBottomCorner(Rect first, Rect second) {
- return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private void appendLog(String log) {
+ if (DEBUG) mLogBuilder.append(" ").append(log);
}
- private static final boolean closeRightBottomCorner(Rect first, Rect second) {
- return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
- && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+ private void outputLog() {
+ if (DEBUG) Slog.d(TAG, mLogBuilder.toString());
+ }
+
+ private static int orientationFromBounds(Rect bounds) {
+ return bounds.width() > bounds.height() ? SCREEN_ORIENTATION_LANDSCAPE
+ : SCREEN_ORIENTATION_PORTRAIT;
+ }
+
+ private static boolean sizeMatches(Rect left, Rect right) {
+ return (Math.abs(right.width() - left.width()) < EPSILON)
+ && (Math.abs(right.height() - left.height()) < EPSILON);
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index ca9b256..30659c1 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -1031,6 +1031,11 @@
result.isPortal() /* isCaptivePortal */,
startTime, endTime);
+ log("isCaptivePortal: isSuccessful()=" + result.isSuccessful() +
+ " isPortal()=" + result.isPortal() +
+ " RedirectUrl=" + result.redirectUrl +
+ " StartTime=" + startTime + " EndTime=" + endTime);
+
return result;
}
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index b7bbd42..47e85b5 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -16,6 +16,12 @@
package com.android.server.connectivity;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_HOST;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PAC;
+import static android.provider.Settings.Global.GLOBAL_HTTP_PROXY_PORT;
+import static android.provider.Settings.Global.HTTP_PROXY;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
@@ -47,16 +53,14 @@
@NonNull
private final Context mContext;
- // TODO : make this private and import as much managing logic from ConnectivityService as
- // possible
@NonNull
- public final Object mProxyLock = new Object();
+ private final Object mProxyLock = new Object();
// The global proxy is the proxy that is set device-wide, overriding any network-specific
// proxy. Note however that proxies are hints ; the system does not enforce their use. Hence
// this value is only for querying.
@Nullable
@GuardedBy("mProxyLock")
- public ProxyInfo mGlobalProxy = null;
+ private ProxyInfo mGlobalProxy = null;
// The default proxy is the proxy that applies to no particular network if the global proxy
// is not set. Individual networks have their own settings that override this. This member
// is set through setDefaultProxy, which is called when the default network changes proxies
@@ -64,10 +68,10 @@
// when PacManager resolves the proxy.
@Nullable
@GuardedBy("mProxyLock")
- public volatile ProxyInfo mDefaultProxy = null;
- // Whether the default proxy is disabled. TODO : make this mDefaultProxyEnabled
+ private volatile ProxyInfo mDefaultProxy = null;
+ // Whether the default proxy is enabled.
@GuardedBy("mProxyLock")
- public boolean mDefaultProxyDisabled = false;
+ private boolean mDefaultProxyEnabled = true;
// The object responsible for Proxy Auto Configuration (PAC).
@NonNull
@@ -85,7 +89,7 @@
@Nullable
private static ProxyInfo canonicalizeProxyInfo(@Nullable final ProxyInfo proxy) {
if (proxy != null && TextUtils.isEmpty(proxy.getHost())
- && (proxy.getPacFileUrl() == null || Uri.EMPTY.equals(proxy.getPacFileUrl()))) {
+ && Uri.EMPTY.equals(proxy.getPacFileUrl())) {
return null;
}
return proxy;
@@ -123,7 +127,7 @@
// This information is already available as a world read/writable jvm property.
synchronized (mProxyLock) {
final ProxyInfo ret = mGlobalProxy;
- if ((ret == null) && !mDefaultProxyDisabled) return mDefaultProxy;
+ if ((ret == null) && mDefaultProxyEnabled) return mDefaultProxy;
return ret;
}
}
@@ -146,11 +150,10 @@
*/
public void loadGlobalProxy() {
ContentResolver res = mContext.getContentResolver();
- String host = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST);
- int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0);
- String exclList = Settings.Global.getString(res,
- Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
- String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
+ String host = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_HOST);
+ int port = Settings.Global.getInt(res, GLOBAL_HTTP_PROXY_PORT, 0);
+ String exclList = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+ String pacFileUrl = Settings.Global.getString(res, GLOBAL_HTTP_PROXY_PAC);
if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
ProxyInfo proxyProperties;
if (!TextUtils.isEmpty(pacFileUrl)) {
@@ -167,10 +170,36 @@
mGlobalProxy = proxyProperties;
}
}
+ loadDeprecatedGlobalHttpProxy();
// TODO : shouldn't this function call mPacManager.setCurrentProxyScriptUrl ?
}
/**
+ * Read the global proxy from the deprecated Settings.Global.HTTP_PROXY setting and apply it.
+ */
+ public void loadDeprecatedGlobalHttpProxy() {
+ final String proxy = Settings.Global.getString(mContext.getContentResolver(), HTTP_PROXY);
+ if (!TextUtils.isEmpty(proxy)) {
+ String data[] = proxy.split(":");
+ if (data.length == 0) {
+ return;
+ }
+
+ final String proxyHost = data[0];
+ int proxyPort = 8080;
+ if (data.length > 1) {
+ try {
+ proxyPort = Integer.parseInt(data[1]);
+ } catch (NumberFormatException e) {
+ return;
+ }
+ }
+ final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
+ setGlobalProxy(p);
+ }
+ }
+
+ /**
* Sends the system broadcast informing apps about a new proxy configuration.
*
* Confusingly this method also sets the PAC file URL. TODO : separate this, it has nothing
@@ -232,11 +261,10 @@
final ContentResolver res = mContext.getContentResolver();
final long token = Binder.clearCallingIdentity();
try {
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
- Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
- exclList);
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_HOST, host);
+ Settings.Global.putInt(res, GLOBAL_HTTP_PROXY_PORT, port);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclList);
+ Settings.Global.putString(res, GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -253,10 +281,7 @@
*/
public void setDefaultProxy(@Nullable ProxyInfo proxyInfo) {
synchronized (mProxyLock) {
- if (mDefaultProxy != null && mDefaultProxy.equals(proxyInfo)) {
- return;
- }
- if (mDefaultProxy == proxyInfo) return; // catches repeated nulls
+ if (Objects.equals(mDefaultProxy, proxyInfo)) return;
if (proxyInfo != null && !proxyInfo.isValid()) {
if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
return;
@@ -277,9 +302,27 @@
mDefaultProxy = proxyInfo;
if (mGlobalProxy != null) return;
- if (!mDefaultProxyDisabled) {
+ if (mDefaultProxyEnabled) {
sendProxyBroadcast(proxyInfo);
}
}
}
+
+ /**
+ * Enable or disable the default proxy.
+ *
+ * This sets the flag for enabling/disabling the default proxy and sends the broadcast
+ * if applicable.
+ * @param enabled whether the default proxy should be enabled.
+ */
+ public void setDefaultProxyEnabled(final boolean enabled) {
+ synchronized (mProxyLock) {
+ if (mDefaultProxyEnabled != enabled) {
+ mDefaultProxyEnabled = enabled;
+ if (mGlobalProxy == null && mDefaultProxy != null) {
+ sendProxyBroadcast(enabled ? mDefaultProxy : null);
+ }
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 71c419f..a9b0d5c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -421,7 +421,6 @@
final IInputContext inputContext;
final int uid;
final int pid;
- final int selfReportedDisplayId;
final InputBinding binding;
final ClientDeathRecipient clientDeathRecipient;
@@ -431,18 +430,16 @@
@Override
public String toString() {
return "ClientState{" + Integer.toHexString(
- System.identityHashCode(this)) + " uid=" + uid
- + " pid=" + pid + " displayId=" + selfReportedDisplayId + "}";
+ System.identityHashCode(this)) + " uid " + uid
+ + " pid " + pid + "}";
}
ClientState(IInputMethodClient _client, IInputContext _inputContext,
- int _uid, int _pid, int _selfReportedDisplayId,
- ClientDeathRecipient _clientDeathRecipient) {
+ int _uid, int _pid, ClientDeathRecipient _clientDeathRecipient) {
client = _client;
inputContext = _inputContext;
uid = _uid;
pid = _pid;
- selfReportedDisplayId = _selfReportedDisplayId;
binding = new InputBinding(null, inputContext.asBinder(), uid, pid);
clientDeathRecipient = _clientDeathRecipient;
}
@@ -1748,21 +1745,15 @@
* process
* @param inputContext communication channel for the dummy
* {@link android.view.inputmethod.InputConnection}
- * @param selfReportedDisplayId self-reported display ID to which the client is associated.
- * Whether the client is still allowed to access to this display
- * or not needs to be evaluated every time the client interacts
- * with the display
*/
@Override
- public void addClient(IInputMethodClient client, IInputContext inputContext,
- int selfReportedDisplayId) {
+ public void addClient(IInputMethodClient client, IInputContext inputContext) {
final int callerUid = Binder.getCallingUid();
final int callerPid = Binder.getCallingPid();
synchronized (mMethodMap) {
// TODO: Optimize this linear search.
for (ClientState state : mClients.values()) {
- if (state.uid == callerUid && state.pid == callerPid
- && state.selfReportedDisplayId == selfReportedDisplayId) {
+ if (state.uid == callerUid && state.pid == callerPid) {
throw new SecurityException("uid=" + callerUid + "/pid=" + callerPid
+ " is already registered");
}
@@ -1773,25 +1764,11 @@
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
- // We cannot fully avoid race conditions where the client UID already lost the access to
- // the given self-reported display ID, even if the client is not maliciously reporting
- // a fake display ID. Unconditionally returning SecurityException just because the
- // client doesn't pass display ID verification can cause many test failures hence not an
- // option right now. At the same time
- // context.getSystemService(InputMethodManager.class)
- // is expected to return a valid non-null instance at any time if we do not choose to
- // have the client crash. Thus we do not verify the display ID at all here. Instead we
- // later check the display ID every time the client needs to interact with the specified
- // display.
- mClients.put(client.asBinder(), new ClientState(client, inputContext, callerUid,
- callerPid, selfReportedDisplayId, deathRecipient));
+ mClients.put(client.asBinder(),
+ new ClientState(client, inputContext, callerUid, callerPid, deathRecipient));
}
}
- private boolean verifyDisplayId(ClientState cs) {
- return mWindowManagerInternal.isUidAllowedOnDisplay(cs.selfReportedDisplayId, cs.uid);
- }
-
void removeClient(IInputMethodClient client) {
synchronized (mMethodMap) {
ClientState cs = mClients.remove(client.asBinder());
@@ -1941,9 +1918,8 @@
mCurAttribute = attribute;
// Check if the input method is changing.
- // We expect the caller has already verified that the client is allowed to access this
- // display ID.
- final int displayId = mCurFocusedWindowClient.selfReportedDisplayId;
+ final int displayId = mWindowManagerInternal.getDisplayIdForWindow(
+ mCurFocusedWindow);
if (mCurId != null && mCurId.equals(mCurMethodId) && displayId == mCurTokenDisplayId) {
if (cs.curSession != null) {
// Fast case: if we are already connected to the input method,
@@ -2008,11 +1984,7 @@
com.android.internal.R.string.input_method_binding_label);
mCurIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
mContext, 0, new Intent(Settings.ACTION_INPUT_METHOD_SETTINGS), 0));
- if (!verifyDisplayId(mCurFocusedWindowClient)) {
- // Wait, the client no longer has access to the display.
- return InputBindResult.INVALID_DISPLAY_ID;
- }
- final int displayId = mCurFocusedWindowClient.selfReportedDisplayId;
+ final int displayId = mWindowManagerInternal.getDisplayIdForWindow(mCurFocusedWindow);
mCurTokenDisplayId = (displayId != INVALID_DISPLAY) ? displayId : DEFAULT_DISPLAY;
if (bindCurrentInputMethodServiceLocked(mCurIntent, this, IME_CONNECTION_BIND_FLAGS)) {
@@ -2612,8 +2584,7 @@
if (cs == null) {
throw new IllegalArgumentException("unknown client " + client.asBinder());
}
- if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
- cs.selfReportedDisplayId)) {
+ if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
return false;
}
@@ -2697,8 +2668,7 @@
if (cs == null) {
throw new IllegalArgumentException("unknown client " + client.asBinder());
}
- if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
- cs.selfReportedDisplayId)) {
+ if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
if (DEBUG) {
Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client);
}
@@ -2797,8 +2767,6 @@
InputBindResult res = null;
long ident = Binder.clearCallingIdentity();
try {
- final int windowDisplayId =
- mWindowManagerInternal.getDisplayIdForWindow(windowToken);
synchronized (mMethodMap) {
if (DEBUG) Slog.v(TAG, "startInputOrWindowGainedFocusInternal: reason="
+ InputMethodClient.getStartInputReason(startInputReason)
@@ -2817,15 +2785,8 @@
throw new IllegalArgumentException("unknown client "
+ client.asBinder());
}
- if (cs.selfReportedDisplayId != windowDisplayId) {
- Slog.e(TAG, "startInputOrWindowGainedFocusInternal: display ID mismatch."
- + " from client:" + cs.selfReportedDisplayId
- + " from window:" + windowDisplayId);
- return InputBindResult.DISPLAY_ID_MISMATCH;
- }
- if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
- cs.selfReportedDisplayId)) {
+ if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid)) {
// Check with the window manager to make sure this client actually
// has a window with focus. If not, reject. This is thread safe
// because if the focus changes some time before or after, the
@@ -2897,9 +2858,9 @@
// If focused display changed, we should unbind current method
// to make app window in previous display relayout after Ime
// window token removed.
- // Note that we can trust client's display ID as long as it matches
- // to the display ID obtained from the window.
- if (cs.selfReportedDisplayId != mCurTokenDisplayId) {
+ final int newFocusDisplayId =
+ mWindowManagerInternal.getDisplayIdForWindow(windowToken);
+ if (newFocusDisplayId != mCurTokenDisplayId) {
unbindCurrentMethodLocked();
}
}
@@ -2997,7 +2958,6 @@
}
private boolean canShowInputMethodPickerLocked(IInputMethodClient client) {
- // TODO(yukawa): multi-display support.
final int uid = Binder.getCallingUid();
if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
return true;
@@ -3074,7 +3034,6 @@
@Override
public void showInputMethodAndSubtypeEnablerFromClient(
IInputMethodClient client, String inputMethodId) {
- // TODO(yukawa): Should we verify the display ID?
if (!calledFromValidUser()) {
return;
}
@@ -3270,7 +3229,6 @@
*/
@Override
public int getInputMethodWindowVisibleHeight() {
- // TODO(yukawa): Should we verify the display ID?
return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId);
}
diff --git a/services/core/java/com/android/server/location/ContextHubClientBroker.java b/services/core/java/com/android/server/location/ContextHubClientBroker.java
index 9640e04..b29b7cf 100644
--- a/services/core/java/com/android/server/location/ContextHubClientBroker.java
+++ b/services/core/java/com/android/server/location/ContextHubClientBroker.java
@@ -76,6 +76,13 @@
*/
private final AtomicBoolean mConnectionOpen = new AtomicBoolean(true);
+ /*
+ * Internal interface used to invoke client callbacks.
+ */
+ private interface CallbackConsumer {
+ void accept(IContextHubClientCallback callback) throws RemoteException;
+ }
+
/* package */ ContextHubClientBroker(
Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager,
int contextHubId, short hostEndPointId, IContextHubClientCallback callback) {
@@ -140,12 +147,9 @@
/**
* Invoked when the underlying binder of this broker has died at the client process.
*/
+ @Override
public void binderDied() {
- try {
- IContextHubClient.Stub.asInterface(this).close();
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException while closing client on death", e);
- }
+ close();
}
/**
@@ -168,14 +172,7 @@
* @param message the message that came from a nanoapp
*/
/* package */ void sendMessageToClient(NanoAppMessage message) {
- if (mConnectionOpen.get()) {
- try {
- mCallbackInterface.onMessageFromNanoApp(message);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException while sending message to client (host endpoint ID = "
- + mHostEndPointId + ")", e);
- }
- }
+ invokeCallbackConcurrent(callback -> callback.onMessageFromNanoApp(message));
}
/**
@@ -184,14 +181,7 @@
* @param nanoAppId the ID of the nanoapp that was loaded.
*/
/* package */ void onNanoAppLoaded(long nanoAppId) {
- if (mConnectionOpen.get()) {
- try {
- mCallbackInterface.onNanoAppLoaded(nanoAppId);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException while calling onNanoAppLoaded on client"
- + " (host endpoint ID = " + mHostEndPointId + ")", e);
- }
- }
+ invokeCallbackConcurrent(callback -> callback.onNanoAppLoaded(nanoAppId));
}
/**
@@ -200,28 +190,14 @@
* @param nanoAppId the ID of the nanoapp that was unloaded.
*/
/* package */ void onNanoAppUnloaded(long nanoAppId) {
- if (mConnectionOpen.get()) {
- try {
- mCallbackInterface.onNanoAppUnloaded(nanoAppId);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException while calling onNanoAppUnloaded on client"
- + " (host endpoint ID = " + mHostEndPointId + ")", e);
- }
- }
+ invokeCallbackConcurrent(callback -> callback.onNanoAppUnloaded(nanoAppId));
}
/**
* Notifies the client of a hub reset event if the connection is open.
*/
/* package */ void onHubReset() {
- if (mConnectionOpen.get()) {
- try {
- mCallbackInterface.onHubReset();
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException while calling onHubReset on client" +
- " (host endpoint ID = " + mHostEndPointId + ")", e);
- }
- }
+ invokeCallbackConcurrent(callback -> callback.onHubReset());
}
/**
@@ -231,12 +207,21 @@
* @param abortCode the nanoapp specific abort code
*/
/* package */ void onNanoAppAborted(long nanoAppId, int abortCode) {
+ invokeCallbackConcurrent(callback -> callback.onNanoAppAborted(nanoAppId, abortCode));
+ }
+
+ /**
+ * Helper function to invoke a specified client callback, if the connection is open.
+ *
+ * @param consumer the consumer specifying the callback to invoke
+ */
+ private void invokeCallbackConcurrent(CallbackConsumer consumer) {
if (mConnectionOpen.get()) {
try {
- mCallbackInterface.onNanoAppAborted(nanoAppId, abortCode);
+ consumer.accept(mCallbackInterface);
} catch (RemoteException e) {
- Log.e(TAG, "RemoteException while calling onNanoAppAborted on client"
- + " (host endpoint ID = " + mHostEndPointId + ")", e);
+ Log.e(TAG, "RemoteException while invoking client callback (host endpoint ID = "
+ + mHostEndPointId + ")", e);
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f9d49d7..506cc44 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -4282,14 +4282,16 @@
}
private void doChannelWarningToast(CharSequence toastText) {
- final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
- final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
- Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
- if (warningEnabled) {
- Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
- Toast.LENGTH_SHORT);
- toast.show();
- }
+ Binder.withCleanCallingIdentity(() -> {
+ final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
+ final boolean warningEnabled = Settings.Global.getInt(getContext().getContentResolver(),
+ Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, defaultWarningEnabled) != 0;
+ if (warningEnabled) {
+ Toast toast = Toast.makeText(getContext(), mHandler.getLooper(), toastText,
+ Toast.LENGTH_SHORT);
+ toast.show();
+ }
+ });
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
index 3ffc5c5..9c1ac34 100644
--- a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
+++ b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
@@ -57,7 +57,7 @@
// should use the getSerialForPackage method with the calling package specified.
if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
/* callingPackage */ null, "getSerial")) {
- return null;
+ return Build.UNKNOWN;
}
return SystemProperties.get("ro.serialno", Build.UNKNOWN);
}
@@ -66,7 +66,7 @@
public @Nullable String getSerialForPackage(String callingPackage) throws RemoteException {
if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mContext,
callingPackage, "getSerial")) {
- return null;
+ return Build.UNKNOWN;
}
return SystemProperties.get("ro.serialno", Build.UNKNOWN);
}
diff --git a/services/core/java/com/android/server/pm/dex/TEST_MAPPING b/services/core/java/com/android/server/pm/dex/TEST_MAPPING
index ad52559..c93af2a 100644
--- a/services/core/java/com/android/server/pm/dex/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/dex/TEST_MAPPING
@@ -1,19 +1,12 @@
{
"presubmit": [
{
- "name": "DexLoggerTests"
- },
- {
- "name": "DexManagerTests"
- },
- {
- "name": "DexoptOptionsTests"
- },
- {
- "name": "DexoptUtilsTest"
- },
- {
- "name": "PackageDexUsageTests"
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.pm.dex"
+ }
+ ]
},
{
"name": "DexLoggerIntegrationTests"
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 1cba1c7..a55b49f 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -95,10 +95,22 @@
mIsShowing = showing;
mCallback.onShowingChanged();
- try {
- mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error informing keystore of screen lock", e);
+ int retry = 2;
+ while (retry > 0) {
+ try {
+ mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
+ break;
+ } catch (RemoteException e) {
+ if (retry == 2) {
+ Slog.w(TAG, "Error informing keystore of screen lock. Keystore may have died"
+ + " -> refreshing service token and retrying");
+ mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
+ .getService("android.security.keystore"));
+ } else {
+ Slog.e(TAG, "Error informing keystore of screen lock after retrying once", e);
+ }
+ --retry;
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6f728fc..642f5781 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -92,7 +92,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -119,7 +118,6 @@
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
-import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
import android.annotation.CallSuper;
import android.annotation.NonNull;
@@ -2065,9 +2063,25 @@
layoutAndAssignWindowLayersIfNeeded();
}
- int taskIdFromPoint(int x, int y) {
+ /**
+ * Used to obtain task ID when user taps on coordinate (x, y) in this display, and outside
+ * current task in focus.
+ *
+ * This returns the task ID of the foremost task at (x, y) if the task is not home. Otherwise it
+ * returns -1.
+ *
+ * @param x horizontal coordinate of the tap position
+ * @param y vertical coordinate of the tap position
+ * @return the task ID if a non-home task is found; -1 if not
+ */
+ int taskForTapOutside(int x, int y) {
for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
+ if (stack.isActivityTypeHome()) {
+ // We skip not only home stack, but also everything behind home because user can't
+ // see them.
+ break;
+ }
final int taskId = stack.taskIdFromPoint(x, y);
if (taskId != -1) {
return taskId;
diff --git a/services/core/java/com/android/server/wm/TaskPositioningController.java b/services/core/java/com/android/server/wm/TaskPositioningController.java
index b7e37b2..25148d1 100644
--- a/services/core/java/com/android/server/wm/TaskPositioningController.java
+++ b/services/core/java/com/android/server/wm/TaskPositioningController.java
@@ -88,7 +88,7 @@
}
taskId = task.mTaskId;
} else {
- taskId = displayContent.taskIdFromPoint(x, y);
+ taskId = displayContent.taskForTapOutside(x, y);
}
}
if (taskId >= 0) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index b096bf2..5410676 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -430,25 +430,14 @@
public abstract boolean isUidFocused(int uid);
/**
- * Checks whether the specified IME client has IME focus or not.
+ * Checks whether the specified process has IME focus or not.
*
* @param uid UID of the process to be queried
* @param pid PID of the process to be queried
- * @param displayId Display ID reported from the client. Note that this method also verifies
- * whether the specified process is allowed to access to this display or not
- * @return {@code true} if the IME client specified with {@code uid}, {@code pid}, and
- * {@code displayId} has IME focus
+ * @return {@code true} if a process that is identified by {@code uid} and {@code pid} has IME
+ * focus
*/
- public abstract boolean isInputMethodClientFocus(int uid, int pid, int displayId);
-
- /**
- * Checks whether the given {@code uid} is allowed to use the given {@code displayId} or not.
- *
- * @param displayId Display ID to be checked
- * @param uid UID to be checked.
- * @return {@code true} if the given {@code uid} is allowed to use the given {@code displayId}
- */
- public abstract boolean isUidAllowedOnDisplay(int displayId, int uid);
+ public abstract boolean isInputMethodClientFocus(int uid, int pid);
/**
* Return the display Id for given window.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index e153a1d..10ba63e 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7201,20 +7201,16 @@
}
@Override
- public boolean isInputMethodClientFocus(int uid, int pid, int displayId) {
- if (displayId == Display.INVALID_DISPLAY) {
- return false;
- }
+ public boolean isInputMethodClientFocus(int uid, int pid) {
synchronized (mWindowMap) {
- final DisplayContent displayContent = mRoot.getTopFocusedDisplayContent();
- if (displayContent == null
- || displayContent.getDisplayId() != displayId
- || !displayContent.hasAccess(uid)) {
- return false;
+ // Check all displays if any input method window has focus.
+ for (int i = mRoot.mChildren.size() - 1; i >= 0; --i) {
+ final DisplayContent displayContent = mRoot.mChildren.get(i);
+ if (displayContent.isInputMethodClientFocus(uid, pid)) {
+ return true;
+ }
}
- if (displayContent.isInputMethodClientFocus(uid, pid)) {
- return true;
- }
+
// Okay, how about this... what is the current focus?
// It seems in some cases we may not have moved the IM
// target window, such as when it was in a pop-up window,
@@ -7223,7 +7219,7 @@
// press home. Sometimes the IME won't go down.)
// Would be nice to fix this more correctly, but it's
// way at the end of a release, and this should be good enough.
- final WindowState currentFocus = displayContent.mCurrentFocus;
+ final WindowState currentFocus = mRoot.getTopFocusedDisplayContent().mCurrentFocus;
if (currentFocus != null && currentFocus.mSession.mUid == uid
&& currentFocus.mSession.mPid == pid) {
return true;
@@ -7233,20 +7229,6 @@
}
@Override
- public boolean isUidAllowedOnDisplay(int displayId, int uid) {
- if (displayId == Display.DEFAULT_DISPLAY) {
- return true;
- }
- if (displayId == Display.INVALID_DISPLAY) {
- return false;
- }
- synchronized (mWindowMap) {
- final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
- return displayContent != null && displayContent.hasAccess(uid);
- }
- }
-
- @Override
public int getDisplayIdForWindow(IBinder windowToken) {
synchronized (mWindowMap) {
final WindowState window = mWindowMap.get(windowToken);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 52b849f..bbc4f44 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -468,6 +468,12 @@
}
}
+ // Diagnostic to ensure that the system is in a base healthy state. Done here as a common
+ // non-zygote process.
+ if (!VMRuntime.hasBootImageSpaces()) {
+ Slog.wtf(TAG, "Runtime is not running with a boot image!");
+ }
+
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 9d686ef..d197d01 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -28,7 +28,6 @@
import android.net.util.InterfaceParams;
import android.system.ErrnoException;
import android.system.Os;
-import android.system.StructGroupReq;
import android.system.StructTimeval;
import android.util.Log;
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
deleted file mode 100644
index 9de64f2..0000000
--- a/services/tests/servicestests/src/com/android/server/am/ActivityLaunchParamsModifierTests.java
+++ /dev/null
@@ -1,144 +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.am;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_DONE;
-import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_SKIP;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import android.app.ActivityOptions;
-import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.am.LaunchParamsController.LaunchParams;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for exercising resizing bounds due to activity options.
- *
- * Build/Install/Run:
- * atest FrameworksServicesTests:ActivityLaunchParamsModifierTests
- */
-@MediumTest
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class ActivityLaunchParamsModifierTests extends ActivityTestsBase {
- private ActivityLaunchParamsModifier mModifier;
- private ActivityTaskManagerService mService;
- private ActivityStack mStack;
- private TaskRecord mTask;
- private ActivityRecord mActivity;
-
- private LaunchParams mCurrent;
- private LaunchParams mResult;
-
- @Before
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mService = createActivityTaskManagerService();
- mModifier = new ActivityLaunchParamsModifier(mService.mStackSupervisor);
- mCurrent = new LaunchParams();
- mResult = new LaunchParams();
-
-
- mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
- mActivity = new ActivityBuilder(mService).setTask(mTask).build();
- }
-
-
- @Test
- public void testSkippedInvocations() throws Exception {
- // No specified activity should be ignored
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- null /*activity*/, null /*source*/, null /*options*/, mCurrent, mResult));
-
- // No specified activity options should be ignored
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, null /*options*/, mCurrent, mResult));
-
- // launch bounds specified should be ignored.
- final ActivityOptions options = ActivityOptions.makeBasic();
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // Non-resizeable records should be ignored
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
- assertFalse(mActivity.isResizeable());
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // make record resizeable
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
- assertTrue(mActivity.isResizeable());
-
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // Does not support freeform
- mService.mSupportsFreeformWindowManagement = false;
- assertFalse(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- mService.mSupportsFreeformWindowManagement = true;
- options.setLaunchBounds(new Rect());
- assertTrue(mService.mStackSupervisor.canUseActivityOptionsLaunchBounds(options));
-
- // Invalid bounds
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
- options.setLaunchBounds(new Rect(0, 0, -1, -1));
- assertEquals(RESULT_SKIP, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
-
- // Valid bounds should cause the positioner to be applied.
- options.setLaunchBounds(new Rect(0, 0, 100, 100));
- assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
- }
-
- @Test
- public void testBoundsExtraction() throws Exception {
- // Make activity resizeable and enable freeform mode.
- mActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
- mService.mSupportsFreeformWindowManagement = true;
-
- ActivityOptions options = ActivityOptions.makeBasic();
- final Rect proposedBounds = new Rect(20, 30, 45, 40);
- options.setLaunchBounds(proposedBounds);
-
- assertEquals(RESULT_DONE, mModifier.onCalculate(null /*task*/, null /*layout*/,
- mActivity, null /*source*/, options /*options*/, mCurrent, mResult));
- assertEquals(mResult.mBounds, proposedBounds);
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
index f5b8f78..0d1302f 100644
--- a/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/TaskLaunchParamsModifierTests.java
@@ -11,239 +11,1098 @@
* 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
+ * limitations under the License.
*/
package com.android.server.am;
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_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LOCKED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.util.DisplayMetrics.DENSITY_DEFAULT;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.am.LaunchParamsController.LaunchParamsModifier.RESULT_CONTINUE;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
-import android.content.pm.ActivityInfo.WindowLayout;
+import android.app.ActivityOptions;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
import android.graphics.Rect;
+import android.os.Build;
import android.platform.test.annotations.Presubmit;
import android.view.Gravity;
-import androidx.test.filters.MediumTest;
+import androidx.test.filters.SmallTest;
+import androidx.test.filters.FlakyTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.am.LaunchParamsController.LaunchParams;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Locale;
+
/**
- * Tests for exercising resizing task bounds.
+ * Tests for default task bounds.
*
* Build/Install/Run:
* atest FrameworksServicesTests:TaskLaunchParamsModifierTests
*/
-@MediumTest
+@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
+@FlakyTest(detail = "Confirm stable in post-submit before removing")
public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
- private final static int STACK_WIDTH = 100;
- private final static int STACK_HEIGHT = 200;
- private final static Rect STACK_BOUNDS = new Rect(0, 0, STACK_WIDTH, STACK_HEIGHT);
+ private ActivityRecord mActivity;
- private ActivityTaskManagerService mService;
- private ActivityStack mStack;
- private TaskRecord mTask;
+ private TaskLaunchParamsModifier mTarget;
- private TaskLaunchParamsModifier mPositioner;
-
- private LaunchParamsController.LaunchParams mCurrent;
- private LaunchParamsController.LaunchParams mResult;
+ private LaunchParams mCurrent;
+ private LaunchParams mResult;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
- mService = createActivityTaskManagerService();
- mStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
- WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
- mStack.requestResize(STACK_BOUNDS);
+ setupActivityTaskManagerService();
+ mService.mSupportsFreeformWindowManagement = true;
+ when(mSupervisor.canUseActivityOptionsLaunchBounds(any())).thenCallRealMethod();
- // We must create the task after resizing to make sure it does not inherit the stack
- // dimensions on resize.
- mTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+ mActivity = new ActivityBuilder(mService).build();
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+ mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
- mPositioner = new TaskLaunchParamsModifier();
+ mTarget = new TaskLaunchParamsModifier(mSupervisor);
- mResult = new LaunchParamsController.LaunchParams();
- mCurrent = new LaunchParamsController.LaunchParams();
+ mCurrent = new LaunchParams();
+ mCurrent.reset();
+ mResult = new LaunchParams();
+ mResult.reset();
}
- /**
- * Ensures that the setup bounds are set as expected with the stack bounds set and the task
- * bounds still {@code null}.
- * @throws Exception
- */
+ // =============================
+ // Display ID Related Tests
+ // =============================
@Test
- public void testInitialBounds() throws Exception {
- assertEquals(mStack.getOverrideBounds(), STACK_BOUNDS);
- assertEquals(mTask.getOverrideBounds(), new Rect());
+ public void testDefaultToPrimaryDisplay() {
+ createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(DEFAULT_DISPLAY, mResult.mPreferredDisplayId);
}
- /**
- * Ensures that a task positioned with no {@link WindowLayout} receives the default launch
- * position.
- * @throws Exception
- */
@Test
- public void testLaunchNoWindowLayout() throws Exception {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask, null /*layout*/,
- null /*record*/, null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(getDefaultBounds(Gravity.NO_GRAVITY), mResult.mBounds);
+ public void testUsesPreviousDisplayIdIfSet() {
+ createNewActivityDisplay(WINDOWING_MODE_FREEFORM);
+ final TestActivityDisplay display = createNewActivityDisplay(WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = display.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(display.mDisplayId, mResult.mPreferredDisplayId);
}
- /**
- * Ensures that a task positioned with an empty {@link WindowLayout} receives the default launch
- * position.
- * @throws Exception
- */
@Test
- public void testlaunchEmptyWindowLayout() throws Exception {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
- new WindowLayout(0, 0, 0, 0, Gravity.NO_GRAVITY, 0, 0), null /*activity*/,
- null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(mResult.mBounds, getDefaultBounds(Gravity.NO_GRAVITY));
+ public void testUsesSourcesDisplayIdIfSet() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+ final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ ActivityRecord source = createSourceActivity(fullscreenDisplay);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, /* options */ null, mCurrent, mResult));
+
+ assertEquals(fullscreenDisplay.mDisplayId, mResult.mPreferredDisplayId);
}
- /**
- * Ensures that a task positioned with a {@link WindowLayout} gravity specified is positioned
- * according to specification.
- * @throws Exception
- */
@Test
- public void testlaunchWindowLayoutGravity() throws Exception {
- // Unspecified gravity should be ignored
- testGravity(Gravity.NO_GRAVITY);
+ public void testUsesOptionsDisplayIdIfSet() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+ final TestActivityDisplay fullscreenDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FULLSCREEN);
- // Unsupported gravity should be ignored
- testGravity(Gravity.LEFT);
- testGravity(Gravity.RIGHT);
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ ActivityRecord source = createSourceActivity(freeformDisplay);
- // Test defaults for vertical gravities
- testGravity(Gravity.TOP);
- testGravity(Gravity.BOTTOM);
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(fullscreenDisplay.mDisplayId);
- // Test corners
- testGravity(Gravity.TOP | Gravity.LEFT);
- testGravity(Gravity.TOP | Gravity.RIGHT);
- testGravity(Gravity.BOTTOM | Gravity.LEFT);
- testGravity(Gravity.BOTTOM | Gravity.RIGHT);
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ assertEquals(fullscreenDisplay.mDisplayId, mResult.mPreferredDisplayId);
}
- private void testGravity(int gravity) {
- try {
- assertEquals(RESULT_CONTINUE, mPositioner.onCalculate(mTask,
- new WindowLayout(0, 0, 0, 0, gravity, 0, 0), null /*activity*/,
- null /*source*/, null /*options*/, mCurrent, mResult));
- assertEquals(mResult.mBounds, getDefaultBounds(gravity));
- } finally {
- mCurrent.reset();
- mResult.reset();
+ // =====================================
+ // Launch Windowing Mode Related Tests
+ // =====================================
+ @Test
+ public void testBoundsInOptionsInfersFreeformOnFreeformDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchBounds(new Rect(0, 0, 100, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testBoundsInOptionsInfersFreeformWithResizeableActivity() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchBounds(new Rect(0, 0, 100, 100));
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testKeepsPictureInPictureLaunchModeInOptions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_PINNED, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testKeepsPictureInPictureLaunchModeWithBoundsInOptions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+ options.setLaunchBounds(new Rect(0, 0, 100, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_PINNED, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testKeepsFullscreenLaunchModeInOptionsOnNonFreeformDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testNonEmptyLayoutInfersFreeformOnFreeformDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testNonEmptyLayoutInfersFreeformWithEmptySize() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testNonEmptyLayoutInfersFreeformWithResizeableActivity() {
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testRespectsFullyResolvedCurrentParam_Fullscreen() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testRespectsModeFromFullyResolvedCurrentParam_NonEmptyBounds() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testForceMaximizesPreDApp() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.CUPCAKE;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testForceMaximizesAppWithoutMultipleDensitySupport() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.appInfo.flags = 0;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testForceMaximizesUnresizeableApp() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testSkipsForceMaximizingAppsOnNonFreeformDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
+ options.setLaunchBounds(new Rect(0, 0, 200, 100));
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testUsesFullscreenOnNonFreeformDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(DEFAULT_DISPLAY);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ @Test
+ public void testUsesFreeformByDefaultForPostNApp() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testUsesFreeformByDefaultForPreNResizeableAppWithoutOrientationRequest() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+ WINDOWING_MODE_FREEFORM);
+ }
+
+ @Test
+ public void testSkipsFreeformForPreNResizeableAppOnNonFullscreenDisplay() {
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(DEFAULT_DISPLAY);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquivalentWindowingMode(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode,
+ WINDOWING_MODE_FULLSCREEN);
+ }
+
+ // ================================
+ // Launching Bounds Related Tests
+ // ===============================
+ @Test
+ public void testKeepsBoundsWithPictureInPictureLaunchModeInOptions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_PINNED);
+
+ final Rect expected = new Rect(0, 0, 100, 100);
+ options.setLaunchBounds(expected);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(expected, mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_LeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(0, mResult.mBounds.left);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.TOP).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(0, mResult.mBounds.top);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_TopLeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.TOP | Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(0, mResult.mBounds.left);
+ assertEquals(0, mResult.mBounds.top);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_RightGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.RIGHT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(1920, mResult.mBounds.right);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.BOTTOM).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(1080, mResult.mBounds.bottom);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsRespectsGravityWithEmptySize_BottomRightGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setGravity(Gravity.BOTTOM | Gravity.RIGHT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(1920, mResult.mBounds.right);
+ assertEquals(1080, mResult.mBounds.bottom);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_CenterToDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 500, 1020, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_LeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 500, 120, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.TOP).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 0, 1020, 80), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_TopLeftGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.TOP | Gravity.LEFT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 120, 80), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.RIGHT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(1800, 500, 1920, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_BottomGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.BOTTOM).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 1000, 1020, 1080), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsOnFreeformDisplay_RightBottomGravity() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).setGravity(Gravity.BOTTOM | Gravity.RIGHT).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(1800, 1000, 1920, 1080), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutFractionBoundsOnFreeformDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidthFraction(0.0625f).setHeightFraction(0.1f).build();
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 486, 1020, 594), mResult.mBounds);
+ }
+
+ @Test
+ public void testNonEmptyLayoutBoundsWithResizeableActivity() {
+ final ActivityDisplay display = mSupervisor.getActivityDisplay(DEFAULT_DISPLAY);
+ display.setBounds(new Rect(0, 0, 1920, 1080));
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setWidth(120).setHeight(80).build();
+
+ mCurrent.mPreferredDisplayId = DEFAULT_DISPLAY;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(900, 500, 1020, 580), mResult.mBounds);
+ }
+
+ @Test
+ public void testRespectBoundsFromFullyResolvedCurrentParam_NonEmptyBounds() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ mCurrent.mPreferredDisplayId = freeformDisplay.mDisplayId;
+ mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
+ mCurrent.mBounds.set(0, 0, 200, 100);
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, /* options */ null, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 200, 100), mResult.mBounds);
+ }
+
+ @Test
+ public void testDefaultSizeSmallerThanBigScreen() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ final int resultWidth = mResult.mBounds.width();
+ final int displayWidth = freeformDisplay.getBounds().width();
+ assertTrue("Result width " + resultWidth + " is not smaller than " + displayWidth,
+ resultWidth < displayWidth);
+
+ final int resultHeight = mResult.mBounds.height();
+ final int displayHeight = freeformDisplay.getBounds().height();
+ assertTrue("Result width " + resultHeight + " is not smaller than "
+ + displayHeight, resultHeight < displayHeight);
+ }
+
+ @Test
+ public void testDefaultFreeformSizeCenteredToDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertEquals("Distance to left and right should be equal.",
+ mResult.mBounds.left - displayBounds.left,
+ displayBounds.right - mResult.mBounds.right);
+ assertEquals("Distance to top and bottom should be equal.",
+ mResult.mBounds.top - displayBounds.top,
+ displayBounds.bottom - mResult.mBounds.bottom);
+ }
+
+ @Test
+ public void testCascadesToSourceSizeForFreeform() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(0, 0, 412, 732);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("Left bounds should be larger than 0.", mResult.mBounds.left > 0);
+ assertTrue("Top bounds should be larger than 0.", mResult.mBounds.top > 0);
+ assertTrue("Bounds should be centered at somewhere in the left half, but it's "
+ + "centerX is " + mResult.mBounds.centerX(),
+ mResult.mBounds.centerX() < displayBounds.centerX());
+ assertTrue("Bounds should be centered at somewhere in the top half, but it's "
+ + "centerY is " + mResult.mBounds.centerY(),
+ mResult.mBounds.centerY() < displayBounds.centerY());
+ }
+
+ @Test
+ public void testAdjustBoundsToFitDisplay_TopLeftOutOfDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(0, 0, 200, 400);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("display bounds doesn't contain result. display bounds: "
+ + displayBounds + " result: " + mResult.mBounds,
+ displayBounds.contains(mResult.mBounds));
+ }
+
+ @Test
+ public void testAdjustBoundsToFitDisplay_BottomRightOutOfDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(1720, 680, 1920, 1080);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("display bounds doesn't contain result. display bounds: "
+ + displayBounds + " result: " + mResult.mBounds,
+ displayBounds.contains(mResult.mBounds));
+ }
+
+ @Test
+ public void testAdjustBoundsToFitDisplay_LargerThanDisplay() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ Configuration overrideConfig = new Configuration();
+ overrideConfig.setTo(mSupervisor.getOverrideConfiguration());
+ overrideConfig.setLayoutDirection(new Locale("ar"));
+ mSupervisor.onConfigurationChanged(overrideConfig);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityRecord source = createSourceActivity(freeformDisplay);
+ source.setBounds(1720, 680, 1920, 1080);
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, source, options, mCurrent, mResult));
+
+ final Rect displayBounds = freeformDisplay.getBounds();
+ assertTrue("display bounds doesn't contain result. display bounds: "
+ + displayBounds + " result: " + mResult.mBounds,
+ displayBounds.contains(mResult.mBounds));
+ }
+
+ @Test
+ public void testRespectsLayoutMinDimensions() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+
+ final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
+ .setMinWidth(500).setMinHeight(800).build();
+
+ mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
+ /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(500, mResult.mBounds.width());
+ assertEquals(800, mResult.mBounds.height());
+ }
+
+ @Test
+ public void testRotatesInPlaceInitialBoundsMismatchOrientation() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(100, 100, 500, 300));
+
+ mActivity.info.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(200, 0, 400, 400), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToRightForCloseToLeftBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(50, 50, 100, 150));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(50, 50, 500, 300));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(170, 50, 620, 300), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToLeftForCloseToRightBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(1720, 50, 1830, 150));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(1720, 50, 1850, 300));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(1600, 50, 1730, 300), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToRightFirstForHorizontallyCenteredAndCloseToTopWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(0, 0, 100, 300));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(0, 0, 1800, 200));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(120, 0, 1920, 200), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToLeftNoSpaceOnRightForHorizontallyCenteredAndCloseToTopWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 300));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(120, 0, 1860, 200));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 1740, 200), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToBottomRightFirstForCenteredBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(120, 0, 240, 100));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(120, 0, 1800, 1013));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(240, 67, 1920, 1080), mResult.mBounds);
+ }
+
+ @Test
+ public void testShiftsToTopLeftIfNoSpaceOnBottomRightForCenteredBoundsWhenConflict() {
+ final TestActivityDisplay freeformDisplay = createNewActivityDisplay(
+ WINDOWING_MODE_FREEFORM);
+
+ addFreeformTaskTo(freeformDisplay, new Rect(120, 67, 240, 100));
+
+ final ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(freeformDisplay.mDisplayId);
+ options.setLaunchBounds(new Rect(120, 67, 1800, 1020));
+
+ assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
+ mActivity, /* source */ null, options, mCurrent, mResult));
+
+ assertEquals(new Rect(0, 0, 1680,
+ 953), mResult.mBounds);
+ }
+
+ private TestActivityDisplay createNewActivityDisplay(int windowingMode) {
+ final TestActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
+ display.setWindowingMode(windowingMode);
+ display.setBounds(/* left */ 0, /* top */ 0, /* right */ 1920, /* bottom */ 1080);
+ display.getConfiguration().densityDpi = DENSITY_DEFAULT;
+ return display;
+ }
+
+ private ActivityRecord createSourceActivity(TestActivityDisplay display) {
+ final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+ ACTIVITY_TYPE_STANDARD, true);
+ return new ActivityBuilder(mService).setStack(stack).setCreateTask(true).build();
+ }
+
+ private void addFreeformTaskTo(TestActivityDisplay display, Rect bounds) {
+ final TestActivityStack stack = display.createStack(display.getWindowingMode(),
+ ACTIVITY_TYPE_STANDARD, true);
+ stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+ task.setBounds(bounds);
+ }
+
+ private void assertEquivalentWindowingMode(int expected, int actual, int parentWindowingMode) {
+ if (expected != parentWindowingMode) {
+ assertEquals(expected, actual);
+ } else {
+ assertEquals(WINDOWING_MODE_UNDEFINED, actual);
}
}
- /**
- * Ensures that a task which causes a conflict with another task when positioned is adjusted as
- * expected.
- * @throws Exception
- */
- @Test
- public void testLaunchWindowCenterConflict() throws Exception {
- testConflict(Gravity.NO_GRAVITY);
- testConflict(Gravity.TOP);
- testConflict(Gravity.BOTTOM);
- testConflict(Gravity.TOP | Gravity.LEFT);
- testConflict(Gravity.TOP | Gravity.RIGHT);
- testConflict(Gravity.BOTTOM | Gravity.LEFT);
- testConflict(Gravity.BOTTOM | Gravity.RIGHT);
- }
+ private static class WindowLayoutBuilder {
+ private int mWidth = -1;
+ private int mHeight = -1;
+ private float mWidthFraction = -1f;
+ private float mHeightFraction = -1f;
+ private int mGravity = Gravity.NO_GRAVITY;
+ private int mMinWidth = -1;
+ private int mMinHeight = -1;
- private void testConflict(int gravity) {
- final WindowLayout layout = new WindowLayout(0, 0, 0, 0, gravity, 0, 0);
-
- // layout first task
- mService.mStackSupervisor.getLaunchParamsController().layoutTask(mTask, layout);
-
- // Second task will be laid out on top of the first so starting bounds is the same.
- final Rect expectedBounds = new Rect(mTask.getOverrideBounds());
-
- ActivityRecord activity = null;
- TaskRecord secondTask = null;
-
- // wrap with try/finally to ensure cleanup of activity/stack.
- try {
- // empty tasks are ignored in conflicts
- activity = new ActivityBuilder(mService).setTask(mTask).build();
-
- // Create secondary task
- secondTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
-
- // layout second task
- assertEquals(RESULT_CONTINUE,
- mPositioner.onCalculate(secondTask, layout, null /*activity*/,
- null /*source*/, null /*options*/, mCurrent, mResult));
-
- if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)
- || (gravity & (Gravity.BOTTOM | Gravity.RIGHT))
- == (Gravity.BOTTOM | Gravity.RIGHT)) {
- expectedBounds.offset(-TaskLaunchParamsModifier.getHorizontalStep(
- mStack.getOverrideBounds()), 0);
- } else if ((gravity & Gravity.TOP) == Gravity.TOP
- || (gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
- expectedBounds.offset(
- TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()), 0);
- } else {
- expectedBounds.offset(
- TaskLaunchParamsModifier.getHorizontalStep(mStack.getOverrideBounds()),
- TaskLaunchParamsModifier.getVerticalStep(mStack.getOverrideBounds()));
- }
-
- assertEquals(mResult.mBounds, expectedBounds);
- } finally {
- // Remove task and activity to prevent influencing future tests
- if (activity != null) {
- mTask.removeActivity(activity);
- }
-
- if (secondTask != null) {
- mStack.removeTask(secondTask, "cleanup", ActivityStack.REMOVE_TASK_MODE_DESTROYING);
- }
- }
- }
-
- private Rect getDefaultBounds(int gravity) {
- final Rect bounds = new Rect();
- bounds.set(mStack.getOverrideBounds());
-
- final int verticalInset =
- TaskLaunchParamsModifier.getFreeformStartTop(mStack.getOverrideBounds());
- final int horizontalInset =
- TaskLaunchParamsModifier.getFreeformStartLeft(mStack.getOverrideBounds());
-
- bounds.inset(horizontalInset, verticalInset);
-
- if ((gravity & (Gravity.TOP | Gravity.RIGHT)) == (Gravity.TOP | Gravity.RIGHT)) {
- bounds.offsetTo(horizontalInset * 2, 0);
- } else if ((gravity & Gravity.TOP) == Gravity.TOP) {
- bounds.offsetTo(0, 0);
- } else if ((gravity & (Gravity.BOTTOM | Gravity.RIGHT))
- == (Gravity.BOTTOM | Gravity.RIGHT)) {
- bounds.offsetTo(horizontalInset * 2, verticalInset * 2);
- } else if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) {
- bounds.offsetTo(0, verticalInset * 2);
+ private WindowLayoutBuilder setWidth(int width) {
+ mWidth = width;
+ return this;
}
- return bounds;
+ private WindowLayoutBuilder setHeight(int height) {
+ mHeight = height;
+ return this;
+ }
+
+ private WindowLayoutBuilder setWidthFraction(float widthFraction) {
+ mWidthFraction = widthFraction;
+ return this;
+ }
+
+ private WindowLayoutBuilder setHeightFraction(float heightFraction) {
+ mHeightFraction = heightFraction;
+ return this;
+ }
+
+ private WindowLayoutBuilder setGravity(int gravity) {
+ mGravity = gravity;
+ return this;
+ }
+
+ private WindowLayoutBuilder setMinWidth(int minWidth) {
+ mMinWidth = minWidth;
+ return this;
+ }
+
+ private WindowLayoutBuilder setMinHeight(int minHeight) {
+ mMinHeight = minHeight;
+ return this;
+ }
+
+ private ActivityInfo.WindowLayout build() {
+ return new ActivityInfo.WindowLayout(mWidth, mWidthFraction, mHeight, mHeightFraction,
+ mGravity, mMinWidth, mMinHeight);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
index 7125246..3c8b2a0 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DragDropControllerTests.java
@@ -40,27 +40,25 @@
import android.view.SurfaceSession;
import android.view.View;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import androidx.test.filters.SmallTest;
+
/**
* Tests for the {@link DragDropController} class.
*
- * atest FrameworksServicesTests:com.android.server.wm.DragDropControllerTests
+ * Build/Install/Run:
+ * atest FrameworksServicesTests:com.android.server.wm.DragDropControllerTests
*/
@SmallTest
-@RunWith(AndroidJUnit4.class)
@Presubmit
public class DragDropControllerTests extends WindowTestsBase {
private static final int TIMEOUT_MS = 3000;
@@ -109,6 +107,7 @@
return window;
}
+ @Override
@Before
public void setUp() throws Exception {
final UserManagerInternal userManager = mock(UserManagerInternal.class);
@@ -127,6 +126,7 @@
}
}
+ @Override
@After
public void tearDown() throws Exception {
LocalServices.removeServiceForTest(UserManagerInternal.class);
@@ -139,25 +139,25 @@
mTarget.cancelDragAndDrop(mToken);
}
latch = new CountDownLatch(1);
- mTarget.setOnClosedCallbackLocked(() -> {
- latch.countDown();
- });
+ mTarget.setOnClosedCallbackLocked(latch::countDown);
}
assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+ super.tearDown();
}
@Test
- public void testDragFlow() throws Exception {
+ public void testDragFlow() {
dragFlow(0, ClipData.newPlainText("label", "Test"), 0, 0);
}
@Test
- public void testPerformDrag_NullDataWithGrantUri() throws Exception {
+ public void testPerformDrag_NullDataWithGrantUri() {
dragFlow(View.DRAG_FLAG_GLOBAL | View.DRAG_FLAG_GLOBAL_URI_READ, null, 0, 0);
}
@Test
- public void testPerformDrag_NullDataToOtherUser() throws Exception {
+ public void testPerformDrag_NullDataToOtherUser() {
final WindowState otherUsersWindow =
createDropTargetWindow("Other user's window", 1 * UserHandle.PER_USER_RANGE);
doReturn(otherUsersWindow).when(mDisplayContent).getTouchableWinAtPointLocked(10, 10);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 6f4f173..33b137e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -29,14 +29,14 @@
import android.graphics.Rect;
import android.os.UserManager;
-import androidx.test.InstrumentationRegistry;
-
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import java.io.File;
+import androidx.test.InstrumentationRegistry;
+
/**
* Base class for tests that use a {@link TaskSnapshotPersister}.
*/
@@ -54,9 +54,11 @@
sFilesDir = InstrumentationRegistry.getContext().getFilesDir();
}
+ @Override
@Before
public void setUp() throws Exception {
super.setUp();
+
final UserManager um = UserManager.get(InstrumentationRegistry.getContext());
mTestUserId = um.getUserHandle();
mPersister = new TaskSnapshotPersister(userId -> sFilesDir);
@@ -64,9 +66,12 @@
mPersister.start();
}
+ @Override
@After
public void tearDown() throws Exception {
cleanDirectory();
+
+ super.tearDown();
}
private void cleanDirectory() {
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index ea44279..0e9a63c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -19,36 +19,37 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
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.After;
import org.junit.Before;
import org.junit.Test;
-import org.junit.runner.RunWith;
+
+import androidx.test.filters.SmallTest;
/**
* Tests for the {@link DisplayContent.TaskStackContainers} container in {@link DisplayContent}.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.TaskStackContainersTests
+ * atest FrameworksServicesTests:com.android.server.wm.TaskStackContainersTests
*/
@SmallTest
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class TaskStackContainersTests extends WindowTestsBase {
private TaskStack mPinnedStack;
+ @Override
@Before
public void setUp() throws Exception {
super.setUp();
+
mPinnedStack = createStackControllerOnStackOnDisplay(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent).mContainer;
// Stack should contain visible app window to be considered visible.
@@ -60,13 +61,16 @@
assertTrue(mPinnedStack.isVisible());
}
+ @Override
@After
public void tearDown() throws Exception {
mPinnedStack.removeImmediately();
+
+ super.tearDown();
}
@Test
- public void testStackPositionChildAt() throws Exception {
+ public void testStackPositionChildAt() {
// Test that always-on-top stack can't be moved to position other than top.
final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
final TaskStack stack2 = createTaskStackOnDisplay(mDisplayContent);
@@ -76,8 +80,8 @@
final int stack1Pos = taskStackContainer.mChildren.indexOf(stack1);
final int stack2Pos = taskStackContainer.mChildren.indexOf(stack2);
final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack);
- assertGreaterThan(pinnedStackPos, stack2Pos);
- assertGreaterThan(stack2Pos, stack1Pos);
+ assertThat(pinnedStackPos).isGreaterThan(stack2Pos);
+ assertThat(stack2Pos).isGreaterThan(stack1Pos);
taskStackContainer.positionChildAt(WindowContainer.POSITION_BOTTOM, mPinnedStack, false);
assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1);
@@ -91,7 +95,7 @@
}
@Test
- public void testStackPositionBelowPinnedStack() throws Exception {
+ public void testStackPositionBelowPinnedStack() {
// Test that no stack can be above pinned stack.
final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
@@ -99,7 +103,7 @@
final int stackPos = taskStackContainer.mChildren.indexOf(stack1);
final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack);
- assertGreaterThan(pinnedStackPos, stackPos);
+ assertThat(pinnedStackPos).isGreaterThan(stackPos);
taskStackContainer.positionChildAt(WindowContainer.POSITION_TOP, stack1, false);
assertEquals(taskStackContainer.mChildren.get(stackPos), stack1);
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 70e4ce4..cf67d78 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -48,18 +48,17 @@
import android.view.IWindow;
import android.view.WindowManager;
-import androidx.test.InstrumentationRegistry;
-
import com.android.server.AttributeCache;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import java.util.HashSet;
import java.util.LinkedList;
+import androidx.test.InstrumentationRegistry;
+
/**
* Common base class for window manager unit test classes.
*
@@ -194,14 +193,6 @@
}
}
- /**
- * @return A SurfaceBuilderFactory to inject in to the WindowManagerService during
- * set-up (or null).
- */
- SurfaceBuilderFactory getSurfaceBuilderFactory() {
- return null;
- }
-
private WindowState createCommonWindow(WindowState parent, int type, String name) {
synchronized (sWm.mWindowMap) {
final WindowState win = createWindow(parent, type, name);
@@ -212,16 +203,6 @@
}
}
- /** Asserts that the first entry is greater than the second entry. */
- void assertGreaterThan(int first, int second) throws Exception {
- Assert.assertTrue("Excepted " + first + " to be greater than " + second, first > second);
- }
-
- /** Asserts that the first entry is greater than the second entry. */
- void assertLessThan(int first, int second) throws Exception {
- Assert.assertTrue("Excepted " + first + " to be less than " + second, first < second);
- }
-
/**
* Waits until the main handler for WM has processed all messages.
*/
diff --git a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
index 8f9fb1b..a610e6e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ZOrderingTests.java
@@ -32,36 +32,35 @@
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
+import static com.google.common.truth.Truth.assertThat;
+
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
import org.junit.After;
import org.junit.Test;
-import org.junit.runner.RunWith;
import java.util.HashMap;
import java.util.LinkedList;
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
/**
* Tests for the {@link WindowLayersController} class.
*
* Build/Install/Run:
- * bit FrameworksServicesTests:com.android.server.wm.ZOrderingTests
+ * atest FrameworksServicesTests:com.android.server.wm.ZOrderingTests
*/
@SmallTest
@FlakyTest(bugId = 74078662)
@Presubmit
-@RunWith(AndroidJUnit4.class)
public class ZOrderingTests extends WindowTestsBase {
private class LayerRecordingTransaction extends SurfaceControl.Transaction {
- HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap();
- HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap();
+ HashMap<SurfaceControl, Integer> mLayersForControl = new HashMap<>();
+ HashMap<SurfaceControl, SurfaceControl> mRelativeLayersForControl = new HashMap<>();
@Override
public SurfaceControl.Transaction setLayer(SurfaceControl sc, int layer) {
@@ -86,11 +85,11 @@
private SurfaceControl getRelativeLayer(SurfaceControl sc) {
return mRelativeLayersForControl.get(sc);
}
- };
+ }
// We have WM use our Hierarchy recording subclass of SurfaceControl.Builder
// such that we can keep track of the parents of Surfaces as they are constructed.
- private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap();
+ private HashMap<SurfaceControl, SurfaceControl> mParentFor = new HashMap<>();
private class HierarchyRecorder extends SurfaceControl.Builder {
SurfaceControl mPendingParent;
@@ -109,13 +108,13 @@
mPendingParent = null;
return sc;
}
- };
+ }
class HierarchyRecordingBuilderFactory implements SurfaceBuilderFactory {
public SurfaceControl.Builder make(SurfaceSession s) {
return new HierarchyRecorder(s);
}
- };
+ }
private LayerRecordingTransaction mTransaction;
@@ -136,7 +135,7 @@
}
LinkedList<SurfaceControl> getAncestors(LayerRecordingTransaction t, SurfaceControl sc) {
- LinkedList<SurfaceControl> p = new LinkedList();
+ LinkedList<SurfaceControl> p = new LinkedList<>();
SurfaceControl current = sc;
do {
p.addLast(current);
@@ -153,7 +152,7 @@
void assertZOrderGreaterThan(LayerRecordingTransaction t, SurfaceControl left,
- SurfaceControl right) throws Exception {
+ SurfaceControl right) {
final LinkedList<SurfaceControl> leftParentChain = getAncestors(t, left);
final LinkedList<SurfaceControl> rightParentChain = getAncestors(t, right);
@@ -168,16 +167,15 @@
}
if (rightTop == null) { // right is the parent of left.
- assertGreaterThan(t.getLayer(leftTop), 0);
+ assertThat(t.getLayer(leftTop)).isGreaterThan(0);
} else if (leftTop == null) { // left is the parent of right.
- assertGreaterThan(0, t.getLayer(rightTop));
+ assertThat(t.getLayer(rightTop)).isLessThan(0);
} else {
- assertGreaterThan(t.getLayer(leftTop),
- t.getLayer(rightTop));
+ assertThat(t.getLayer(leftTop)).isGreaterThan(t.getLayer(rightTop));
}
}
- void assertWindowHigher(WindowState left, WindowState right) throws Exception {
+ void assertWindowHigher(WindowState left, WindowState right) {
assertZOrderGreaterThan(mTransaction, left.getSurfaceControl(), right.getSurfaceControl());
}
@@ -186,7 +184,7 @@
}
@Test
- public void testAssignWindowLayers_ForImeWithNoTarget() throws Exception {
+ public void testAssignWindowLayers_ForImeWithNoTarget() {
sWm.mInputMethodTarget = null;
mDisplayContent.assignChildLayers(mTransaction);
@@ -203,7 +201,7 @@
}
@Test
- public void testAssignWindowLayers_ForImeWithAppTarget() throws Exception {
+ public void testAssignWindowLayers_ForImeWithAppTarget() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
sWm.mInputMethodTarget = imeAppTarget;
@@ -222,7 +220,7 @@
}
@Test
- public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() throws Exception {
+ public void testAssignWindowLayers_ForImeWithAppTargetWithChildWindows() {
final WindowState imeAppTarget = createWindow("imeAppTarget");
final WindowState imeAppTargetChildAboveWindow = createWindow(imeAppTarget,
TYPE_APPLICATION_ATTACHED_DIALOG, imeAppTarget.mToken,
@@ -248,7 +246,7 @@
}
@Test
- public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() throws Exception {
+ public void testAssignWindowLayers_ForImeWithAppTargetAndAppAbove() {
final WindowState appBelowImeTarget = createWindow("appBelowImeTarget");
final WindowState imeAppTarget = createWindow("imeAppTarget");
final WindowState appAboveImeTarget = createWindow("appAboveImeTarget");
@@ -271,7 +269,7 @@
}
@Test
- public void testAssignWindowLayers_ForImeNonAppImeTarget() throws Exception {
+ public void testAssignWindowLayers_ForImeNonAppImeTarget() {
final WindowState imeSystemOverlayTarget = createWindow(null, TYPE_SYSTEM_OVERLAY,
mDisplayContent, "imeSystemOverlayTarget",
true /* ownerCanAddInternalSystemWindow */);
@@ -298,7 +296,7 @@
}
@Test
- public void testAssignWindowLayers_ForStatusBarImeTarget() throws Exception {
+ public void testAssignWindowLayers_ForStatusBarImeTarget() {
sWm.mInputMethodTarget = mStatusBarWindow;
mDisplayContent.assignChildLayers(mTransaction);
@@ -312,7 +310,7 @@
}
@Test
- public void testStackLayers() throws Exception {
+ public void testStackLayers() {
final WindowState anyWindow1 = createWindow("anyWindow");
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
@@ -342,7 +340,7 @@
}
@Test
- public void testAssignWindowLayers_ForSysUiPanels() throws Exception {
+ public void testAssignWindowLayers_ForSysUiPanels() {
final WindowState navBarPanel =
createWindow(null, TYPE_NAVIGATION_BAR_PANEL, mDisplayContent, "NavBarPanel");
final WindowState statusBarPanel =
@@ -359,7 +357,7 @@
}
@Test
- public void testAssignWindowLayers_ForNegativelyZOrderedSubtype() throws Exception {
+ public void testAssignWindowLayers_ForNegativelyZOrderedSubtype() {
// TODO(b/70040778): We should aim to eliminate the last user of TYPE_APPLICATION_MEDIA
// then we can drop all negative layering on the windowing side.
@@ -376,7 +374,7 @@
}
@Test
- public void testDockedDividerPosition() throws Exception {
+ public void testDockedDividerPosition() {
final WindowState pinnedStackWindow = createWindowOnStack(null, WINDOWING_MODE_PINNED,
ACTIVITY_TYPE_STANDARD, TYPE_BASE_APPLICATION, mDisplayContent,
"pinnedStackWindow");
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 08bc9bc..daa09f5 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -397,7 +397,19 @@
public static final int PROPERTY_WIFI = 0x00000008;
/**
- * Call is using high definition audio.
+ * When set, the UI should indicate to the user that a call is using high definition
+ * audio.
+ * <p>
+ * The underlying {@link ConnectionService} is responsible for reporting this
+ * property. It is important to note that this property is not intended to report the
+ * actual audio codec being used for a Call, but whether the call should be indicated
+ * to the user as high definition.
+ * <p>
+ * The Android Telephony stack reports this property for calls based on a number
+ * of factors, including which audio codec is used and whether a call is using an HD
+ * codec end-to-end. Some mobile operators choose to suppress display of an HD indication,
+ * and in these cases this property will not be set for a call even if the underlying audio
+ * codec is in fact "high definition".
*/
public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 4846092..8454d12 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3289,7 +3289,6 @@
values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex());
values.put(CDMA_ERI_ICON_MODE, state.getCdmaEriIconMode());
values.put(IS_EMERGENCY_ONLY, state.isEmergencyOnly());
- values.put(IS_DATA_ROAMING_FROM_REGISTRATION, state.getDataRoamingFromRegistration());
values.put(IS_USING_CARRIER_AGGREGATION, state.isUsingCarrierAggregation());
return values;
}
diff --git a/telephony/java/android/telephony/NeighboringCellInfo.java b/telephony/java/android/telephony/NeighboringCellInfo.java
index 79298fd..ac38efb 100644
--- a/telephony/java/android/telephony/NeighboringCellInfo.java
+++ b/telephony/java/android/telephony/NeighboringCellInfo.java
@@ -34,8 +34,8 @@
* Received Signal Strength and Cell ID location.
*
* @deprecated This class should not be used by any app targeting
- * {@link Build.VERSION_CODES.Q Android Q} or higher. Instead callers should use
- * {@Link android.telephony.CellInfo CellInfo}.
+ * {@link android.os.Build.VERSION_CODES#Q Android Q} or higher. Instead callers should use
+ * {@link android.telephony.CellInfo CellInfo}.
*/
@Deprecated
public class NeighboringCellInfo implements Parcelable
diff --git a/telephony/java/android/telephony/NetworkRegistrationState.java b/telephony/java/android/telephony/NetworkRegistrationState.java
index c393155..b312f84 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -95,6 +95,13 @@
@RegState
private final int mRegState;
+ /**
+ * Save the {@link ServiceState.RoamingType roaming type}. it can be overridden roaming type
+ * from resource overlay or carrier config.
+ */
+ @ServiceState.RoamingType
+ private int mRoamingType;
+
private final int mAccessNetworkTechnology;
private final int mRejectCause;
@@ -140,6 +147,8 @@
mDomain = domain;
mTransportType = transportType;
mRegState = regState;
+ mRoamingType = (regState == REG_STATE_ROAMING)
+ ? ServiceState.ROAMING_TYPE_UNKNOWN : ServiceState.ROAMING_TYPE_NOT_ROAMING;
mAccessNetworkTechnology = accessNetworkTechnology;
mRejectCause = rejectCause;
mAvailableServices = availableServices;
@@ -182,6 +191,7 @@
mDomain = source.readInt();
mTransportType = source.readInt();
mRegState = source.readInt();
+ mRoamingType = source.readInt();
mAccessNetworkTechnology = source.readInt();
mRejectCause = source.readInt();
mEmergencyOnly = source.readBoolean();
@@ -211,6 +221,31 @@
}
/**
+ * @return {@code true} if registered on roaming network, {@code false} otherwise.
+ */
+ public boolean isRoaming() {
+ return mRoamingType != ServiceState.ROAMING_TYPE_NOT_ROAMING;
+ }
+
+ /**
+ * Set {@link ServiceState.RoamingType roaming type}. This could override
+ * roaming type based on resource overlay or carrier config.
+ * @hide
+ */
+ public void setRoamingType(@ServiceState.RoamingType int roamingType) {
+ mRoamingType = roamingType;
+ }
+
+ /**
+ * @return {@link ServiceState.RoamingType roaming type}. This could return
+ * overridden roaming type based on resource overlay or carrier config.
+ * @hide
+ */
+ public @ServiceState.RoamingType int getRoamingType() {
+ return mRoamingType;
+ }
+
+ /**
* @return Whether emergency is enabled.
*/
public boolean isEmergencyEnabled() { return mEmergencyOnly; }
@@ -280,6 +315,7 @@
.append(" domain=").append((mDomain == DOMAIN_CS) ? "CS" : "PS")
.append("transportType=").append(mTransportType)
.append(" regState=").append(regStateToString(mRegState))
+ .append(" roamingType=").append(mRoamingType)
.append(" accessNetworkTechnology=")
.append(TelephonyManager.getNetworkTypeName(mAccessNetworkTechnology))
.append(" rejectCause=").append(mRejectCause)
@@ -293,9 +329,9 @@
@Override
public int hashCode() {
- return Objects.hash(mDomain, mTransportType, mRegState, mAccessNetworkTechnology,
- mRejectCause, mEmergencyOnly, mAvailableServices, mCellIdentity,
- mVoiceSpecificStates, mDataSpecificStates);
+ return Objects.hash(mDomain, mTransportType, mRegState, mRoamingType,
+ mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices,
+ mCellIdentity, mVoiceSpecificStates, mDataSpecificStates);
}
@Override
@@ -310,6 +346,7 @@
return mDomain == other.mDomain
&& mTransportType == other.mTransportType
&& mRegState == other.mRegState
+ && mRoamingType == other.mRoamingType
&& mAccessNetworkTechnology == other.mAccessNetworkTechnology
&& mRejectCause == other.mRejectCause
&& mEmergencyOnly == other.mEmergencyOnly
@@ -325,6 +362,7 @@
dest.writeInt(mDomain);
dest.writeInt(mTransportType);
dest.writeInt(mRegState);
+ dest.writeInt(mRoamingType);
dest.writeInt(mAccessNetworkTechnology);
dest.writeInt(mRejectCause);
dest.writeBoolean(mEmergencyOnly);
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 7469186..e0ec2c5 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -20,6 +20,7 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
+import android.content.Intent;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -57,7 +58,7 @@
* Normal operation condition, the phone is registered
* with an operator either in home network or in roaming.
*/
- public static final int STATE_IN_SERVICE = 0;
+ public static final int STATE_IN_SERVICE = TelephonyProtoEnums.SERVICE_STATE_IN_SERVICE; // 0
/**
* Phone is not registered with any operator, the phone
@@ -65,17 +66,19 @@
* searching to registration at all, or registration is denied, or radio
* signal is not available.
*/
- public static final int STATE_OUT_OF_SERVICE = 1;
+ public static final int STATE_OUT_OF_SERVICE =
+ TelephonyProtoEnums.SERVICE_STATE_OUT_OF_SERVICE; // 1
/**
* The phone is registered and locked. Only emergency numbers are allowed. {@more}
*/
- public static final int STATE_EMERGENCY_ONLY = 2;
+ public static final int STATE_EMERGENCY_ONLY =
+ TelephonyProtoEnums.SERVICE_STATE_EMERGENCY_ONLY; // 2
/**
* Radio of telephony is explicitly powered off.
*/
- public static final int STATE_POWER_OFF = 3;
+ public static final int STATE_POWER_OFF = TelephonyProtoEnums.SERVICE_STATE_POWER_OFF; // 3
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -198,6 +201,15 @@
private int mVoiceRegState = STATE_OUT_OF_SERVICE;
private int mDataRegState = STATE_OUT_OF_SERVICE;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "ROAMING_TYPE_" }, value = {
+ ROAMING_TYPE_NOT_ROAMING,
+ ROAMING_TYPE_UNKNOWN,
+ ROAMING_TYPE_DOMESTIC,
+ ROAMING_TYPE_INTERNATIONAL
+ })
+ public @interface RoamingType {}
/**
* Roaming type
* HOME : in home network
@@ -228,8 +240,6 @@
*/
public static final int UNKNOWN_ID = -1;
- private int mVoiceRoamingType;
- private int mDataRoamingType;
private String mVoiceOperatorAlphaLong;
private String mVoiceOperatorAlphaShort;
private String mVoiceOperatorNumeric;
@@ -259,8 +269,6 @@
@UnsupportedAppUsage
private int mCdmaEriIconMode;
- private boolean mIsDataRoamingFromRegistration;
-
@UnsupportedAppUsage
private boolean mIsUsingCarrierAggregation;
@@ -332,8 +340,6 @@
protected void copyFrom(ServiceState s) {
mVoiceRegState = s.mVoiceRegState;
mDataRegState = s.mDataRegState;
- mVoiceRoamingType = s.mVoiceRoamingType;
- mDataRoamingType = s.mDataRoamingType;
mVoiceOperatorAlphaLong = s.mVoiceOperatorAlphaLong;
mVoiceOperatorAlphaShort = s.mVoiceOperatorAlphaShort;
mVoiceOperatorNumeric = s.mVoiceOperatorNumeric;
@@ -351,7 +357,6 @@
mCdmaEriIconIndex = s.mCdmaEriIconIndex;
mCdmaEriIconMode = s.mCdmaEriIconMode;
mIsEmergencyOnly = s.mIsEmergencyOnly;
- mIsDataRoamingFromRegistration = s.mIsDataRoamingFromRegistration;
mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation;
mChannelNumber = s.mChannelNumber;
mCellBandwidths = s.mCellBandwidths == null ? null :
@@ -367,8 +372,6 @@
public ServiceState(Parcel in) {
mVoiceRegState = in.readInt();
mDataRegState = in.readInt();
- mVoiceRoamingType = in.readInt();
- mDataRoamingType = in.readInt();
mVoiceOperatorAlphaLong = in.readString();
mVoiceOperatorAlphaShort = in.readString();
mVoiceOperatorNumeric = in.readString();
@@ -386,7 +389,6 @@
mCdmaEriIconIndex = in.readInt();
mCdmaEriIconMode = in.readInt();
mIsEmergencyOnly = in.readInt() != 0;
- mIsDataRoamingFromRegistration = in.readInt() != 0;
mIsUsingCarrierAggregation = in.readInt() != 0;
mLteEarfcnRsrpBoost = in.readInt();
mNetworkRegistrationStates = new ArrayList<>();
@@ -398,8 +400,6 @@
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mVoiceRegState);
out.writeInt(mDataRegState);
- out.writeInt(mVoiceRoamingType);
- out.writeInt(mDataRoamingType);
out.writeString(mVoiceOperatorAlphaLong);
out.writeString(mVoiceOperatorAlphaShort);
out.writeString(mVoiceOperatorNumeric);
@@ -417,7 +417,6 @@
out.writeInt(mCdmaEriIconIndex);
out.writeInt(mCdmaEriIconMode);
out.writeInt(mIsEmergencyOnly ? 1 : 0);
- out.writeInt(mIsDataRoamingFromRegistration ? 1 : 0);
out.writeInt(mIsUsingCarrierAggregation ? 1 : 0);
out.writeInt(mLteEarfcnRsrpBoost);
out.writeList(mNetworkRegistrationStates);
@@ -535,17 +534,21 @@
*/
@UnsupportedAppUsage
public boolean getVoiceRoaming() {
- return mVoiceRoamingType != ROAMING_TYPE_NOT_ROAMING;
+ return getVoiceRoamingType() != ROAMING_TYPE_NOT_ROAMING;
}
-
/**
* Get current voice network roaming type
* @return roaming type
* @hide
*/
@UnsupportedAppUsage
- public int getVoiceRoamingType() {
- return mVoiceRoamingType;
+ public @RoamingType int getVoiceRoamingType() {
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return regState.getRoamingType();
+ }
+ return ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -555,19 +558,7 @@
*/
@UnsupportedAppUsage
public boolean getDataRoaming() {
- return mDataRoamingType != ROAMING_TYPE_NOT_ROAMING;
- }
-
- /**
- * Set whether data network registration state is roaming
- *
- * This should only be set to the roaming value received
- * once the data registration phase has completed.
- * @hide
- */
- @UnsupportedAppUsage
- public void setDataRoamingFromRegistration(boolean dataRoaming) {
- mIsDataRoamingFromRegistration = dataRoaming;
+ return getDataRoamingType() != ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -576,7 +567,12 @@
* @hide
*/
public boolean getDataRoamingFromRegistration() {
- return mIsDataRoamingFromRegistration;
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return (regState.getRegState() == NetworkRegistrationState.REG_STATE_ROAMING);
+ }
+ return false;
}
/**
@@ -585,8 +581,13 @@
* @hide
*/
@UnsupportedAppUsage
- public int getDataRoamingType() {
- return mDataRoamingType;
+ public @RoamingType int getDataRoamingType() {
+ final NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState != null) {
+ return regState.getRoamingType();
+ }
+ return ROAMING_TYPE_NOT_ROAMING;
}
/**
@@ -759,8 +760,6 @@
return Objects.hash(
mVoiceRegState,
mDataRegState,
- mVoiceRoamingType,
- mDataRoamingType,
mChannelNumber,
mCellBandwidths,
mVoiceOperatorAlphaLong,
@@ -780,7 +779,6 @@
mCdmaEriIconIndex,
mCdmaEriIconMode,
mIsEmergencyOnly,
- mIsDataRoamingFromRegistration,
mIsUsingCarrierAggregation,
mLteEarfcnRsrpBoost,
mNetworkRegistrationStates);
@@ -794,8 +792,6 @@
return (mVoiceRegState == s.mVoiceRegState
&& mDataRegState == s.mDataRegState
&& mIsManualNetworkSelection == s.mIsManualNetworkSelection
- && mVoiceRoamingType == s.mVoiceRoamingType
- && mDataRoamingType == s.mDataRoamingType
&& mChannelNumber == s.mChannelNumber
&& Arrays.equals(mCellBandwidths, s.mCellBandwidths)
&& equalsHandlesNulls(mVoiceOperatorAlphaLong, s.mVoiceOperatorAlphaLong)
@@ -813,7 +809,6 @@
&& equalsHandlesNulls(mCdmaDefaultRoamingIndicator,
s.mCdmaDefaultRoamingIndicator)
&& mIsEmergencyOnly == s.mIsEmergencyOnly
- && mIsDataRoamingFromRegistration == s.mIsDataRoamingFromRegistration
&& mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation)
&& (mNetworkRegistrationStates == null ? s.mNetworkRegistrationStates == null :
s.mNetworkRegistrationStates != null &&
@@ -933,8 +928,6 @@
.append(", mChannelNumber=").append(mChannelNumber)
.append(", duplexMode()=").append(getDuplexMode())
.append(", mCellBandwidths=").append(Arrays.toString(mCellBandwidths))
- .append(", mVoiceRoamingType=").append(getRoamingLogString(mVoiceRoamingType))
- .append(", mDataRoamingType=").append(getRoamingLogString(mDataRoamingType))
.append(", mVoiceOperatorAlphaLong=").append(mVoiceOperatorAlphaLong)
.append(", mVoiceOperatorAlphaShort=").append(mVoiceOperatorAlphaShort)
.append(", mDataOperatorAlphaLong=").append(mDataOperatorAlphaLong)
@@ -951,7 +944,6 @@
.append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator)
.append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator)
.append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
- .append(", mIsDataRoamingFromRegistration=").append(mIsDataRoamingFromRegistration)
.append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
.append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
.append(", mNetworkRegistrationStates=").append(mNetworkRegistrationStates)
@@ -962,8 +954,6 @@
if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setNullState=" + state);
mVoiceRegState = state;
mDataRegState = state;
- mVoiceRoamingType = ROAMING_TYPE_NOT_ROAMING;
- mDataRoamingType = ROAMING_TYPE_NOT_ROAMING;
mChannelNumber = -1;
mCellBandwidths = new int[0];
mVoiceOperatorAlphaLong = null;
@@ -983,7 +973,6 @@
mCdmaEriIconIndex = -1;
mCdmaEriIconMode = -1;
mIsEmergencyOnly = false;
- mIsDataRoamingFromRegistration = false;
mIsUsingCarrierAggregation = false;
mLteEarfcnRsrpBoost = 0;
mNetworkRegistrationStates = new ArrayList<>();
@@ -1029,32 +1018,50 @@
}
public void setRoaming(boolean roaming) {
- mVoiceRoamingType = (roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
- mDataRoamingType = mVoiceRoamingType;
+ setVoiceRoaming(roaming);
+ setDataRoaming(roaming);
}
/** @hide */
@UnsupportedAppUsage
public void setVoiceRoaming(boolean roaming) {
- mVoiceRoamingType = (roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
+ setVoiceRoamingType(roaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
}
/** @hide */
@UnsupportedAppUsage
- public void setVoiceRoamingType(int type) {
- mVoiceRoamingType = type;
+ public void setVoiceRoamingType(@RoamingType int type) {
+ NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState == null) {
+ regState = new NetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_CS, AccessNetworkConstants.TransportType.WWAN,
+ ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
+ false, null, null);
+ addNetworkRegistrationState(regState);
+ }
+ regState.setRoamingType(type);
}
/** @hide */
@UnsupportedAppUsage
public void setDataRoaming(boolean dataRoaming) {
- mDataRoamingType = (dataRoaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
+ setDataRoamingType(dataRoaming ? ROAMING_TYPE_UNKNOWN : ROAMING_TYPE_NOT_ROAMING);
}
/** @hide */
@UnsupportedAppUsage
- public void setDataRoamingType(int type) {
- mDataRoamingType = type;
+ public void setDataRoamingType(@RoamingType int type) {
+ NetworkRegistrationState regState = getNetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
+ if (regState == null) {
+ regState = new NetworkRegistrationState(
+ NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
+ ServiceState.ROAMING_TYPE_NOT_ROAMING, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0,
+ false, null, null);
+ addNetworkRegistrationState(regState);
+ }
+ regState.setRoamingType(type);
}
/**
@@ -1166,30 +1173,10 @@
*/
@UnsupportedAppUsage
private void setFromNotifierBundle(Bundle m) {
- mVoiceRegState = m.getInt("voiceRegState");
- mDataRegState = m.getInt("dataRegState");
- mVoiceRoamingType = m.getInt("voiceRoamingType");
- mDataRoamingType = m.getInt("dataRoamingType");
- mVoiceOperatorAlphaLong = m.getString("operator-alpha-long");
- mVoiceOperatorAlphaShort = m.getString("operator-alpha-short");
- mVoiceOperatorNumeric = m.getString("operator-numeric");
- mDataOperatorAlphaLong = m.getString("data-operator-alpha-long");
- mDataOperatorAlphaShort = m.getString("data-operator-alpha-short");
- mDataOperatorNumeric = m.getString("data-operator-numeric");
- mIsManualNetworkSelection = m.getBoolean("manual");
- mRilVoiceRadioTechnology = m.getInt("radioTechnology");
- mRilDataRadioTechnology = m.getInt("dataRadioTechnology");
- mCssIndicator = m.getBoolean("cssIndicator");
- mNetworkId = m.getInt("networkId");
- mSystemId = m.getInt("systemId");
- mCdmaRoamingIndicator = m.getInt("cdmaRoamingIndicator");
- mCdmaDefaultRoamingIndicator = m.getInt("cdmaDefaultRoamingIndicator");
- mIsEmergencyOnly = m.getBoolean("emergencyOnly");
- mIsDataRoamingFromRegistration = m.getBoolean("isDataRoamingFromRegistration");
- mIsUsingCarrierAggregation = m.getBoolean("isUsingCarrierAggregation");
- mLteEarfcnRsrpBoost = m.getInt("LteEarfcnRsrpBoost");
- mChannelNumber = m.getInt("ChannelNumber");
- mCellBandwidths = m.getIntArray("CellBandwidths");
+ ServiceState ssFromBundle = m.getParcelable(Intent.EXTRA_SERVICE_STATE);
+ if (ssFromBundle != null) {
+ copyFrom(ssFromBundle);
+ }
}
/**
@@ -1200,10 +1187,13 @@
*/
@UnsupportedAppUsage
public void fillInNotifierBundle(Bundle m) {
+ m.putParcelable(Intent.EXTRA_SERVICE_STATE, this);
+ // serviceState already consists of below entries.
+ // for backward compatibility, we continue fill in below entries.
m.putInt("voiceRegState", mVoiceRegState);
m.putInt("dataRegState", mDataRegState);
- m.putInt("voiceRoamingType", mVoiceRoamingType);
- m.putInt("dataRoamingType", mDataRoamingType);
+ m.putInt("dataRoamingType", getDataRoamingType());
+ m.putInt("voiceRoamingType", getVoiceRoamingType());
m.putString("operator-alpha-long", mVoiceOperatorAlphaLong);
m.putString("operator-alpha-short", mVoiceOperatorAlphaShort);
m.putString("operator-numeric", mVoiceOperatorNumeric);
@@ -1219,7 +1209,7 @@
m.putInt("cdmaRoamingIndicator", mCdmaRoamingIndicator);
m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator);
m.putBoolean("emergencyOnly", mIsEmergencyOnly);
- m.putBoolean("isDataRoamingFromRegistration", mIsDataRoamingFromRegistration);
+ m.putBoolean("isDataRoamingFromRegistration", getDataRoamingFromRegistration());
m.putBoolean("isUsingCarrierAggregation", mIsUsingCarrierAggregation);
m.putInt("LteEarfcnRsrpBoost", mLteEarfcnRsrpBoost);
m.putInt("ChannelNumber", mChannelNumber);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index a264707..f850693 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -32,12 +32,14 @@
import android.annotation.UnsupportedAppUsage;
import android.app.BroadcastOptions;
import android.app.PendingIntent;
+import android.app.job.JobService;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.database.ContentObserver;
import android.net.INetworkPolicyManager;
import android.net.NetworkCapabilities;
import android.net.Uri;
@@ -116,6 +118,52 @@
@UnsupportedAppUsage
public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
+
+ /**
+ * Generates a content {@link Uri} used to receive updates on simInfo change
+ * on the given subscriptionId
+ * @param subscriptionId the subscriptionId to receive updates on
+ * @return the Uri used to observe carrier identity changes
+ * @hide
+ */
+ public static Uri getUriForSubscriptionId(int subscriptionId) {
+ return Uri.withAppendedPath(CONTENT_URI, String.valueOf(subscriptionId));
+ }
+
+ /**
+ * A content {@link Uri} used to receive updates on wfc enabled user setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription wfc enabled {@link SubscriptionManager#WFC_IMS_ENABLED}
+ * while your app is running. You can also use a {@link JobService} to ensure your app
+ * is notified of changes to the {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri WFC_ENABLED_CONTENT_URI = Uri.withAppendedPath(CONTENT_URI, "wfc");
+
+ /**
+ * A content {@link Uri} used to receive updates on enhanced 4g user setting.
+ * <p>
+ * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+ * subscription enhanced 4G enabled {@link SubscriptionManager#ENHANCED_4G_MODE_ENABLED}
+ * while your app is running. You can also use a {@link JobService} to ensure your app
+ * is notified of changes to the {@link Uri} even when it is not running.
+ * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+ * updates to the {@link Uri}.
+ * To be notified of changes to a specific subId, append subId to the URI
+ * {@link Uri#withAppendedPath(Uri, String)}.
+ * @hide
+ */
+ @SystemApi
+ public static final Uri ENHANCED_4G_ENABLED_CONTENT_URI = Uri.withAppendedPath(
+ CONTENT_URI, "enhanced_4g");
+
+
/**
* TelephonyProvider unique key column name is the subscription id.
* <P>Type: TEXT (String)</P>
@@ -1603,7 +1651,7 @@
* Check if the subscription ID is usable.
*
* A usable subscription ID has a valid value except some special values such as
- * {@link DEFAULT_SUBSCRIPTION_ID}. It can be used for subscription functions.
+ * {@link #DEFAULT_SUBSCRIPTION_ID}. It can be used for subscription functions.
*
* @param subscriptionId the subscription ID
* @return {@code true} if the subscription ID is usable; {@code false} otherwise.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c5e4707..fca14c8 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -60,6 +60,7 @@
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.text.TextUtils;
import android.util.Log;
import com.android.ims.internal.IImsServiceFeatureCallback;
@@ -2446,39 +2447,46 @@
*
* These are the ordinal value of IccCardConstants.State.
*/
- public static final int SIM_STATE_UNKNOWN = 0;
+
+ public static final int SIM_STATE_UNKNOWN = TelephonyProtoEnums.SIM_STATE_UNKNOWN; // 0
/** SIM card state: no SIM card is available in the device */
- public static final int SIM_STATE_ABSENT = 1;
+ public static final int SIM_STATE_ABSENT = TelephonyProtoEnums.SIM_STATE_ABSENT; // 1
/** SIM card state: Locked: requires the user's SIM PIN to unlock */
- public static final int SIM_STATE_PIN_REQUIRED = 2;
+ public static final int SIM_STATE_PIN_REQUIRED =
+ TelephonyProtoEnums.SIM_STATE_PIN_REQUIRED; // 2
/** SIM card state: Locked: requires the user's SIM PUK to unlock */
- public static final int SIM_STATE_PUK_REQUIRED = 3;
+ public static final int SIM_STATE_PUK_REQUIRED =
+ TelephonyProtoEnums.SIM_STATE_PUK_REQUIRED; // 3
/** SIM card state: Locked: requires a network PIN to unlock */
- public static final int SIM_STATE_NETWORK_LOCKED = 4;
+ public static final int SIM_STATE_NETWORK_LOCKED =
+ TelephonyProtoEnums.SIM_STATE_NETWORK_LOCKED; // 4
/** SIM card state: Ready */
- public static final int SIM_STATE_READY = 5;
+ public static final int SIM_STATE_READY = TelephonyProtoEnums.SIM_STATE_READY; // 5
/** SIM card state: SIM Card is NOT READY */
- public static final int SIM_STATE_NOT_READY = 6;
+ public static final int SIM_STATE_NOT_READY = TelephonyProtoEnums.SIM_STATE_NOT_READY; // 6
/** SIM card state: SIM Card Error, permanently disabled */
- public static final int SIM_STATE_PERM_DISABLED = 7;
+ public static final int SIM_STATE_PERM_DISABLED =
+ TelephonyProtoEnums.SIM_STATE_PERM_DISABLED; // 7
/** SIM card state: SIM Card Error, present but faulty */
- public static final int SIM_STATE_CARD_IO_ERROR = 8;
+ public static final int SIM_STATE_CARD_IO_ERROR =
+ TelephonyProtoEnums.SIM_STATE_CARD_IO_ERROR; // 8
/** SIM card state: SIM Card restricted, present but not usable due to
* carrier restrictions.
*/
- public static final int SIM_STATE_CARD_RESTRICTED = 9;
+ public static final int SIM_STATE_CARD_RESTRICTED =
+ TelephonyProtoEnums.SIM_STATE_CARD_RESTRICTED; // 9
/**
* SIM card state: Loaded: SIM card applications have been loaded
* @hide
*/
@SystemApi
- public static final int SIM_STATE_LOADED = 10;
+ public static final int SIM_STATE_LOADED = TelephonyProtoEnums.SIM_STATE_LOADED; // 10
/**
* SIM card state: SIM Card is present
* @hide
*/
@SystemApi
- public static final int SIM_STATE_PRESENT = 11;
+ public static final int SIM_STATE_PRESENT = TelephonyProtoEnums.SIM_STATE_PRESENT; // 11
/**
* Extra included in {@link #ACTION_SIM_CARD_STATE_CHANGED} and
@@ -5395,7 +5403,7 @@
@UnsupportedAppUsage
public static String getTelephonyProperty(String property, String defaultVal) {
String propVal = SystemProperties.get(property);
- return propVal == null ? defaultVal : propVal;
+ return TextUtils.isEmpty(propVal) ? defaultVal : propVal;
}
/** @hide */
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 8379f8c..eb144f9 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -80,7 +80,7 @@
*/
public static final int TYPE_ALL = ApnTypes.ALL;
/** APN type for default data traffic. */
- public static final int TYPE_DEFAULT = ApnTypes.DEFAULT;
+ public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI;
/** APN type for MMS traffic. */
public static final int TYPE_MMS = ApnTypes.MMS;
/** APN type for SUPL assisted GPS. */
@@ -979,7 +979,7 @@
return false;
}
// DEFAULT can handle HIPRI.
- if (hasApnType(type) || (type == TYPE_HIPRI && hasApnType(TYPE_DEFAULT))) {
+ if (hasApnType(type)) {
return true;
}
return false;
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 3a26350..cb8269e 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -420,6 +420,7 @@
int RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING = 201;
int RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA = 202;
int RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA = 203;
+ int RIL_REQUEST_SET_PREFERRED_DATA_MODEM = 204;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/tests/ActivityTests/Android.mk b/tests/ActivityTests/Android.mk
index 4c68c8b..94294f6 100644
--- a/tests/ActivityTests/Android.mk
+++ b/tests/ActivityTests/Android.mk
@@ -10,9 +10,5 @@
LOCAL_CERTIFICATE := platform
LOCAL_USE_AAPT2 := true
-# Disable AAPT2 manifest checks to fix:
-# frameworks/base/tests/ActivityTests/AndroidManifest.xml:42: error: unexpected element <preferred> found in <manifest><application><activity>.
-# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
-LOCAL_AAPT_FLAGS += --warn-manifest-validation
include $(BUILD_PACKAGE)
diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk
index c225e17..a6c21db 100644
--- a/tests/NetworkSecurityConfigTest/Android.mk
+++ b/tests/NetworkSecurityConfigTest/Android.mk
@@ -7,7 +7,6 @@
LOCAL_JAVA_LIBRARIES := \
android.test.runner \
- conscrypt \
android.test.base \
LOCAL_STATIC_JAVA_LIBRARIES := junit
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 750e2fb..132135d 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -63,7 +63,8 @@
libunwindstack \
libutilscallstack \
libziparchive \
- libz
+ libz \
+ netd_aidl_interface-cpp
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
@@ -92,7 +93,8 @@
liblog \
libcutils \
libnativehelper \
- libnetdaidl
+ libnetdaidl \
+ netd_aidl_interface-cpp
LOCAL_STATIC_LIBRARIES := \
libpcap \
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 954f1ed..3ea1755 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -46,7 +46,7 @@
IApkSerializer(IAaptContext* context, const Source& source) : context_(context), source_(source) {}
virtual bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
- IArchiveWriter* writer) = 0;
+ IArchiveWriter* writer, uint32_t compression_flags) = 0;
virtual bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) = 0;
virtual bool SerializeFile(FileReference* file, IArchiveWriter* writer) = 0;
@@ -59,7 +59,10 @@
bool ConvertApk(IAaptContext* context, unique_ptr<LoadedApk> apk, IApkSerializer* serializer,
IArchiveWriter* writer) {
- if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/, writer)) {
+ io::IFile* manifest = apk->GetFileCollection()->FindFile(kAndroidManifestPath);
+ if (!serializer->SerializeXml(apk->GetManifest(), kAndroidManifestPath, true /*utf16*/, writer,
+ (manifest != nullptr && manifest->WasCompressed())
+ ? ArchiveEntry::kCompress : 0u)) {
context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
<< "failed to serialize AndroidManifest.xml");
return false;
@@ -133,7 +136,7 @@
: IApkSerializer(context, source), tableFlattenerOptions_(options) {}
bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
- IArchiveWriter* writer) override {
+ IArchiveWriter* writer, uint32_t compression_flags) override {
BigBuffer buffer(4096);
XmlFlattenerOptions options = {};
options.use_utf16 = utf16;
@@ -144,8 +147,7 @@
}
io::BigBufferInputStream input_stream(&buffer);
- return io::CopyInputStreamToArchive(context_, &input_stream, path, ArchiveEntry::kCompress,
- writer);
+ return io::CopyInputStreamToArchive(context_, &input_stream, path, compression_flags, writer);
}
bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
@@ -186,7 +188,8 @@
return false;
}
- if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer)) {
+ if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
+ file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
context_->GetDiagnostics()->Error(DiagMessage(source_)
<< "failed to serialize to binary XML: " << *file->path);
return false;
@@ -216,10 +219,10 @@
: IApkSerializer(context, source) {}
bool SerializeXml(const xml::XmlResource* xml, const std::string& path, bool utf16,
- IArchiveWriter* writer) override {
+ IArchiveWriter* writer, uint32_t compression_flags) override {
pb::XmlNode pb_node;
SerializeXmlResourceToPb(*xml, &pb_node);
- return io::CopyProtoToArchive(context_, &pb_node, path, ArchiveEntry::kCompress, writer);
+ return io::CopyProtoToArchive(context_, &pb_node, path, compression_flags, writer);
}
bool SerializeTable(ResourceTable* table, IArchiveWriter* writer) override {
@@ -246,7 +249,8 @@
return false;
}
- if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer)) {
+ if (!SerializeXml(xml.get(), *file->path, false /*utf16*/, writer,
+ file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u)) {
context_->GetDiagnostics()->Error(DiagMessage(source_)
<< "failed to serialize to proto XML: " << *file->path);
return false;
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
index 5c9df6a..c7993e3 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/pps/HomeSpTest.java
@@ -189,8 +189,7 @@
Map<String, Long> homeNetworkIds = new HashMap<>();
byte[] rawSsidBytes = new byte[33];
Arrays.fill(rawSsidBytes, (byte) 'a');
- homeNetworkIds.put(
- StringFactory.newStringFromBytes(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
+ homeNetworkIds.put(new String(rawSsidBytes, StandardCharsets.UTF_8), 0x1234L);
homeSp.setHomeNetworkIds(homeNetworkIds);
assertFalse(homeSp.validate());
}