Merge "Check album art for video thumbnails."
diff --git a/api/current.txt b/api/current.txt
index 5a26671..4c67bae 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -23,6 +23,7 @@
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
field public static final java.lang.String BIND_AUTOFILL_SERVICE = "android.permission.BIND_AUTOFILL_SERVICE";
+ field public static final java.lang.String BIND_CALL_REDIRECTION_SERVICE = "android.permission.BIND_CALL_REDIRECTION_SERVICE";
field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -280,7 +281,7 @@
field public static final int allowBackup = 16843392; // 0x1010280
field public static final int allowClearUserData = 16842757; // 0x1010005
field public static final int allowEmbedded = 16843765; // 0x10103f5
- field public static final int allowForceDark = 16844171; // 0x101058b
+ field public static final int allowForceDark = 16844172; // 0x101058c
field public static final int allowParallelSyncs = 16843570; // 0x1010332
field public static final int allowSingleTap = 16843353; // 0x1010259
field public static final int allowTaskReparenting = 16843268; // 0x1010204
@@ -774,11 +775,11 @@
field public static final int isFeatureSplit = 16844123; // 0x101055b
field public static final int isGame = 16843764; // 0x10103f4
field public static final int isIndicator = 16843079; // 0x1010147
- field public static final int isLightTheme = 16844175; // 0x101058f
+ field public static final int isLightTheme = 16844176; // 0x1010590
field public static final int isModifier = 16843334; // 0x1010246
field public static final int isRepeatable = 16843336; // 0x1010248
field public static final int isScrollContainer = 16843342; // 0x101024e
- field public static final int isSplitRequired = 16844176; // 0x1010590
+ field public static final int isSplitRequired = 16844177; // 0x1010591
field public static final int isStatic = 16844122; // 0x101055a
field public static final int isSticky = 16843335; // 0x1010247
field public static final int isolatedProcess = 16843689; // 0x10103a9
@@ -938,7 +939,7 @@
field public static final int minSdkVersion = 16843276; // 0x101020c
field public static final int minWidth = 16843071; // 0x101013f
field public static final int minimumHorizontalAngle = 16843901; // 0x101047d
- field public static final int minimumUiTimeout = 16844174; // 0x101058e
+ field public static final int minimumUiTimeout = 16844175; // 0x101058f
field public static final int minimumVerticalAngle = 16843902; // 0x101047e
field public static final int mipMap = 16843725; // 0x10103cd
field public static final int mirrorForRtl = 16843726; // 0x10103ce
@@ -978,10 +979,10 @@
field public static final int onClick = 16843375; // 0x101026f
field public static final int oneshot = 16843159; // 0x1010197
field public static final int opacity = 16843550; // 0x101031e
- field public static final int opticalInsetBottom = 16844170; // 0x101058a
- field public static final int opticalInsetLeft = 16844167; // 0x1010587
- field public static final int opticalInsetRight = 16844169; // 0x1010589
- field public static final int opticalInsetTop = 16844168; // 0x1010588
+ field public static final int opticalInsetBottom = 16844171; // 0x101058b
+ field public static final int opticalInsetLeft = 16844168; // 0x1010588
+ field public static final int opticalInsetRight = 16844170; // 0x101058a
+ field public static final int opticalInsetTop = 16844169; // 0x1010589
field public static final int order = 16843242; // 0x10101ea
field public static final int orderInCategory = 16843231; // 0x10101df
field public static final int ordering = 16843490; // 0x10102e2
@@ -997,6 +998,7 @@
field public static final int overlapAnchor = 16843874; // 0x1010462
field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
field public static final int packageNames = 16843649; // 0x1010381
+ field public static final int packageType = 16844167; // 0x1010587
field public static final int padding = 16842965; // 0x10100d5
field public static final int paddingBottom = 16842969; // 0x10100d9
field public static final int paddingEnd = 16843700; // 0x10103b4
@@ -1306,7 +1308,7 @@
field public static final int summaryColumn = 16843426; // 0x10102a2
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
- field public static final int supportsAmbientMode = 16844172; // 0x101058c
+ field public static final int supportsAmbientMode = 16844173; // 0x101058d
field public static final int supportsAssist = 16844016; // 0x10104f0
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
field public static final int supportsLocalInteraction = 16844047; // 0x101050f
@@ -13757,6 +13759,7 @@
method public static android.graphics.ImageDecoder.Source createSource(android.content.res.AssetManager, java.lang.String);
method public static android.graphics.ImageDecoder.Source createSource(java.nio.ByteBuffer);
method public static android.graphics.ImageDecoder.Source createSource(java.io.File);
+ method public static android.graphics.ImageDecoder.Source createSource(java.util.concurrent.Callable<android.content.res.AssetFileDescriptor>);
method public static android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
method public static android.graphics.Bitmap decodeBitmap(android.graphics.ImageDecoder.Source) throws java.io.IOException;
method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
@@ -15975,6 +15978,7 @@
method public int canAuthenticate();
field public static final int ERROR_NONE = 0; // 0x0
field public static final int ERROR_NO_BIOMETRICS = 11; // 0xb
+ field public static final int ERROR_NO_HARDWARE = 12; // 0xc
field public static final int ERROR_UNAVAILABLE = 1; // 0x1
}
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index d490701..ced65f2 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -327,7 +327,7 @@
EXPECT_EQ(33, item5.mValue.int_value);
const FieldValue& item6 = event1.getValues()[6];
- EXPECT_EQ(0x2020382, item6.mField.getField());
+ EXPECT_EQ(0x2020383, item6.mField.getField());
EXPECT_EQ(Type::LONG, item6.mValue.getType());
EXPECT_EQ(678L, item6.mValue.long_value);
@@ -337,7 +337,7 @@
EXPECT_EQ(44, item7.mValue.int_value);
const FieldValue& item8 = event1.getValues()[8];
- EXPECT_EQ(0x2020482, item8.mField.getField());
+ EXPECT_EQ(0x2020483, item8.mField.getField());
EXPECT_EQ(Type::LONG, item8.mValue.getType());
EXPECT_EQ(890L, item8.mValue.long_value);
@@ -347,7 +347,7 @@
EXPECT_EQ(1, item9.mValue.int_value);
const FieldValue& item10 = event1.getValues()[10];
- EXPECT_EQ(0x2020583, item10.mField.getField());
+ EXPECT_EQ(0x2020584, item10.mField.getField());
EXPECT_EQ(Type::STRING, item10.mValue.getType());
EXPECT_EQ("test2", item10.mValue.str_value);
@@ -357,7 +357,7 @@
EXPECT_EQ(2, item11.mValue.int_value);
const FieldValue& item12 = event1.getValues()[12];
- EXPECT_EQ(0x2020683, item12.mField.getField());
+ EXPECT_EQ(0x2020684, item12.mField.getField());
EXPECT_EQ(Type::STRING, item12.mValue.getType());
EXPECT_EQ("test1", item12.mValue.str_value);
@@ -367,7 +367,7 @@
EXPECT_EQ(111, item13.mValue.int_value);
const FieldValue& item14 = event1.getValues()[14];
- EXPECT_EQ(0x2020784, item14.mField.getField());
+ EXPECT_EQ(0x2020785, item14.mField.getField());
EXPECT_EQ(Type::FLOAT, item14.mValue.getType());
EXPECT_EQ(2.2f, item14.mValue.float_value);
@@ -377,7 +377,7 @@
EXPECT_EQ(222, item15.mValue.int_value);
const FieldValue& item16 = event1.getValues()[16];
- EXPECT_EQ(0x2028884, item16.mField.getField());
+ EXPECT_EQ(0x2028885, item16.mField.getField());
EXPECT_EQ(Type::FLOAT, item16.mValue.getType());
EXPECT_EQ(1.1f, item16.mValue.float_value);
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 34c2282..1144e26 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1760,7 +1760,7 @@
/**
* Like {@link #execStartActivity(android.content.Context, android.os.IBinder,
* android.os.IBinder, String, android.content.Intent, int, android.os.Bundle)},
- * but for calls from a {#link Fragment}.
+ * but for calls from a {@link Fragment}.
*
* @param who The Context from which the activity is being started.
* @param contextThread The main thread of the Context from which the activity
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 654bfaf..8e6a385 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -2973,7 +2973,7 @@
* socket will be encrypted.
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
* {@link BluetoothServerSocket}.
- * <p>The system will assign a dynamic PSM value. This PSM value can be read from the {#link
+ * <p>The system will assign a dynamic PSM value. This PSM value can be read from the {@link
* BluetoothServerSocket#getPsm()} and this value will be released when this server socket is
* closed, Bluetooth is turned off, or the application exits unexpectedly.
* <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
@@ -3031,7 +3031,7 @@
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
* {@link BluetoothServerSocket}.
* <p>The system will assign a dynamic protocol/service multiplexer (PSM) value. This PSM value
- * can be read from the {#link BluetoothServerSocket#getPsm()} and this value will be released
+ * can be read from the {@link BluetoothServerSocket#getPsm()} and this value will be released
* when this server socket is closed, Bluetooth is turned off, or the application exits
* unexpectedly.
* <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 73e98cd..30d5fbc 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1596,7 +1596,7 @@
* For example, for Bluetooth 2.1 devices, if any of the devices does not
* have an input and output capability or just has the ability to
* display a numeric key, a secure socket connection is not possible.
- * In such a case, use {#link createInsecureRfcommSocket}.
+ * In such a case, use {@link createInsecureRfcommSocket}.
* For more details, refer to the Security Model section 5.2 (vol 3) of
* Bluetooth Core Specification version 2.1 + EDR.
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
@@ -1631,7 +1631,7 @@
* For example, for Bluetooth 2.1 devices, if any of the devices does not
* have an input and output capability or just has the ability to
* display a numeric key, a secure socket connection is not possible.
- * In such a case, use {#link createInsecureRfcommSocket}.
+ * In such a case, use {@link createInsecureRfcommSocket}.
* For more details, refer to the Security Model section 5.2 (vol 3) of
* Bluetooth Core Specification version 2.1 + EDR.
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
@@ -1688,7 +1688,7 @@
* For example, for Bluetooth 2.1 devices, if any of the devices does not
* have an input and output capability or just has the ability to
* display a numeric key, a secure socket connection is not possible.
- * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}.
+ * In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}.
* For more details, refer to the Security Model section 5.2 (vol 3) of
* Bluetooth Core Specification version 2.1 + EDR.
* <p>Hint: If you are connecting to a Bluetooth serial board then try
@@ -1972,7 +1972,7 @@
* 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,
+ * secure socket connection is not possible, use {@link createInsecureLeL2capCocSocket(int,
* int)}.
*
* @param psm dynamic PSM value from remote device
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
index 5fc344a..758c68d 100644
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ b/core/java/android/bluetooth/BluetoothServerSocket.java
@@ -203,7 +203,7 @@
/**
* 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
+ * {@link BluetoothAdapter.listenUsingL2capChannel()} or {@link
* BluetoothAdapter.listenUsingInsecureL2capChannel()}. The returned value is undefined if this
* method is called on non-L2CAP server sockets.
*
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index b8739b9..0faecb0 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -19,6 +19,7 @@
import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
+import android.annotation.IntDef;
import android.annotation.RequiresPermission;
import android.content.Context;
import android.os.RemoteException;
@@ -46,6 +47,14 @@
*/
public static final int ERROR_NO_BIOMETRICS = BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS;
+ /**
+ * There is no biometric hardware.
+ */
+ public static final int ERROR_NO_HARDWARE = BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT;
+
+ @IntDef({ERROR_NONE, ERROR_UNAVAILABLE, ERROR_NO_BIOMETRICS, ERROR_NO_HARDWARE})
+ @interface BiometricError {}
+
private final Context mContext;
private final IBiometricService mService;
@@ -68,7 +77,7 @@
* {@link #ERROR_NONE} if a biometric can currently be used (enrolled and available).
*/
@RequiresPermission(USE_BIOMETRIC)
- public int canAuthenticate() {
+ public @BiometricError int canAuthenticate() {
if (mService != null) {
try {
return mService.canAuthenticate(mContext.getOpPackageName());
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index f7f627e..097a3e3 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -2095,7 +2095,7 @@
* Called when the application has reported a new location of its text
* cursor. This is only called if explicitly requested by the input method.
* The default implementation does nothing.
- * @deprecated Use {#link onUpdateCursorAnchorInfo(CursorAnchorInfo)} instead.
+ * @deprecated Use {@link #onUpdateCursorAnchorInfo(CursorAnchorInfo)} instead.
*/
@Deprecated
public void onUpdateCursor(Rect newCursor) {
@@ -2162,7 +2162,7 @@
}
/**
- * @return {#link ExtractEditText} if it is considered to be visible and active. Otherwise
+ * @return {@link ExtractEditText} if it is considered to be visible and active. Otherwise
* {@code null} is returned.
*/
private ExtractEditText getExtractEditTextIfVisible() {
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index b4b8887..0513fee 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -162,9 +162,9 @@
/**
* Set which boundary of the screen the DockWindow sticks to.
*
- * @param gravity The boundary of the screen to stick. See {#link
- * android.view.Gravity.LEFT}, {#link android.view.Gravity.TOP},
- * {#link android.view.Gravity.BOTTOM}, {#link
+ * @param gravity The boundary of the screen to stick. See {@link
+ * android.view.Gravity.LEFT}, {@link android.view.Gravity.TOP},
+ * {@link android.view.Gravity.BOTTOM}, {@link
* android.view.Gravity.RIGHT}.
*/
public void setGravity(int gravity) {
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 69f50a2..a2da6ea 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -46,7 +46,7 @@
/**
* Set if the user desires to use this network even if it is unvalidated. This field has meaning
- * only if {#link explicitlySelected} is true. If it is, this field must also be set to the
+ * only if {@link explicitlySelected} is true. If it is, this field must also be set to the
* appropriate value based on previous user choice.
*/
public boolean acceptUnvalidated;
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index c38fcf3..0a3403b 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -896,8 +896,8 @@
* @deprecated No longer used by the input system.
* {@link #getAction} value: multiple duplicate key events have
* occurred in a row, or a complex string is being delivered. If the
- * key code is not {#link {@link #KEYCODE_UNKNOWN} then the
- * {#link {@link #getRepeatCount()} method returns the number of times
+ * key code is not {@link #KEYCODE_UNKNOWN} then the
+ * {@link #getRepeatCount()} method returns the number of times
* the given key code should be executed.
* Otherwise, if the key code is {@link #KEYCODE_UNKNOWN}, then
* this is a sequence of characters as returned by {@link #getCharacters}.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e452f5d..f3f012d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1932,6 +1932,13 @@
<permission android:name="android.permission.BIND_SCREENING_SERVICE"
android:protectionLevel="signature|privileged" />
+ <!-- Must be required by a {@link android.telecom.CallRedirectionService},
+ to ensure that only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission android:name="android.permission.BIND_CALL_REDIRECTION_SERVICE"
+ android:protectionLevel="signature|privileged" />
+
<!-- Must be required by a {@link android.telecom.ConnectionService},
to ensure that only the system can bind to it.
@deprecated {@link android.telecom.ConnectionService}s should require
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 8ff29ba..99af0de 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1442,8 +1442,11 @@
{@link #AndroidManifestService service},
{@link #AndroidManifestReceiver receiver},
{@link #AndroidManifestActivity activity},
- {@link #AndroidManifestActivityAlias activity-alias}, and
- {@link #AndroidManifestUsesLibrary uses-library}. The application tag
+ {@link #AndroidManifestActivityAlias activity-alias},
+ {@link #AndroidManifestUsesLibrary uses-library},
+ {@link #AndroidManifestUsesStaticLibrary uses-static-library}, and
+ {@link #AndroidManifestUsesPackage uses-package}.
+ The application tag
appears as a child of the root {@link #AndroidManifest manifest} tag in
an application's manifest file. -->
<declare-styleable name="AndroidManifestApplication" parent="AndroidManifest">
@@ -1877,12 +1880,35 @@
library is singed with more than one certificate.
<p>This appears as a child tag of the
- {@link #AndroidManifestUsesStaticLibrary uses-static-library} tag. -->
+ {@link #AndroidManifestUsesStaticLibrary uses-static-library} or
+ {@link #AndroidManifestUsesPackage uses-package} tag. -->
<declare-styleable name="AndroidManifestAdditionalCertificate" parent="AndroidManifestUsesStaticLibrary">
<!-- The SHA-256 digest of the library signing certificate. -->
<attr name="certDigest" />
</declare-styleable>
+ <!-- The <code>uses-package</code> specifies some kind of dependency on another
+ package. It does not have any impact on the app's execution on the device,
+ but provides information about dependencies it has on other packages that need
+ to be satisfied for it to run correctly. That is, this is primarily for
+ installers to know what other apps need to be installed along with this one.
+
+ <p>This appears as a child tag of the
+ {@link #AndroidManifestApplication application} tag. -->
+ <declare-styleable name="AndroidManifestUsesPackage" parent="AndroidManifestApplication">
+ <!-- Required type of association with the package, for example "android.package.ad_service"
+ if it provides an advertising service. -->
+ <attr name="packageType" format="string" />
+ <!-- Required name of the package you use. -->
+ <attr name="name" />
+ <!-- Optional minimum version of the package that satisfies the dependency. -->
+ <attr name="version" />
+ <!-- Optional minimum major version of the package that satisfies the dependency. -->
+ <attr name="versionMajor" format="integer" />
+ <!-- Optional SHA-256 digest of the package signing certificate. -->
+ <attr name="certDigest" format="string" />
+ </declare-styleable>
+
<!-- The <code>supports-screens</code> specifies the screen dimensions an
application supports. By default a modern application supports all
screen sizes and must explicitly disable certain screen sizes here;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f55f391..8b73b67 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3550,4 +3550,7 @@
<!-- Pre-scale volume at volume step 3 for Absolute Volume -->
<fraction name="config_prescaleAbsoluteVolume_index3">85%</fraction>
+
+ <!-- Whether or not the "SMS app service" feature is enabled -->
+ <bool name="config_useSmsAppService">true</bool>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index fadefff..2e42e4a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2903,6 +2903,7 @@
<eat-comment />
<public-group type="attr" first-id="0x01010587">
+ <public name="packageType" />
<public name="opticalInsetLeft" />
<public name="opticalInsetTop" />
<public name="opticalInsetRight" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 72ae0d6..a7b6dde 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3475,4 +3475,6 @@
<java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index1" />
<java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index2" />
<java-symbol type="fraction" name="config_prescaleAbsoluteVolume_index3" />
+
+ <java-symbol type="bool" name="config_useSmsAppService" />
</resources>
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 6ce66bd..009e042 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -59,6 +59,7 @@
import java.io.InputStream;
import java.lang.annotation.Retention;
import java.nio.ByteBuffer;
+import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -283,26 +284,7 @@
return createFromStream(is, true, this);
}
-
- final FileDescriptor fd = assetFd.getFileDescriptor();
- final long offset = assetFd.getStartOffset();
-
- ImageDecoder decoder = null;
- try {
- try {
- Os.lseek(fd, offset, SEEK_SET);
- decoder = nCreate(fd, this);
- } catch (ErrnoException e) {
- decoder = createFromStream(new FileInputStream(fd), true, this);
- }
- } finally {
- if (decoder == null) {
- IoUtils.closeQuietly(assetFd);
- } else {
- decoder.mAssetFd = assetFd;
- }
- }
- return decoder;
+ return createFromAssetFileDescriptor(assetFd, this);
}
}
@@ -354,6 +336,30 @@
return decoder;
}
+ @NonNull
+ private static ImageDecoder createFromAssetFileDescriptor(@NonNull AssetFileDescriptor assetFd,
+ Source source) throws IOException {
+ final FileDescriptor fd = assetFd.getFileDescriptor();
+ final long offset = assetFd.getStartOffset();
+
+ ImageDecoder decoder = null;
+ try {
+ try {
+ Os.lseek(fd, offset, SEEK_SET);
+ decoder = nCreate(fd, source);
+ } catch (ErrnoException e) {
+ decoder = createFromStream(new FileInputStream(fd), true, source);
+ }
+ } finally {
+ if (decoder == null) {
+ IoUtils.closeQuietly(assetFd);
+ } else {
+ decoder.mAssetFd = assetFd;
+ }
+ }
+ return decoder;
+ }
+
/**
* For backwards compatibility, this does *not* close the InputStream.
*
@@ -528,6 +534,29 @@
}
}
+ private static class CallableSource extends Source {
+ CallableSource(@NonNull Callable<AssetFileDescriptor> callable) {
+ mCallable = callable;
+ }
+
+ private final Callable<AssetFileDescriptor> mCallable;
+
+ @Override
+ public ImageDecoder createImageDecoder() throws IOException {
+ AssetFileDescriptor assetFd = null;
+ try {
+ assetFd = mCallable.call();
+ } catch (Exception e) {
+ if (e instanceof IOException) {
+ throw (IOException) e;
+ } else {
+ throw new IOException(e);
+ }
+ }
+ return createFromAssetFileDescriptor(assetFd, this);
+ }
+ }
+
/**
* Information about an encoded image.
*/
@@ -971,6 +1000,27 @@
}
/**
+ * Create a new {@link Source Source} from a {@link Callable} that returns a
+ * new {@link AssetFileDescriptor} for each request. This provides control
+ * over how the {@link AssetFileDescriptor} is created, such as passing
+ * options into {@link ContentResolver#openTypedAssetFileDescriptor}, or
+ * enabling use of a {@link android.os.CancellationSignal}.
+ * <p>
+ * It's important for the given {@link Callable} to return a new, unique
+ * {@link AssetFileDescriptor} for each invocation, to support reuse of the
+ * returned {@link Source Source}.
+ *
+ * @return a new Source object, which can be passed to
+ * {@link #decodeDrawable decodeDrawable} or {@link #decodeBitmap
+ * decodeBitmap}.
+ */
+ @AnyThread
+ @NonNull
+ public static Source createSource(@NonNull Callable<AssetFileDescriptor> callable) {
+ return new CallableSource(callable);
+ }
+
+ /**
* Return the width and height of a given sample size.
*
* <p>This takes an input that functions like
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 85eac4b..c074cce 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4607,7 +4607,7 @@
/**
* The message sent to apps when the contents of the device list changes if they provide
- * a {#link Handler} object to addOnAudioDeviceConnectionListener().
+ * a {@link Handler} object to addOnAudioDeviceConnectionListener().
*/
private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
private final static int MSG_DEVICES_DEVICES_ADDED = 1;
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 340f279..18d36eb 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -227,7 +227,7 @@
* transfers the object to the <em>Prepared</em> state once the method call
* returns, or a call to {@link #prepareAsync()} (asynchronous) which
* first transfers the object to the <em>Preparing</em> state after the
- * call returns (which occurs almost right way) while the internal
+ * call returns (which occurs almost right away) while the internal
* player engine continues working on the rest of preparation work
* until the preparation work completes. When the preparation completes or when {@link #prepare()} call returns,
* the internal player engine then calls a user supplied callback method,
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index 0f83fd5..8665f28 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -47,414 +47,190 @@
/**
* @hide
- * MediaPlayer2 class can be used to control playback
- * of audio/video files and streams. An example on how to use the methods in
- * this class can be found in {@link android.widget.VideoView}.
+ *
+ * MediaPlayer2 class can be used to control playback of audio/video files and streams.
*
* <p>Topics covered here are:
* <ol>
- * <li><a href="#StateDiagram">State Diagram</a>
- * <li><a href="#Valid_and_Invalid_States">Valid and Invalid States</a>
+ * <li><a href="#PlayerStates">Player states</a>
+ * <li><a href="#InvalidStates">Invalid method calls</a>
* <li><a href="#Permissions">Permissions</a>
- * <li><a href="#Callbacks">Register informational and error callbacks</a>
+ * <li><a href="#Callbacks">Callbacks</a>
* </ol>
*
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about how to use MediaPlayer2, read the
- * <a href="{@docRoot}guide/topics/media/mediaplayer.html">Media Playback</a> developer guide.</p>
- * </div>
*
- * <a name="StateDiagram"></a>
- * <h3>State Diagram</h3>
+ * <h3 id="PlayerStates">Player states</h3>
*
- * <p>Playback control of audio/video files and streams is managed as a state
- * machine. The following diagram shows the life cycle and the states of a
- * MediaPlayer2 object driven by the supported playback control operations.
- * The ovals represent the states a MediaPlayer2 object may reside
- * in. The arcs represent the playback control operations that drive the object
- * state transition. There are two types of arcs. The arcs with a single arrow
- * head represent synchronous method calls, while those with
- * a double arrow head represent asynchronous method calls.</p>
+ * <p>The playback control of audio/video files is managed as a state machine.</p>
+ * <p><div style="text-align:center;"><img src="../../../images/mediaplayer2_state_diagram.png"
+ * alt="MediaPlayer2 State diagram"
+ * border="0" /></div></p>
+ * <p>The MediaPlayer2 object has five states:</p>
+ * <ol>
+ * <li><p>{@link #PLAYER_STATE_IDLE}: MediaPlayer2 is in the <strong>Idle</strong>
+ * state after you create it using
+ * {@link #create()}, or after calling {@link #reset()}.</p>
*
- * <p><img src="../../../images/mediaplayer_state_diagram.gif"
- * alt="MediaPlayer State diagram"
- * border="0" /></p>
+ * <p>While in this state, you should call
+ * {@link #setDataSource(DataSourceDesc2) setDataSource()}. It is a good
+ * programming practice to register an {@link EventCallback#onCallCompleted onCallCompleted}
+ * <a href="#Callbacks">callback</a> and watch for {@link #CALL_STATUS_BAD_VALUE} and
+ * {@link #CALL_STATUS_ERROR_IO}, which might be caused by <code>setDataSource</code>.
+ * </p>
*
- * <p>From this state diagram, one can see that a MediaPlayer2 object has the
- * following states:</p>
+ * <p>Calling {@link #prepare()} transfers a MediaPlayer2 object to
+ * the <strong>Prepared</strong> state. Note
+ * that {@link #prepare()} is asynchronous. When the preparation completes,
+ * if you register an {@link EventCallback#onInfo onInfo} <a href="#Callbacks">callback</a>,
+ * the player executes the callback
+ * with {@link #MEDIA_INFO_PREPARED} and transitions to the
+ * <strong>Prepared</strong> state.</p>
+ * </li>
+ *
+ * <li>{@link #PLAYER_STATE_PREPARED}: A MediaPlayer object must be in the
+ * <strong>Prepared</strong> state before playback can be started for the first time.
+ * While in this state, you can set player properties
+ * such as audio/sound volume and looping by invoking the corresponding set methods.
+ * Calling {@link #play()} transfers a MediaPlayer2 object to
+ * the <strong>Playing</strong> state.
+ * </li>
+ *
+ * <li>{@link #PLAYER_STATE_PLAYING}:
+ * <p>The player plays the data source while in this state.
+ * If you register an {@link EventCallback#onInfo onInfo} <a href="#Callbacks">callback</a>,
+ * the player regularly executes the callback with
+ * {@link #MEDIA_INFO_BUFFERING_UPDATE}.
+ * This allows applications to keep track of the buffering status
+ * while streaming audio/video.</p>
+ *
+ * <p> When the playback reaches the end of stream, the behavior depends on whether or
+ * not you've enabled looping by calling {@link #loopCurrent(boolean) loopCurrent}:</p>
+ * <ul>
+ * <li>If the looping mode was set to <code>false</code>, the player will transfer
+ * to the <strong>Paused</strong> state. If you registered an {@link EventCallback#onInfo
+ * onInfo} <a href="#Callbacks">callback</a>
+ * the player calls the callback with {@link #MEDIA_INFO_DATA_SOURCE_END} and enters
+ * the <strong>Paused</strong> state.
+ * </li>
+ * <li>If the looping mode was set to <code>true</code>,
+ * the MediaPlayer2 object remains in the <strong>Playing</strong> state and replays its
+ * data source from the beginning.</li>
+ * </ul>
+ * </li>
+ *
+ * <li>{@link #PLAYER_STATE_PAUSED}: Audio/video playback pauses while in this state.
+ * Call {@link #play()} to resume playback from the position where it paused.</li>
+ *
+ * <li>{@link #PLAYER_STATE_ERROR}: <p>In general, playback might fail due to various
+ * reasons such as unsupported audio/video format, poorly interleaved
+ * audio/video, resolution too high, streaming timeout, and others.
+ * In addition, due to programming errors, a playback
+ * control operation might be performed from an <a href="#InvalidStates">invalid state</a>.
+ * In these cases the player transitions to the <strong>Error</strong> state.</p>
+ *
+ * <p>If you register an {@link EventCallback#onError onError}}
+ * <a href="#Callbacks">callback</a>,
+ * the callback will be performed when entering the state. When programming errors happen,
+ * such as calling {@link #prepare() prepare} and
+ * {@link #setDataSource(DataSourceDesc) setDataSource} methods
+ * from an <a href="#InvalidStates">invalid state</a>, the callback is called with
+ * {@link #CALL_STATUS_INVALID_OPERATION}. The MediaPlayer2 object enters the
+ * <strong>Error</strong> state whether or not a callback exists. </p>
+ *
+ * <p>To recover from an error and reuse a MediaPlayer2 object that is in the <strong>
+ * Error</strong> state,
+ * call {@link #reset() reset}. The object will return to the <strong>Idle</strong>
+ * state and all state information will be lost.</p>
+ * </li>
+ * </ol>
+ *
+ * <p>You should follow these best practices when coding an app that uses MediaPlayer2:</p>
+ *
* <ul>
- * <li>When a MediaPlayer2 object is just created using <code>create</code> or
- * after {@link #reset()} is called, it is in the <em>Idle</em> state; and after
- * {@link #close()} is called, it is in the <em>End</em> state. Between these
- * two states is the life cycle of the MediaPlayer2 object.
- * <ul>
- * <li> It is a programming error to invoke methods such
- * as {@link #getCurrentPosition()},
- * {@link #getDuration()}, {@link #getVideoHeight()},
- * {@link #getVideoWidth()}, {@link #setAudioAttributes(AudioAttributes)},
- * {@link #setPlayerVolume(float)}, {@link #pause()}, {@link #play()},
- * {@link #seekTo(long, int)} or
- * {@link #prepare()} in the <em>Idle</em> state.
- * <li>It is also recommended that once
- * a MediaPlayer2 object is no longer being used, call {@link #close()} immediately
- * so that resources used by the internal player engine associated with the
- * MediaPlayer2 object can be released immediately. Resource may include
- * singleton resources such as hardware acceleration components and
- * failure to call {@link #close()} may cause subsequent instances of
- * MediaPlayer2 objects to fallback to software implementations or fail
- * altogether. Once the MediaPlayer2
- * object is in the <em>End</em> state, it can no longer be used and
- * there is no way to bring it back to any other state. </li>
- * <li>Furthermore,
- * the MediaPlayer2 objects created using <code>new</code> is in the
- * <em>Idle</em> state.
- * </li>
- * </ul>
- * </li>
- * <li>In general, some playback control operation may fail due to various
- * reasons, such as unsupported audio/video format, poorly interleaved
- * audio/video, resolution too high, streaming timeout, and the like.
- * Thus, error reporting and recovery is an important concern under
- * these circumstances. Sometimes, due to programming errors, invoking a playback
- * control operation in an invalid state may also occur. Under all these
- * error conditions, the internal player engine invokes a user supplied
- * EventCallback.onError() method if an EventCallback has been
- * registered beforehand via
- * {@link #setEventCallback(Executor, EventCallback)}.
- * <ul>
- * <li>It is important to note that once an error occurs, the
- * MediaPlayer2 object enters the <em>Error</em> state (except as noted
- * above), even if an error listener has not been registered by the application.</li>
- * <li>In order to reuse a MediaPlayer2 object that is in the <em>
- * Error</em> state and recover from the error,
- * {@link #reset()} can be called to restore the object to its <em>Idle</em>
- * state.</li>
- * <li>It is good programming practice to have your application
- * register a OnErrorListener to look out for error notifications from
- * the internal player engine.</li>
- * <li>IllegalStateException is
- * thrown to prevent programming errors such as calling
- * {@link #prepare()}, {@link #setDataSource(DataSourceDesc)}
- * methods in an invalid state. </li>
- * </ul>
- * </li>
- * <li>Calling
- * {@link #setDataSource(DataSourceDesc)} transfers a
- * MediaPlayer2 object in the <em>Idle</em> state to the
- * <em>Initialized</em> state.
- * <ul>
- * <li>An IllegalStateException is thrown if
- * setDataSource() is called in any other state.</li>
- * <li>It is good programming
- * practice to always look out for <code>IllegalArgumentException</code>
- * and <code>IOException</code> that may be thrown from
- * <code>setDataSource</code>.</li>
- * </ul>
- * </li>
- * <li>A MediaPlayer2 object must first enter the <em>Prepared</em> state
- * before playback can be started.
- * <ul>
- * <li>There are an asynchronous way that the <em>Prepared</em> state can be reached:
- * a call to {@link #prepare()} (asynchronous) which
- * first transfers the object to the <em>Preparing</em> state after the
- * call returns (which occurs almost right way) while the internal
- * player engine continues working on the rest of preparation work
- * until the preparation work completes. When the preparation completes,
- * the internal player engine then calls a user supplied callback method,
- * onInfo() of the EventCallback interface with {@link #MEDIA_INFO_PREPARED},
- * if an EventCallback is registered beforehand via
- * {@link #setEventCallback(Executor, EventCallback)}.</li>
- * <li>It is important to note that
- * the <em>Preparing</em> state is a transient state, and the behavior
- * of calling any method with side effect while a MediaPlayer2 object is
- * in the <em>Preparing</em> state is undefined.</li>
- * <li>An IllegalStateException is
- * thrown if {@link #prepare()} is called in
- * any other state.</li>
- * <li>While in the <em>Prepared</em> state, properties
- * such as audio/sound volume, screenOnWhilePlaying, looping can be
- * adjusted by invoking the corresponding set methods.</li>
- * </ul>
- * </li>
- * <li>To start the playback, {@link #play()} must be called. After
- * {@link #play()} returns successfully, the MediaPlayer2 object is in the
- * <em>Started</em> state. {@link #getPlayerState()} can be called to test
- * whether the MediaPlayer2 object is in the <em>Started</em> state.
- * <ul>
- * <li>While in the <em>Started</em> state, the internal player engine calls
- * a user supplied callback method EventCallback.onInfo() with
- * {@link #MEDIA_INFO_BUFFERING_UPDATE} if an EventCallback has been
- * registered beforehand via
- * {@link #setEventCallback(Executor, EventCallback)}.
- * This callback allows applications to keep track of the buffering status
- * while streaming audio/video.</li>
- * <li>Calling {@link #play()} has not effect
- * on a MediaPlayer2 object that is already in the <em>Started</em> state.</li>
- * </ul>
- * </li>
- * <li>Playback can be paused and stopped, and the current playback position
- * can be adjusted. Playback can be paused via {@link #pause()}. When the call to
- * {@link #pause()} returns, the MediaPlayer2 object enters the
- * <em>Paused</em> state. Note that the transition from the <em>Started</em>
- * state to the <em>Paused</em> state and vice versa happens
- * asynchronously in the player engine. It may take some time before
- * the state is updated in calls to {@link #getPlayerState()}, and it can be
- * a number of seconds in the case of streamed content.
- * <ul>
- * <li>Calling {@link #play()} to resume playback for a paused
- * MediaPlayer2 object, and the resumed playback
- * position is the same as where it was paused. When the call to
- * {@link #play()} returns, the paused MediaPlayer2 object goes back to
- * the <em>Started</em> state.</li>
- * <li>Calling {@link #pause()} has no effect on
- * a MediaPlayer2 object that is already in the <em>Paused</em> state.</li>
- * </ul>
- * </li>
- * <li>The playback position can be adjusted with a call to
- * {@link #seekTo(long, int)}.
- * <ul>
- * <li>Although the asynchronuous {@link #seekTo(long, int)}
- * call returns right away, the actual seek operation may take a while to
- * finish, especially for audio/video being streamed. When the actual
- * seek operation completes, the internal player engine calls a user
- * supplied EventCallback.onCallCompleted() with
- * {@link #CALL_COMPLETED_SEEK_TO}
- * if an EventCallback has been registered beforehand via
- * {@link #setEventCallback(Executor, EventCallback)}.</li>
- * <li>Please
- * note that {@link #seekTo(long, int)} can also be called in the other states,
- * such as <em>Prepared</em>, <em>Paused</em> and <em>PlaybackCompleted
- * </em> state. When {@link #seekTo(long, int)} is called in those states,
- * one video frame will be displayed if the stream has video and the requested
- * position is valid.
- * </li>
- * <li>Furthermore, the actual current playback position
- * can be retrieved with a call to {@link #getCurrentPosition()}, which
- * is helpful for applications such as a Music player that need to keep
- * track of the playback progress.</li>
- * </ul>
- * </li>
- * <li>When the playback reaches the end of stream, the playback completes.
- * <ul>
- * <li>If current source is set to loop by {@link #loopCurrent(boolean)},
- * the MediaPlayer2 object shall remain in the <em>Started</em> state.</li>
- * <li>If the looping mode was set to <var>false
- * </var>, the player engine calls a user supplied callback method,
- * EventCallback.onCompletion(), if an EventCallback is
- * registered beforehand via
- * {@link #setEventCallback(Executor, EventCallback)}.
- * The invoke of the callback signals that the object is now in the <em>
- * PlaybackCompleted</em> state.</li>
- * <li>While in the <em>PlaybackCompleted</em>
- * state, calling {@link #play()} can restart the playback from the
- * beginning of the audio/video source.</li>
+ *
+ * <li>Use <a href="#Callbacks">callbacks</a> to respond to state changes and errors.</li>
+ *
+ * <li>When a MediaPlayer2 object is no longer being used, call {@link #close() close} as soon as
+ * possible to release the resources used by the internal player engine associated with the
+ * MediaPlayer2. Failure to call {@link #close() close} may cause subsequent instances of
+ * MediaPlayer2 objects to fallback to software implementations or fail altogether.
+ * You cannot use MediaPlayer2
+ * after you call {@link #close() close}. There is no way to bring it back to any other state.</li>
+ *
+ * <li>The current playback position can be retrieved with a call to
+ * {@link #getCurrentPosition() getCurrentPosition},
+ * which is helpful for applications such as a Music player that need to keep track of the playback
+ * progress.</li>
+ *
+ * <li>The playback position can be adjusted with a call to {@link #seekTo seekTo}. Although the
+ * asynchronous {@link #seekTo seekTo} call returns right away, the actual seek operation may take a
+ * while to finish, especially for audio/video being streamed. If you register an
+ * {@link EventCallback#onCallCompleted onCallCompleted} <a href="#Callbacks">callback</a>,
+ * the callback is
+ * called When the seek operation completes with {@link #CALL_COMPLETED_SEEK_TO}.</li>
+ *
+ * <li>You can call {@link #seekTo seekTo} from the <strong>Paused</strong> state.
+ * In this case, if you are playing a video stream and
+ * the requested position is valid one video frame is displayed.</li>
+ *
* </ul>
*
+ * <h3 id="InvalidStates">Invalid method calls</h3>
*
- * <a name="Valid_and_Invalid_States"></a>
- * <h3>Valid and invalid states</h3>
+ * <p>The only methods you safely call from the <strong>Error</strong> state are
+ * {@link #close() close},
+ * {@link #reset() reset},
+ * {@link #notifyWhenCommandLabelReached notifyWhenCommandLabelReached},
+ * {@link #clearPendingCommands() clearPendingCommands},
+ * {@link #setEventCallback setEventCallback},
+ * {@link #clearEventCallback() clearEventCallback}
+ * and {@link #getState() getState}.
+ * Any other methods might throw an exception, return meaningless data, or invoke a
+ * {@link EventCallback#onCallCompleted onCallCompleted} with an error code.</p>
+ *
+ * <p>Most methods can be called from any non-Error state. They will either perform their work or
+ * silently have no effect. The following table lists the methods that will invoke a
+ * {@link EventCallback#onCallCompleted onCallCompleted} with an error code
+ * or throw an exception when they are called from the associated invalid states.</p>
*
* <table border="0" cellspacing="0" cellpadding="0">
- * <tr><td>Method Name </p></td>
- * <td>Valid Sates </p></td>
- * <td>Invalid States </p></td>
- * <td>Comments </p></td></tr>
- * <tr><td>attachAuxEffect </p></td>
- * <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted} </p></td>
- * <td>{Idle, Error} </p></td>
- * <td>This method must be called after setDataSource.
- * Calling it does not change the object state. </p></td></tr>
- * <tr><td>getAudioSessionId </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>getCurrentPosition </p></td>
- * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
- * PlaybackCompleted} </p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change the
- * state. Calling this method in an invalid state transfers the object
- * to the <em>Error</em> state. </p></td></tr>
- * <tr><td>getDuration </p></td>
- * <td>{Prepared, Started, Paused, Stopped, PlaybackCompleted} </p></td>
- * <td>{Idle, Initialized, Error} </p></td>
- * <td>Successful invoke of this method in a valid state does not change the
- * state. Calling this method in an invalid state transfers the object
- * to the <em>Error</em> state. </p></td></tr>
- * <tr><td>getVideoHeight </p></td>
- * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change the
- * state. Calling this method in an invalid state transfers the object
- * to the <em>Error</em> state. </p></td></tr>
- * <tr><td>getVideoWidth </p></td>
- * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change
- * the state. Calling this method in an invalid state transfers the
- * object to the <em>Error</em> state. </p></td></tr>
- * <tr><td>getPlayerState </p></td>
- * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change
- * the state. Calling this method in an invalid state transfers the
- * object to the <em>Error</em> state. </p></td></tr>
- * <tr><td>pause </p></td>
- * <td>{Started, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Prepared, Stopped, Error}</p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Paused</em> state. Calling this method in an
- * invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
- * <tr><td>prepare </p></td>
- * <td>{Initialized, Stopped} </p></td>
- * <td>{Idle, Prepared, Started, Paused, PlaybackCompleted, Error} </p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Preparing</em> state. Calling this method in an
- * invalid state throws an IllegalStateException.</p></td></tr>
- * <tr><td>release </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>After {@link #close()}, the object is no longer available. </p></td></tr>
- * <tr><td>reset </p></td>
- * <td>{Idle, Initialized, Prepared, Started, Paused, Stopped,
- * PlaybackCompleted, Error}</p></td>
- * <td>{}</p></td>
- * <td>After {@link #reset()}, the object is like being just created.</p></td></tr>
- * <tr><td>seekTo </p></td>
- * <td>{Prepared, Started, Paused, PlaybackCompleted} </p></td>
- * <td>{Idle, Initialized, Stopped, Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change
- * the state. Calling this method in an invalid state transfers the
- * object to the <em>Error</em> state. </p></td></tr>
- * <tr><td>setAudioAttributes </p></td>
- * <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method does not change the state. In order for the
- * target audio attributes type to become effective, this method must be called before
- * prepare().</p></td></tr>
- * <tr><td>setAudioSessionId </p></td>
- * <td>{Idle} </p></td>
- * <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
- * Error} </p></td>
- * <td>This method must be called in idle state as the audio session ID must be known before
- * calling setDataSource. Calling it does not change the object
- * state. </p></td></tr>
- * <tr><td>setAudioStreamType (deprecated)</p></td>
- * <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method does not change the state. In order for the
- * target audio stream type to become effective, this method must be called before
- * prepare().</p></td></tr>
- * <tr><td>setAuxEffectSendLevel </p></td>
- * <td>any</p></td>
- * <td>{} </p></td>
- * <td>Calling this method does not change the object state. </p></td></tr>
- * <tr><td>setDataSource </p></td>
- * <td>{Idle} </p></td>
- * <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
- * Error} </p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Initialized</em> state. Calling this method in an
- * invalid state throws an IllegalStateException.</p></td></tr>
- * <tr><td>setDisplay </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>setSurface </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>loopCurrent </p></td>
- * <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method in a valid state does not change
- * the state. Calling this method in an
- * invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
- * <tr><td>isLooping </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>setDrmEventCallback </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>setEventCallback </p></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
- * <tr><td>setPlaybackParams</p></td>
- * <td>{Initialized, Prepared, Started, Paused, PlaybackCompleted, Error}</p></td>
- * <td>{Idle, Stopped} </p></td>
- * <td>This method will change state in some cases, depending on when it's called.
- * </p></td></tr>
- * <tr><td>setPlayerVolume </p></td>
- * <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
- * PlaybackCompleted}</p></td>
- * <td>{Error}</p></td>
- * <td>Successful invoke of this method does not change the state.
- * <tr><td>play </p></td>
- * <td>{Prepared, Started, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Stopped, Error}</p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Started</em> state. Calling this method in an
- * invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
- * <tr><td>stop </p></td>
- * <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Error}</p></td>
- * <td>Successful invoke of this method in a valid state transfers the
- * object to the <em>Stopped</em> state. Calling this method in an
- * invalid state transfers the object to the <em>Error</em> state.</p></td></tr>
- * <tr><td>getTrackInfo </p></td>
- * <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Error}</p></td>
- * <td>Successful invoke of this method does not change the state.</p></td></tr>
- * <tr><td>selectTrack </p></td>
- * <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Error}</p></td>
- * <td>Successful invoke of this method does not change the state.</p></td></tr>
- * <tr><td>deselectTrack </p></td>
- * <td>{Prepared, Started, Stopped, Paused, PlaybackCompleted}</p></td>
- * <td>{Idle, Initialized, Error}</p></td>
- * <td>Successful invoke of this method does not change the state.</p></td></tr>
+ * <tr><th>Method Name</th>
+ * <th>Invalid States</th></tr>
*
+ * <tr><td>setDataSource</td> <td>{Prepared, Paused, Playing}</td></tr>
+ * <tr><td>prepare</td> <td>{Prepared, Paused, Playing}</td></tr>
+ * <tr><td>play</td> <td>{Idle}</td></tr>
+ * <tr><td>pause</td> <td>{Idle}</td></tr>
+ * <tr><td>seekTo</td> <td>{Idle}</td></tr>
+ * <tr><td>getCurrentPosition</td> <td>{Idle}</td></tr>
+ * <tr><td>getDuration</td> <td>{Idle}</td></tr>
+ * <tr><td>getBufferedPosition</td> <td>{Idle}</td></tr>
+ * <tr><td>getTrackInfo</td> <td>{Idle}</td></tr>
+ * <tr><td>getSelectedTrack</td> <td>{Idle}</td></tr>
+ * <tr><td>selectTrack</td> <td>{Idle}</td></tr>
+ * <tr><td>deselectTrack</td> <td>{Idle}</td></tr>
* </table>
*
- * <a name="Permissions"></a>
- * <h3>Permissions</h3>
- * <p>One may need to declare a corresponding WAKE_LOCK permission {@link
- * android.R.styleable#AndroidManifestUsesPermission <uses-permission>}
- * element.
- *
+ * <h3 id="Permissions">Permissions</h3>
* <p>This class requires the {@link android.Manifest.permission#INTERNET} permission
* when used with network-based content.
*
- * <a name="Callbacks"></a>
- * <h3>Callbacks</h3>
- * <p>Applications may want to register for informational and error
- * events in order to be informed of some internal state update and
- * possible runtime errors during playback or streaming. Registration for
- * these events is done by properly setting the appropriate listeners (via calls
- * to
- * {@link #setEventCallback(Executor, EventCallback)},
- * {@link #setDrmEventCallback(Executor, DrmEventCallback)}).
- * In order to receive the respective callback
- * associated with these listeners, applications are required to create
- * MediaPlayer2 objects on a thread with its own Looper running (main UI
- * thread by default has a Looper running).
+ * <h3 id="Callbacks">Callbacks</h3>
+ * <p>Many errors do not result in a transition to the <strong>Error</strong> state.
+ * It is good programming practice to register callback listeners using
+ * {@link #setEventCallback(Executor, EventCallback) setEventCallback} and
+ * {@link #setDrmEventCallback(Executor, DrmEventCallback) setDrmEventCallback}).
+ * You can receive a callback at any time and from any state.</p>
*
+ * <p>If it's important for your app to respond to state changes (for instance, to update the
+ * controls on a transport UI), you should register an
+ * {@link EventCallback#onCallCompleted onCallCompleted} and
+ * detect state change commands by testing the <code>what</code> parameter for a callback from one
+ * of the state transition methods: {@link #CALL_COMPLETED_PREPARE}, {@link #CALL_COMPLETED_PLAY},
+ * and {@link #CALL_COMPLETED_PAUSE}.
+ * Then check the <code>status</code> parameter. The value {@link #CALL_STATUS_NO_ERROR} indicates a
+ * successful transition. Any other value will be an error. Call {@link #getState()} to
+ * determine the current state. </p>
*/
public abstract class MediaPlayer2 implements SubtitleController.Listener
, AutoCloseable
@@ -467,7 +243,6 @@
* @return A MediaPlayer2 object created
*/
public static final MediaPlayer2 create() {
- // TODO: load MediaUpdate APK
return new MediaPlayer2Impl();
}
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 53735e5..678cb9a 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -53,7 +53,6 @@
import com.android.framework.protobuf.InvalidProtocolBufferException;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
import libcore.io.IoBridge;
@@ -350,7 +349,7 @@
addTask(new Task(CALL_COMPLETED_SET_DATA_SOURCE, false) {
@Override
void process() throws IOException {
- Preconditions.checkArgument(dsd != null, "the DataSourceDesc cannot be null");
+ checkArgument(dsd != null, "the DataSourceDesc cannot be null");
int state = getState();
if (state != PLAYER_STATE_ERROR && state != PLAYER_STATE_IDLE) {
throw new IllegalStateException("called in wrong state " + state);
@@ -376,7 +375,7 @@
addTask(new Task(CALL_COMPLETED_SET_NEXT_DATA_SOURCE, false) {
@Override
void process() {
- Preconditions.checkArgument(dsd != null, "the DataSourceDesc cannot be null");
+ checkArgument(dsd != null, "the DataSourceDesc cannot be null");
synchronized (mSrcLock) {
mNextDSDs = new ArrayList<DataSourceDesc>(1);
mNextDSDs.add(dsd);
@@ -690,7 +689,7 @@
private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd, long srcId)
throws IOException {
- Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
+ checkArgument(dsd != null, "the DataSourceDesc cannot be null");
switch (dsd.getType()) {
case DataSourceDesc.TYPE_CALLBACK:
@@ -1290,7 +1289,7 @@
addTask(new Task(CALL_COMPLETED_SET_BUFFERING_PARAMS, false) {
@Override
void process() {
- Preconditions.checkArgument(params != null, "the BufferingParams cannot be null");
+ checkArgument(params != null, "the BufferingParams cannot be null");
_setBufferingParams(params);
}
});
@@ -1354,7 +1353,7 @@
addTask(new Task(CALL_COMPLETED_SET_PLAYBACK_PARAMS, false) {
@Override
void process() {
- Preconditions.checkArgument(params != null, "the PlaybackParams cannot be null");
+ checkArgument(params != null, "the PlaybackParams cannot be null");
_setPlaybackParams(params);
}
});
@@ -1387,7 +1386,7 @@
addTask(new Task(CALL_COMPLETED_SET_SYNC_PARAMS, false) {
@Override
void process() {
- Preconditions.checkArgument(params != null, "the SyncParams cannot be null");
+ checkArgument(params != null, "the SyncParams cannot be null");
_setSyncParams(params);
}
});
@@ -3027,6 +3026,12 @@
}
}
+ public static void checkArgument(boolean expression, String errorMessage) {
+ if (!expression) {
+ throw new IllegalArgumentException(errorMessage);
+ }
+ }
+
private void sendEvent(final EventNotifier notifier) {
synchronized (mEventCbLock) {
try {
@@ -3803,7 +3808,7 @@
private native void _prepareDrm(@NonNull byte[] uuid, @NonNull byte[] drmSessionId);
- // Modular DRM helpers
+ // Modular DRM helpers
private void prepareDrm_createDrmStep(@NonNull UUID uuid)
throws UnsupportedSchemeException {
@@ -4681,7 +4686,7 @@
private void sendCompleteNotification(int status) {
// In {@link #notifyWhenCommandLabelReached} case, a separate callback
- // {#link #onCommandLabelReached} is already called in {@code process()}.
+ // {@link #onCommandLabelReached} is already called in {@code process()}.
if (mMediaCallType == CALL_COMPLETED_NOTIFY_WHEN_COMMAND_LABEL_REACHED) {
return;
}
diff --git a/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureSource.java b/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureSource.java
index 6595baa..7919723 100644
--- a/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureSource.java
+++ b/media/mca/filterpacks/java/android/filterpacks/videosrc/SurfaceTextureSource.java
@@ -38,7 +38,7 @@
* <p>To use, connect up the sourceListener callback, and then when executing
* the graph, use the SurfaceTexture object passed to the callback to feed
* frames into the filter graph. For example, pass the SurfaceTexture into
- * {#link
+ * {@link
* android.hardware.Camera.setPreviewTexture(android.graphics.SurfaceTexture)}.
* This filter is intended for applications that need for flexibility than the
* CameraSource and MediaSource provide. Note that the application needs to
diff --git a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
index 0bf8bc1..4408ef5 100644
--- a/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
+++ b/packages/LocalTransport/src/com/android/localtransport/LocalTransport.java
@@ -95,7 +95,6 @@
private long mFullBackupSize;
private FileInputStream mCurFullRestoreStream;
- private FileOutputStream mFullRestoreSocketStream;
private byte[] mFullRestoreBuffer;
private final LocalTransportParameters mParameters;
@@ -195,6 +194,15 @@
@Override
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data, int flags) {
+ try {
+ return performBackupInternal(packageInfo, data, flags);
+ } finally {
+ IoUtils.closeQuietly(data);
+ }
+ }
+
+ private int performBackupInternal(
+ PackageInfo packageInfo, ParcelFileDescriptor data, int flags) {
boolean isIncremental = (flags & FLAG_INCREMENTAL) != 0;
boolean isNonIncremental = (flags & FLAG_NON_INCREMENTAL) != 0;
@@ -750,7 +758,6 @@
private void resetFullRestoreState() {
IoUtils.closeQuietly(mCurFullRestoreStream);
mCurFullRestoreStream = null;
- mFullRestoreSocketStream = null;
mFullRestoreBuffer = null;
}
@@ -795,10 +802,11 @@
Log.e(TAG, "Unable to read archive for " + name);
return TRANSPORT_PACKAGE_REJECTED;
}
- mFullRestoreSocketStream = new FileOutputStream(socket.getFileDescriptor());
mFullRestoreBuffer = new byte[2*1024];
}
+ FileOutputStream stream = new FileOutputStream(socket.getFileDescriptor());
+
int nRead;
try {
nRead = mCurFullRestoreStream.read(mFullRestoreBuffer);
@@ -815,14 +823,12 @@
if (DEBUG) {
Log.i(TAG, " delivering restore chunk: " + nRead);
}
- mFullRestoreSocketStream.write(mFullRestoreBuffer, 0, nRead);
+ stream.write(mFullRestoreBuffer, 0, nRead);
}
} catch (IOException e) {
return TRANSPORT_ERROR; // Hard error accessing the file; shouldn't happen
} finally {
- // Most transports will need to explicitly close 'socket' here, but this transport
- // is in the same process as the caller so it can leave it up to the backup manager
- // to manage both socket fds.
+ IoUtils.closeQuietly(socket);
}
return nRead;
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 1af2156..d351c4f3 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -17,6 +17,10 @@
package com.android.systemui;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_UP;
+import static android.view.MotionEvent.ACTION_CANCEL;
+
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.InteractionType;
@@ -86,6 +90,7 @@
private boolean mIsEnabled;
private int mCurrentBoundedUserId = -1;
private float mBackButtonAlpha;
+ private MotionEvent mStatusBarGestureDownEvent;
private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
@@ -108,6 +113,9 @@
}
public void onStatusBarMotionEvent(MotionEvent event) {
+ if (!verifyCaller("onStatusBarMotionEvent")) {
+ return;
+ }
long token = Binder.clearCallingIdentity();
try {
// TODO move this logic to message queue
@@ -115,6 +123,16 @@
StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
if (bar != null) {
bar.dispatchNotificationsPanelTouchEvent(event);
+
+ int action = event.getActionMasked();
+ if (action == ACTION_DOWN) {
+ mStatusBarGestureDownEvent = MotionEvent.obtain(event);
+ }
+ if (action == ACTION_UP || action == ACTION_CANCEL) {
+ mStatusBarGestureDownEvent.recycle();
+ mStatusBarGestureDownEvent = null;
+ }
+ event.recycle();
}
});
} finally {
@@ -298,7 +316,7 @@
// This is the death handler for the binder from the launcher service
private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
- = this::startConnectionToCurrentUser;
+ = this::cleanupAfterDeath;
public OverviewProxyService(Context context) {
mContext = context;
@@ -328,6 +346,22 @@
return mBackButtonAlpha;
}
+ public void cleanupAfterDeath() {
+ if (mStatusBarGestureDownEvent != null) {
+ mHandler.post(()-> {
+ StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
+ if (bar != null) {
+ System.out.println("MERONG dispatchNotificationPanelTouchEvent");
+ mStatusBarGestureDownEvent.setAction(MotionEvent.ACTION_CANCEL);
+ bar.dispatchNotificationsPanelTouchEvent(mStatusBarGestureDownEvent);
+ mStatusBarGestureDownEvent.recycle();
+ mStatusBarGestureDownEvent = null;
+ }
+ });
+ }
+ startConnectionToCurrentUser();
+ }
+
public void startConnectionToCurrentUser() {
if (mHandler.getLooper() != Looper.myLooper()) {
mHandler.post(mConnectionRunnable);
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 608e303..512cd82 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1543,7 +1543,6 @@
* ScrimController.GRADIENT_SCRIM_ALPHA * 255);
mGradientDrawable.setAlpha(alpha);
})
- .withEndAction(() -> getWindow().getDecorView().requestAccessibilityFocus())
.start();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 4b5ab2a..c398a4a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -6,7 +6,9 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
+import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@@ -29,6 +31,7 @@
public class PagedTileLayout extends ViewPager implements QSTileLayout {
private static final boolean DEBUG = false;
+ private static final String CURRENT_PAGE = "current_page";
private static final String TAG = "PagedTileLayout";
private static final int REVEAL_SCROLL_DURATION_MILLIS = 750;
@@ -54,6 +57,9 @@
private AnimatorSet mBounceAnimatorSet;
private float mLastExpansion;
private boolean mDistributeTiles = false;
+ private int mPageToRestore = -1;
+ private int mLayoutOrientation;
+ private int mLayoutDirection;
public PagedTileLayout(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -61,13 +67,37 @@
setAdapter(mAdapter);
setOnPageChangeListener(mOnPageChangeListener);
setCurrentItem(0, false);
+ mLayoutOrientation = getResources().getConfiguration().orientation;
+ mLayoutDirection = getLayoutDirection();
+ }
+
+ public void saveInstanceState(Bundle outState) {
+ outState.putInt(CURRENT_PAGE, getCurrentItem());
+ }
+
+ public void restoreInstanceState(Bundle savedInstanceState) {
+ // There's only 1 page at this point. We want to restore the correct page once the
+ // pages have been inflated
+ mPageToRestore = savedInstanceState.getInt(CURRENT_PAGE, -1);
+ }
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mLayoutOrientation != newConfig.orientation) {
+ mLayoutOrientation = newConfig.orientation;
+ setCurrentItem(0, false);
+ }
}
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
- setAdapter(mAdapter);
- setCurrentItem(0, false);
+ if (mLayoutDirection != layoutDirection) {
+ mLayoutDirection = layoutDirection;
+ setAdapter(mAdapter);
+ setCurrentItem(0, false);
+ }
}
@Override
@@ -116,6 +146,7 @@
super.onFinishInflate();
mPages.add((TilePage) LayoutInflater.from(getContext())
.inflate(R.layout.qs_paged_page, this, false));
+ mAdapter.notifyDataSetChanged();
}
public void setPageIndicator(PageIndicator indicator) {
@@ -218,7 +249,10 @@
mPageIndicator.setNumPages(mPages.size());
setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
- setCurrentItem(0, false);
+ if (mPageToRestore != -1) {
+ setCurrentItem(mPageToRestore, false);
+ mPageToRestore = -1;
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 79e5086..42dfcee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -103,6 +103,9 @@
setListening(savedInstanceState.getBoolean(EXTRA_LISTENING));
setEditLocation(view);
mQSCustomizer.restoreInstanceState(savedInstanceState);
+ if (mQsExpanded) {
+ mQSPanel.getTileLayout().restoreInstanceState(savedInstanceState);
+ }
}
SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
}
@@ -127,6 +130,9 @@
outState.putBoolean(EXTRA_EXPANDED, mQsExpanded);
outState.putBoolean(EXTRA_LISTENING, mListening);
mQSCustomizer.saveInstanceState(outState);
+ if (mQsExpanded) {
+ mQSPanel.getTileLayout().saveInstanceState(outState);
+ }
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index e98ef4c..cf63e47 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -25,6 +25,7 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.metrics.LogMaker;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.service.quicksettings.Tile;
@@ -666,6 +667,11 @@
}
public interface QSTileLayout {
+
+ default void saveInstanceState(Bundle outState) {}
+
+ default void restoreInstanceState(Bundle savedInstanceState) {}
+
void addTile(TileRecord tile);
void removeTile(TileRecord tile);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index c3b87af..90ed97f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2852,6 +2852,7 @@
}
}
else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
+ mStatusBarWindowController.setNotTouchable(false);
finishBarAnimations();
resetUserExpandedStates();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 12b6f9d..298a93e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import static android.view.Display.INVALID_DISPLAY;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
@@ -33,6 +34,7 @@
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.TypedValue;
+import android.view.Display;
import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
@@ -307,6 +309,14 @@
0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
InputDevice.SOURCE_KEYBOARD);
+ //Make KeyEvent work on multi-display environment
+ if (getDisplay() != null) {
+ final int displayId = getDisplay().getDisplayId();
+
+ if (displayId != INVALID_DISPLAY) {
+ ev.setDisplayId(displayId);
+ }
+ }
InputManager.getInstance().injectInputEvent(ev,
InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 9bee8db..44ef8b6d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -379,25 +379,20 @@
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
- // Unbind all services from this package, and then update the user state to
- // re-bind new versions of them.
+ // The package should already be removed from mBoundServices, and added into
+ // mBindingServices in binderDied() during updating. Remove services from this
+ // package from mBindingServices, and then update the user state to re-bind new
+ // versions of them.
synchronized (mLock) {
final int userId = getChangingUserId();
if (userId != mCurrentUserId) {
return;
}
UserState userState = getUserStateLocked(userId);
- boolean unboundAService = false;
- for (int i = userState.mBoundServices.size() - 1; i >= 0; i--) {
- AccessibilityServiceConnection boundService =
- userState.mBoundServices.get(i);
- String servicePkg = boundService.mComponentName.getPackageName();
- if (servicePkg.equals(packageName)) {
- boundService.unbindLocked();
- unboundAService = true;
- }
- }
- if (unboundAService) {
+ boolean reboundAService = userState.mBindingServices.removeIf(
+ component -> component != null
+ && component.getPackageName().equals(packageName));
+ if (reboundAService) {
onUserStateChangedLocked(userState);
}
}
@@ -419,6 +414,7 @@
String compPkg = comp.getPackageName();
if (compPkg.equals(packageName)) {
it.remove();
+ userState.mBindingServices.remove(comp);
// Update the enabled services setting.
persistComponentNamesToSettingLocked(
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
@@ -457,6 +453,7 @@
return true;
}
it.remove();
+ userState.mBindingServices.remove(comp);
persistComponentNamesToSettingLocked(
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
userState.mEnabledServices, userId);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index e0eb269..9d84f57 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -253,11 +253,11 @@
return;
}
mWasConnectedAndDied = true;
- mSystemSupport.getKeyEventDispatcher().flush(this);
UserState userState = mUserStateWeakReference.get();
if (userState != null) {
userState.serviceDisconnectedLocked(this);
}
+ resetLocked();
mSystemSupport.getMagnificationController().resetIfNeeded(mId);
mSystemSupport.onClientChange(false);
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 953c99f..5e8ffb7 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1837,7 +1837,7 @@
}
void systemReady() {
- loadGlobalProxy();
+ mProxyTracker.loadGlobalProxy();
registerNetdEventCallback();
synchronized (this) {
@@ -3455,31 +3455,6 @@
mProxyTracker.setGlobalProxy(proxyProperties);
}
- private 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);
- if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
- ProxyInfo proxyProperties;
- if (!TextUtils.isEmpty(pacFileUrl)) {
- proxyProperties = new ProxyInfo(pacFileUrl);
- } else {
- proxyProperties = new ProxyInfo(host, port, exclList);
- }
- if (!proxyProperties.isValid()) {
- if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
- return;
- }
-
- synchronized (mProxyTracker.mProxyLock) {
- mProxyTracker.mGlobalProxy = proxyProperties;
- }
- }
- }
-
@Override
@Nullable
public ProxyInfo getGlobalProxy() {
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 6cba764..376bc0d 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -107,6 +107,124 @@
* Keeps track of device idleness and drives low power mode based on that.
*
* Test: atest com.android.server.DeviceIdleControllerTest
+ *
+ * Current idling state machine (as of Android 9 Pie). This can be visualized using Graphviz:
+
+ digraph {
+ subgraph deep {
+ label="deep";
+
+ STATE_ACTIVE [label="STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon"]
+ STATE_INACTIVE [label="STATE_INACTIVE\nScreen off AND Not charging"]
+ STATE_IDLE_PENDING [
+ label="STATE_IDLE_PENDING\nSignificant motion monitoring turned on"
+ ]
+ STATE_SENSING [label="STATE_SENSING\nMonitoring for ANY motion"]
+ STATE_LOCATING [
+ label="STATE_LOCATING\nRequesting location, motion monitoring still on"
+ ]
+ STATE_IDLE [
+ label="STATE_IDLE\nLocation and motion detection turned off\n"
+ + "Significant motion monitoring still on"
+ ]
+ STATE_IDLE_MAINTENANCE [label="STATE_IDLE_MAINTENANCE\n"]
+
+ STATE_ACTIVE -> STATE_INACTIVE [label="becomeInactiveIfAppropriateLocked()"]
+
+ STATE_INACTIVE -> STATE_ACTIVE [
+ label="handleMotionDetectedLocked(), becomeActiveLocked()"
+ ]
+ STATE_INACTIVE -> STATE_IDLE_PENDING [label="stepIdleStateLocked()"]
+
+ STATE_IDLE_PENDING -> STATE_ACTIVE [
+ label="handleMotionDetectedLocked(), becomeActiveLocked()"
+ ]
+ STATE_IDLE_PENDING -> STATE_SENSING [label="stepIdleStateLocked()"]
+
+ STATE_SENSING -> STATE_ACTIVE [
+ label="handleMotionDetectedLocked(), becomeActiveLocked()"
+ ]
+ STATE_SENSING -> STATE_LOCATING [label="stepIdleStateLocked()"]
+ STATE_SENSING -> STATE_IDLE [
+ label="stepIdleStateLocked()\n"
+ + "No Location Manager OR (no Network provider AND no GPS provider)"
+ ]
+
+ STATE_LOCATING -> STATE_ACTIVE [
+ label="handleMotionDetectedLocked(), becomeActiveLocked()"
+ ]
+ STATE_LOCATING -> STATE_IDLE [label="stepIdleStateLocked()"]
+
+ STATE_IDLE -> STATE_ACTIVE [label="handleMotionDetectedLocked(), becomeActiveLocked()"]
+ STATE_IDLE -> STATE_IDLE_MAINTENANCE [label="stepIdleStateLocked()"]
+
+ STATE_IDLE_MAINTENANCE -> STATE_ACTIVE [
+ label="handleMotionDetectedLocked(), becomeActiveLocked()"
+ ]
+ STATE_IDLE_MAINTENANCE -> STATE_IDLE [
+ label="stepIdleStateLocked(), exitMaintenanceEarlyIfNeededLocked()"
+ ]
+ }
+
+ subgraph light {
+ label="light"
+
+ LIGHT_STATE_ACTIVE [
+ label="LIGHT_STATE_ACTIVE\nScreen on OR Charging OR Alarm going off soon"
+ ]
+ LIGHT_STATE_INACTIVE [label="LIGHT_STATE_INACTIVE\nScreen off AND Not charging"]
+ LIGHT_STATE_PRE_IDLE [
+ label="LIGHT_STATE_PRE_IDLE\n"
+ + "Delay going into LIGHT_STATE_IDLE due to some running jobs or alarms"
+ ]
+ LIGHT_STATE_IDLE [label="LIGHT_STATE_IDLE\n"]
+ LIGHT_STATE_WAITING_FOR_NETWORK [
+ label="LIGHT_STATE_WAITING_FOR_NETWORK\n"
+ + "Coming out of LIGHT_STATE_IDLE, waiting for network"
+ ]
+ LIGHT_STATE_IDLE_MAINTENANCE [label="LIGHT_STATE_IDLE_MAINTENANCE\n"]
+ LIGHT_STATE_OVERRIDE [
+ label="LIGHT_STATE_OVERRIDE\nDevice in deep doze, light no longer changing states"
+ ]
+
+ LIGHT_STATE_ACTIVE -> LIGHT_STATE_INACTIVE [
+ label="becomeInactiveIfAppropriateLocked()"
+ ]
+ LIGHT_STATE_ACTIVE -> LIGHT_STATE_OVERRIDE [label="deep goes to STATE_IDLE"]
+
+ LIGHT_STATE_INACTIVE -> LIGHT_STATE_ACTIVE [label="becomeActiveLocked()"]
+ LIGHT_STATE_INACTIVE -> LIGHT_STATE_PRE_IDLE [label="active jobs"]
+ LIGHT_STATE_INACTIVE -> LIGHT_STATE_IDLE [label="no active jobs"]
+ LIGHT_STATE_INACTIVE -> LIGHT_STATE_OVERRIDE [label="deep goes to STATE_IDLE"]
+
+ LIGHT_STATE_PRE_IDLE -> LIGHT_STATE_ACTIVE [label="becomeActiveLocked()"]
+ LIGHT_STATE_PRE_IDLE -> LIGHT_STATE_IDLE [
+ label="stepLightIdleStateLocked(), exitMaintenanceEarlyIfNeededLocked()"
+ ]
+ LIGHT_STATE_PRE_IDLE -> LIGHT_STATE_OVERRIDE [label="deep goes to STATE_IDLE"]
+
+ LIGHT_STATE_IDLE -> LIGHT_STATE_ACTIVE [label="becomeActiveLocked()"]
+ LIGHT_STATE_IDLE -> LIGHT_STATE_WAITING_FOR_NETWORK [label="no network"]
+ LIGHT_STATE_IDLE -> LIGHT_STATE_IDLE_MAINTENANCE
+ LIGHT_STATE_IDLE -> LIGHT_STATE_OVERRIDE [label="deep goes to STATE_IDLE"]
+
+ LIGHT_STATE_WAITING_FOR_NETWORK -> LIGHT_STATE_ACTIVE [label="becomeActiveLocked()"]
+ LIGHT_STATE_WAITING_FOR_NETWORK -> LIGHT_STATE_IDLE_MAINTENANCE
+ LIGHT_STATE_WAITING_FOR_NETWORK -> LIGHT_STATE_OVERRIDE [
+ label="deep goes to STATE_IDLE"
+ ]
+
+ LIGHT_STATE_IDLE_MAINTENANCE -> LIGHT_STATE_ACTIVE [label="becomeActiveLocked()"]
+ LIGHT_STATE_IDLE_MAINTENANCE -> LIGHT_STATE_IDLE [
+ label="stepLightIdleStateLocked(), exitMaintenanceEarlyIfNeededLocked()"
+ ]
+ LIGHT_STATE_IDLE_MAINTENANCE -> LIGHT_STATE_OVERRIDE [label="deep goes to STATE_IDLE"]
+
+ LIGHT_STATE_OVERRIDE -> LIGHT_STATE_ACTIVE [
+ label="handleMotionDetectedLocked(), becomeActiveLocked()"
+ ]
+ }
+ }
*/
public class DeviceIdleController extends SystemService
implements AnyMotionDetector.DeviceIdleCallback {
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index b7b5bd9..8077e34 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -356,6 +356,12 @@
public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive,
MutableBoolean outLaunched) {
+ if (event.isLongPress()) {
+ // Long presses are sent as a second key down. If the long press threshold is set lower
+ // than the double tap of sequence interval thresholds, this could cause false double
+ // taps or consecutive taps, so we want to ignore the long press event.
+ return false;
+ }
boolean launched = false;
boolean intercept = false;
long powerTapInterval;
diff --git a/services/core/java/com/android/server/appbinding/AppBindingConstants.java b/services/core/java/com/android/server/appbinding/AppBindingConstants.java
index b0088a8..7184769 100644
--- a/services/core/java/com/android/server/appbinding/AppBindingConstants.java
+++ b/services/core/java/com/android/server/appbinding/AppBindingConstants.java
@@ -40,6 +40,9 @@
private static final String SERVICE_STABLE_CONNECTION_THRESHOLD_SEC_KEY =
"service_stable_connection_threshold_sec";
+ private static final String SMS_SERVICE_ENABLED_KEY =
+ "sms_service_enabled";
+
private static final String SMS_APP_BIND_FLAGS_KEY =
"sms_app_bind_flags";
@@ -67,6 +70,11 @@
public final long SERVICE_STABLE_CONNECTION_THRESHOLD_SEC;
/**
+ * Whether to actually bind to the default SMS app service. (Feature flag)
+ */
+ public final boolean SMS_SERVICE_ENABLED;
+
+ /**
* Extra binding flags for SMS service.
*/
public final int SMS_APP_BIND_FLAGS;
@@ -92,6 +100,8 @@
long serviceReconnectMaxBackoffSec = parser.getLong(
SERVICE_RECONNECT_MAX_BACKOFF_SEC_KEY, TimeUnit.HOURS.toSeconds(1));
+ boolean smsServiceEnabled = parser.getBoolean(SMS_SERVICE_ENABLED_KEY, true);
+
int smsAppBindFlags = parser.getInt(
SMS_APP_BIND_FLAGS_KEY,
Context.BIND_NOT_VISIBLE | Context.BIND_FOREGROUND_SERVICE);
@@ -114,6 +124,7 @@
SERVICE_RECONNECT_BACKOFF_INCREASE = serviceReconnectBackoffIncrease;
SERVICE_RECONNECT_MAX_BACKOFF_SEC = serviceReconnectMaxBackoffSec;
SERVICE_STABLE_CONNECTION_THRESHOLD_SEC = serviceStableConnectionThresholdSec;
+ SMS_SERVICE_ENABLED = smsServiceEnabled;
SMS_APP_BIND_FLAGS = smsAppBindFlags;
}
@@ -129,7 +140,8 @@
*/
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
- pw.println("Constants:");
+ pw.print("Constants: ");
+ pw.println(sourceSettings);
pw.print(prefix);
pw.print(" SERVICE_RECONNECT_BACKOFF_SEC: ");
@@ -148,6 +160,10 @@
pw.println(SERVICE_STABLE_CONNECTION_THRESHOLD_SEC);
pw.print(prefix);
+ pw.print(" SMS_SERVICE_ENABLED: ");
+ pw.println(SMS_SERVICE_ENABLED);
+
+ pw.print(prefix);
pw.print(" SMS_APP_BIND_FLAGS: 0x");
pw.println(Integer.toHexString(SMS_APP_BIND_FLAGS));
}
diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java
index 8c38809..3131255 100644
--- a/services/core/java/com/android/server/appbinding/AppBindingService.java
+++ b/services/core/java/com/android/server/appbinding/AppBindingService.java
@@ -422,7 +422,7 @@
unbindServicesLocked(userId, target, reasonForLog);
}
- final ServiceInfo service = app.findService(userId, mIPackageManager);
+ final ServiceInfo service = app.findService(userId, mIPackageManager, mConstants);
if (service == null) {
continue;
}
diff --git a/services/core/java/com/android/server/appbinding/finders/AppServiceFinder.java b/services/core/java/com/android/server/appbinding/finders/AppServiceFinder.java
index 3d37317..a075c50 100644
--- a/services/core/java/com/android/server/appbinding/finders/AppServiceFinder.java
+++ b/services/core/java/com/android/server/appbinding/finders/AppServiceFinder.java
@@ -69,6 +69,11 @@
mHandler = callbackHandler;
}
+ /** Whether this service should really be enabled. */
+ protected boolean isEnabled(AppBindingConstants constants) {
+ return true;
+ }
+
/** Human readable description of the type of apps; e.g. [Default SMS app] */
@NonNull
public abstract String getAppDescription();
@@ -90,12 +95,20 @@
* Find the target service from the target app on a given user.
*/
@Nullable
- public final ServiceInfo findService(int userId, IPackageManager ipm) {
+ public final ServiceInfo findService(int userId, IPackageManager ipm,
+ AppBindingConstants constants) {
synchronized (mLock) {
mTargetPackages.put(userId, null);
mTargetServices.put(userId, null);
mLastMessages.put(userId, null);
+ if (!isEnabled(constants)) {
+ final String message = "feature disabled";
+ mLastMessages.put(userId, message);
+ Slog.i(TAG, getAppDescription() + " " + message);
+ return null;
+ }
+
final String targetPackage = getTargetPackage(userId);
if (DEBUG) {
Slog.d(TAG, getAppDescription() + " package=" + targetPackage);
diff --git a/services/core/java/com/android/server/appbinding/finders/SmsAppServiceFinder.java b/services/core/java/com/android/server/appbinding/finders/SmsAppServiceFinder.java
index 3340900..fcc28f8 100644
--- a/services/core/java/com/android/server/appbinding/finders/SmsAppServiceFinder.java
+++ b/services/core/java/com/android/server/appbinding/finders/SmsAppServiceFinder.java
@@ -32,7 +32,9 @@
import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.Slog;
+import com.android.internal.R;
import com.android.internal.telephony.SmsApplication;
import com.android.server.appbinding.AppBindingConstants;
@@ -49,6 +51,12 @@
}
@Override
+ protected boolean isEnabled(AppBindingConstants constants) {
+ return constants.SMS_SERVICE_ENABLED
+ && mContext.getResources().getBoolean(R.bool.config_useSmsAppService);
+ }
+
+ @Override
public String getAppDescription() {
return "[Default SMS app]";
}
@@ -77,7 +85,13 @@
public String getTargetPackage(int userId) {
final ComponentName cn = SmsApplication.getDefaultSmsApplicationAsUser(
mContext, /* updateIfNeeded= */ true, userId);
- return cn == null ? null : cn.getPackageName();
+ String ret = cn == null ? null : cn.getPackageName();
+
+ if (DEBUG) {
+ Slog.d(TAG, "getTargetPackage()=" + ret);
+ }
+
+ return ret;
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 5eca489..abc0107 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -63,7 +63,7 @@
*/
public class BiometricService extends SystemService {
- private static final String TAG = "BiometricPromptService";
+ private static final String TAG = "BiometricService";
/**
* No biometric methods or nothing has been enrolled.
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index dc65e1e..b7bbd42 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -142,6 +142,35 @@
}
/**
+ * Read the global proxy settings and cache them in memory.
+ */
+ 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);
+ if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
+ ProxyInfo proxyProperties;
+ if (!TextUtils.isEmpty(pacFileUrl)) {
+ proxyProperties = new ProxyInfo(pacFileUrl);
+ } else {
+ proxyProperties = new ProxyInfo(host, port, exclList);
+ }
+ if (!proxyProperties.isValid()) {
+ if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties);
+ return;
+ }
+
+ synchronized (mProxyLock) {
+ mGlobalProxy = proxyProperties;
+ }
+ }
+ // TODO : shouldn't this function call mPacManager.setCurrentProxyScriptUrl ?
+ }
+
+ /**
* 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
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 910ea73..1f05dc9 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.pm.dex;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.content.Context;
@@ -57,8 +59,6 @@
import dalvik.system.VMRuntime;
import libcore.io.IoUtils;
-import libcore.util.NonNull;
-import libcore.util.Nullable;
import java.io.File;
import java.io.FileNotFoundException;
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 3901ceb..dc0d53b 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -17,6 +17,7 @@
#include <jni.h>
#include <nativehelper/JNIHelp.h>
+#include <binder/IServiceManager.h>
#include <hidl/HidlTransportSupport.h>
#include <schedulerservice/SchedulingPolicyService.h>
@@ -34,7 +35,8 @@
char propBuf[PROPERTY_VALUE_MAX];
property_get("system_init.startsensorservice", propBuf, "1");
if (strcmp(propBuf, "1") == 0) {
- SensorService::instantiate();
+ SensorService::publish(false /* allowIsolated */,
+ IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL);
}
}
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index d8ac561..c66d03c 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -429,7 +429,7 @@
// Internal viewport has changed if there wasn't one earlier, and there is one now, or,
// if they are different.
const bool internalViewportChanged = (newInternalViewport != nullptr) &&
- (oldInternalViewport == nullptr || (*newInternalViewport != *newInternalViewport));
+ (oldInternalViewport == nullptr || (*oldInternalViewport != *newInternalViewport));
if (internalViewportChanged) {
sp<PointerController> controller = mLocked.pointerController.promote();
updatePointerControllerFromViewport(controller, newInternalViewport);
diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
index 2ec6830..4fbc587 100644
--- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
@@ -73,6 +73,9 @@
private static final int IGNORED_ACTION = 13;
private static final int IGNORED_CODE = 1999;
private static final int IGNORED_REPEAT = 42;
+ private static final int IGNORED_META_STATE = 0;
+ private static final int IGNORED_DEVICE_ID = 0;
+ private static final int IGNORED_SCANCODE = 0;
private @Mock Context mContext;
private @Mock Resources mResources;
@@ -369,6 +372,50 @@
}
@Test
+ public void testInterceptPowerKeyDown_longpress() {
+ withCameraDoubleTapPowerEnableConfigValue(true);
+ withCameraDoubleTapPowerDisableSettingValue(0);
+ mGestureLauncherService.updateCameraDoubleTapPowerEnabled();
+ withUserSetupCompleteValue(true);
+
+ long eventTime = INITIAL_EVENT_TIME_MILLIS;
+ KeyEvent keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT);
+ boolean interactive = true;
+ MutableBoolean outLaunched = new MutableBoolean(true);
+ boolean intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+
+ final long interval = GestureLauncherService.CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS - 1;
+ eventTime += interval;
+ keyEvent = new KeyEvent(IGNORED_DOWN_TIME, eventTime, IGNORED_ACTION, IGNORED_CODE,
+ IGNORED_REPEAT, IGNORED_META_STATE, IGNORED_DEVICE_ID, IGNORED_SCANCODE,
+ KeyEvent.FLAG_LONG_PRESS);
+ outLaunched.value = false;
+ intercepted = mGestureLauncherService.interceptPowerKeyDown(keyEvent, interactive,
+ outLaunched);
+ assertFalse(intercepted);
+ assertFalse(outLaunched.value);
+
+ verify(mMetricsLogger, never())
+ .action(eq(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE), anyInt());
+
+ final ArgumentCaptor<Integer> intervalCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMetricsLogger, times(1)).histogram(
+ eq("power_double_tap_interval"), intervalCaptor.capture());
+ List<Integer> intervals = intervalCaptor.getAllValues();
+ assertEquals((int) INITIAL_EVENT_TIME_MILLIS, intervals.get(0).intValue());
+
+ final ArgumentCaptor<Integer> tapCountCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mMetricsLogger, times(1)).histogram(
+ eq("power_consecutive_short_tap_count"), tapCountCaptor.capture());
+ List<Integer> tapCounts = tapCountCaptor.getAllValues();
+ assertEquals(1, tapCounts.get(0).intValue());
+ }
+
+ @Test
public void
testInterceptPowerKeyDown_intervalInBoundsCameraPowerGestureOnInteractiveSetupIncomplete() {
withCameraDoubleTapPowerEnableConfigValue(true);
diff --git a/startop/iorap/Android.bp b/startop/iorap/Android.bp
index 91f6aac..b3b0900 100644
--- a/startop/iorap/Android.bp
+++ b/startop/iorap/Android.bp
@@ -26,26 +26,3 @@
"**/*.java",
],
}
-
-android_test {
- name: "libiorap-java-tests",
- srcs: ["tests/src/**/*.kt"],
-
- static_libs: [
- // non-test dependencies
- "libiorap-java",
- // test android dependencies
- "platform-test-annotations",
- "android-support-test",
- // test framework dependencies
- "mockito-target-inline-minus-junit4",
- "truth-prebuilt",
- ],
-
- //sdk_version: "current",
- //certificate: "platform",
-
- libs: ["android.test.base"],
-
- test_suites: ["device-tests"],
-}
diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp
new file mode 100644
index 0000000..7605784
--- /dev/null
+++ b/startop/iorap/tests/Android.bp
@@ -0,0 +1,40 @@
+// 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.
+
+// TODO: once b/80095087 is fixed, rewrite this back to android_test
+java_library {
+ name: "libiorap-java-test-lib",
+ srcs: ["src/**/*.kt"],
+
+ static_libs: [
+ // non-test dependencies
+ "libiorap-java",
+ // test android dependencies
+ "platform-test-annotations",
+ "android-support-test",
+ // test framework dependencies
+ "mockito-target-inline-minus-junit4",
+ // "mockito-target-minus-junit4",
+ // Mockito also requires JNI (see Android.mk)
+ // and android:debuggable=true (see AndroidManifest.xml)
+ "truth-prebuilt",
+ ],
+
+ // sdk_version: "current",
+ // certificate: "platform",
+
+ libs: ["android.test.base", "android.test.runner"],
+
+ // test_suites: ["device-tests"],
+}
diff --git a/startop/iorap/tests/Android.mk b/startop/iorap/tests/Android.mk
new file mode 100644
index 0000000..1b2aa46
--- /dev/null
+++ b/startop/iorap/tests/Android.mk
@@ -0,0 +1,46 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# android_test does not support JNI libraries
+# TODO: once b/80095087 is fixed, rewrite this back to android_test
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JACK_FLAGS := --multi-dex native
+LOCAL_DX_FLAGS := --multi-dex
+
+LOCAL_PACKAGE_NAME := libiorap-java-tests
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ libiorap-java-test-lib
+
+LOCAL_MULTILIB := both
+
+LOCAL_JNI_SHARED_LIBRARIES := \
+ libdexmakerjvmtiagent \
+ libstaticjvmtiagent \
+ libmultiplejvmtiagentsinterferenceagent
+
+LOCAL_JAVA_LIBRARIES := \
+ android.test.base \
+ android.test.runner
+
+# Use private APIs
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+include $(BUILD_PACKAGE)
diff --git a/startop/iorap/AndroidManifest.xml b/startop/iorap/tests/AndroidManifest.xml
similarity index 78%
rename from startop/iorap/AndroidManifest.xml
rename to startop/iorap/tests/AndroidManifest.xml
index 8e5fe97..99f4add 100644
--- a/startop/iorap/AndroidManifest.xml
+++ b/startop/iorap/tests/AndroidManifest.xml
@@ -25,7 +25,13 @@
android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="com.google.android.startop.iorap.tests" />
- <application>
+ <!--
+ 'debuggable=true' is required to properly load mockito jvmti dependencies,
+ otherwise it gives the following error at runtime:
+
+ Openjdkjvmti plugin was loaded on a non-debuggable Runtime.
+ Plugin was loaded too late to change runtime state to DEBUGGABLE. -->
+ <application android:debuggable="true">
<uses-library android:name="android.test.runner" />
</application>
</manifest>
diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
new file mode 100644
index 0000000..4ba44a9
--- /dev/null
+++ b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.google.android.startop.iorap
+
+import android.net.Uri
+import android.os.ServiceManager
+import android.support.test.filters.MediumTest
+import org.junit.Test
+import org.junit.Ignore
+import org.mockito.Mockito.*
+
+// @Ignore("Test is disabled until iorapd is added to init and there's selinux policies for it")
+@MediumTest
+class IIorapIntegrationTest {
+ /**
+ * @throws ServiceManager.ServiceNotFoundException if iorapd service could not be found
+ */
+ private val iorapService : IIorap by lazy {
+ // TODO: connect to 'iorapd.stub' which doesn't actually do any work other than reply.
+ IIorap.Stub.asInterface(ServiceManager.getServiceOrThrow("iorapd"))
+
+ // Use 'adb shell setenforce 0' otherwise this whole test fails,
+ // because the servicemanager is not allowed to hand out the binder token for iorapd.
+
+ // TODO: implement the selinux policies for iorapd.
+ }
+
+ // A dummy binder stub implementation is required to use with mockito#spy.
+ // Mockito overrides the methods at runtime and tracks how methods were invoked.
+ open class DummyTaskListener : ITaskListener.Stub() {
+ // Note: make parameters nullable to avoid the kotlin IllegalStateExceptions
+ // from using the mockito matchers (eq, argThat, etc).
+ override fun onProgress(requestId: RequestId?, result: TaskResult?) {
+ }
+
+ override fun onComplete(requestId: RequestId?, result: TaskResult?) {
+ }
+ }
+
+ private fun testAnyMethod(func : (RequestId) -> Unit) {
+ val taskListener = spy(DummyTaskListener())!!
+
+ try {
+ iorapService.setTaskListener(taskListener)
+ // Note: Binder guarantees total order for oneway messages sent to the same binder
+ // interface, so we don't need any additional blocking here before sending later calls.
+
+ // Every new method call should have a unique request id.
+ val requestId = RequestId.nextValueForSequence()!!
+
+ // Apply the specific function under test.
+ func(requestId)
+
+ // Typical mockito behavior is to allow any-order callbacks, but we want to test order.
+ val inOrder = inOrder(taskListener)
+
+ // The "stub" behavior of iorapd is that every request immediately gets a response of
+ // BEGAN,ONGOING,COMPLETED
+ inOrder.verify(taskListener, timeout(100)).
+ onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_BEGAN })
+ inOrder.verify(taskListener, timeout(100)).
+ onProgress(eq(requestId), argThat { it!!.state == TaskResult.STATE_ONGOING })
+ inOrder.verify(taskListener, timeout(100)).
+ onComplete(eq(requestId), argThat { it!!.state == TaskResult.STATE_COMPLETED })
+ inOrder.verifyNoMoreInteractions()
+
+ } finally {
+ iorapService.setTaskListener(null)
+ }
+ }
+
+ @Test
+ fun testOnPackageEvent() {
+ testAnyMethod { requestId : RequestId ->
+ iorapService.onPackageEvent(requestId,
+ PackageEvent.createReplaced(
+ Uri.parse("https://www.google.com"), "com.fake.package"))
+ }
+ }
+
+ @Test
+ fun testOnAppIntentEvent() {
+ testAnyMethod { requestId : RequestId ->
+ iorapService.onAppIntentEvent(requestId, AppIntentEvent.createDefaultIntentChanged(
+ ActivityInfo("dont care", "dont care"),
+ ActivityInfo("dont care 2", "dont care 2")))
+ }
+ }
+
+ @Test
+ fun testOnSystemServiceEvent() {
+ testAnyMethod { requestId : RequestId ->
+ iorapService.onSystemServiceEvent(requestId,
+ SystemServiceEvent(SystemServiceEvent.TYPE_START))
+ }
+ }
+
+ @Test
+ fun testOnSystemServiceUserEvent() {
+ testAnyMethod { requestId : RequestId ->
+ iorapService.onSystemServiceUserEvent(requestId,
+ SystemServiceUserEvent(SystemServiceUserEvent.TYPE_START_USER,0))
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ea9ac39..80b6ead 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -8381,6 +8381,29 @@
}
/**
+ * Checks if manual network selection is allowed.
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ *
+ * @return {@code true} if manual network selection is allowed, otherwise return {@code false}.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+ public boolean isManualNetworkSelectionAllowed() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isManualNetworkSelectionAllowed(getSubId());
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#isManualNetworkSelectionAllowed", e);
+ }
+ return true;
+ }
+
+ /**
* Get the most recently available signal strength information.
*
* Get the most recent SignalStrength information reported by the modem. Due
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index ca2bcff..32eb12b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -808,6 +808,13 @@
*/
boolean isDataEnabled(int subId);
+ /**
+ * Checks if manual network selection is allowed.
+ *
+ * @return {@code true} if manual network selection is allowed, otherwise return {@code false}.
+ */
+ boolean isManualNetworkSelectionAllowed(int subId);
+
/**
* Get P-CSCF address from PCO after data connection is established or modified.
* @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index 39722c6..5ed283e 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -584,7 +584,8 @@
// We only make the change if the new package is valid
PackageManager packageManager = context.getPackageManager();
- Collection<SmsApplicationData> applications = getApplicationCollection(context);
+ Collection<SmsApplicationData> applications = getApplicationCollectionInternal(
+ context, userId);
SmsApplicationData oldAppData = oldPackageName != null ?
getApplicationForPackage(applications, oldPackageName) : null;
SmsApplicationData applicationData = getApplicationForPackage(applications, packageName);
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index 2c356d1..b6a984f 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -16,6 +16,8 @@
#include "DumpManifest.h"
+#include <algorithm>
+
#include "LoadedApk.h"
#include "SdkConstants.h"
#include "ValueVisitor.h"
@@ -70,10 +72,14 @@
CATEGORY_ATTR = 0x010103e8,
BANNER_ATTR = 0x10103f2,
ISGAME_ATTR = 0x10103f4,
+ VERSION_ATTR = 0x01010519,
+ CERT_DIGEST_ATTR = 0x01010548,
REQUIRED_FEATURE_ATTR = 0x1010557,
REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
COMPILE_SDK_VERSION_ATTR = 0x01010572,
COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573,
+ VERSION_MAJOR_ATTR = 0x01010577,
+ PACKAGE_TYPE_ATTR = 0x01010587,
};
const std::string& kAndroidNamespace = "http://schemas.android.com/apk/res/android";
@@ -1318,6 +1324,70 @@
}
};
+/** Represents <static-library> elements. **/
+class StaticLibrary : public ManifestExtractor::Element {
+ public:
+ StaticLibrary() = default;
+ std::string name;
+ int version;
+ int versionMajor;
+
+ void Extract(xml::Element* element) override {
+ auto parent_stack = extractor()->parent_stack();
+ if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+ }
+ }
+
+ void Print(text::Printer& printer) override {
+ printer.Print(StringPrintf(
+ "static-library: name='%s' version='%d' versionMajor='%d'\n",
+ name.data(), version, versionMajor));
+ }
+};
+
+/** Represents <uses-static-library> elements. **/
+class UsesStaticLibrary : public ManifestExtractor::Element {
+ public:
+ UsesStaticLibrary() = default;
+ std::string name;
+ int version;
+ int versionMajor;
+ std::vector<std::string> certDigests;
+
+ void Extract(xml::Element* element) override {
+ auto parent_stack = extractor()->parent_stack();
+ if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
+ name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
+ version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+ AddCertDigest(element);
+ }
+ }
+
+ void AddCertDigest(xml::Element* element) {
+ std::string digest = GetAttributeStringDefault(FindAttribute(element, CERT_DIGEST_ATTR), "");
+ // We allow ":" delimiters in the SHA declaration as this is the format
+ // emitted by the certtool making it easy for developers to copy/paste.
+ digest.erase(std::remove(digest.begin(), digest.end(), ':'), digest.end());
+ if (!digest.empty()) {
+ certDigests.push_back(digest);
+ }
+ }
+
+ void Print(text::Printer& printer) override {
+ printer.Print(StringPrintf(
+ "uses-static-library: name='%s' version='%d' versionMajor='%d'",
+ name.data(), version, versionMajor));
+ for (size_t i = 0; i < certDigests.size(); i++) {
+ printer.Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
+ }
+ printer.Print("\n");
+ }
+};
+
/**
* Represents <meta-data> elements. These tags are only printed when a flag is passed in to
* explicitly enable meta data printing.
@@ -1326,29 +1396,29 @@
public:
MetaData() = default;
std::string name;
- const std::string* value;
+ std::string value;
const int* value_int;
- const std::string* resource;
+ std::string resource;
const int* resource_int;
void Extract(xml::Element* element) override {
name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
- value = GetAttributeString(FindAttribute(element, VALUE_ATTR));
+ value = GetAttributeStringDefault(FindAttribute(element, VALUE_ATTR), "");
value_int = GetAttributeInteger(FindAttribute(element, VALUE_ATTR));
- resource = GetAttributeString(FindAttribute(element, RESOURCE_ATTR));
+ resource = GetAttributeStringDefault(FindAttribute(element, RESOURCE_ATTR), "");
resource_int = GetAttributeInteger(FindAttribute(element, RESOURCE_ATTR));
}
void Print(text::Printer& printer) override {
if (extractor()->options_.include_meta_data && !name.empty()) {
printer.Print(StringPrintf("meta-data: name='%s' ", name.data()));
- if (value) {
- printer.Print(StringPrintf("value='%s' ", value->data()));
+ if (!value.empty()) {
+ printer.Print(StringPrintf("value='%s' ", value.data()));
} else if (value_int) {
printer.Print(StringPrintf("value='%d' ", *value_int));
} else {
- if (resource) {
- printer.Print(StringPrintf("resource='%s' ", resource->data()));
+ if (!resource.empty()) {
+ printer.Print(StringPrintf("resource='%s' ", resource.data()));
} else if (resource_int) {
printer.Print(StringPrintf("resource='%d' ", *resource_int));
}
@@ -1544,15 +1614,65 @@
class UsesPackage : public ManifestExtractor::Element {
public:
UsesPackage() = default;
+ const std::string* packageType = nullptr;
const std::string* name = nullptr;
+ int version;
+ int versionMajor;
+ std::vector<std::string> certDigests;
void Extract(xml::Element* element) override {
- name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+ auto parent_stack = extractor()->parent_stack();
+ if (parent_stack.size() > 0 && ElementCast<Application>(parent_stack[0])) {
+ packageType = GetAttributeString(FindAttribute(element, PACKAGE_TYPE_ATTR));
+ name = GetAttributeString(FindAttribute(element, NAME_ATTR));
+ version = GetAttributeIntegerDefault(FindAttribute(element, VERSION_ATTR), 0);
+ versionMajor = GetAttributeIntegerDefault(FindAttribute(element, VERSION_MAJOR_ATTR), 0);
+ AddCertDigest(element);
+ }
+ }
+
+ void AddCertDigest(xml::Element* element) {
+ std::string digest = GetAttributeStringDefault(FindAttribute(element, CERT_DIGEST_ATTR), "");
+ // We allow ":" delimiters in the SHA declaration as this is the format
+ // emitted by the certtool making it easy for developers to copy/paste.
+ digest.erase(std::remove(digest.begin(), digest.end(), ':'), digest.end());
+ if (!digest.empty()) {
+ certDigests.push_back(digest);
+ }
}
void Print(text::Printer& printer) override {
if (name) {
- printer.Print(StringPrintf("uses-package:'%s'\n", name->data()));
+ if (packageType) {
+ printer.Print(StringPrintf(
+ "uses-typed-package: type='%s' name='%s' version='%d' versionMajor='%d'",
+ packageType->data(), name->data(), version, versionMajor));
+ for (size_t i = 0; i < certDigests.size(); i++) {
+ printer.Print(StringPrintf(" certDigest='%s'", certDigests[i].data()));
+ }
+ printer.Print("\n");
+ } else {
+ printer.Print(StringPrintf("uses-package:'%s'\n", name->data()));
+ }
+ }
+ }
+};
+
+/** Represents <additional-certificate> elements. **/
+class AdditionalCertificate : public ManifestExtractor::Element {
+ public:
+ AdditionalCertificate() = default;
+
+ void Extract(xml::Element* element) override {
+ auto parent_stack = extractor()->parent_stack();
+ if (parent_stack.size() > 0) {
+ if (ElementCast<UsesPackage>(parent_stack[0])) {
+ UsesPackage* uses = ElementCast<UsesPackage>(parent_stack[0]);
+ uses->AddCertDigest(element);
+ } else if (ElementCast<UsesStaticLibrary>(parent_stack[0])) {
+ UsesStaticLibrary* uses = ElementCast<UsesStaticLibrary>(parent_stack[0]);
+ uses->AddCertDigest(element);
+ }
}
}
};
@@ -1837,10 +1957,10 @@
&& offhost_apdu_action)) {
// Attempt to load the resource file
- if (!meta_data->resource) {
+ if (!meta_data->resource.empty()) {
return;
}
- auto resource = apk->LoadXml(*meta_data->resource, diag);
+ auto resource = apk->LoadXml(meta_data->resource, diag);
if (!resource) {
return;
}
@@ -2065,6 +2185,9 @@
{"uses-permission-sdk-23", std::is_base_of<UsesPermissionSdk23, T>::value},
{"uses-library", std::is_base_of<UsesLibrary, T>::value},
{"uses-package", std::is_base_of<UsesPackage, T>::value},
+ {"static-library", std::is_base_of<StaticLibrary, T>::value},
+ {"uses-static-library", std::is_base_of<UsesStaticLibrary, T>::value},
+ {"additional-certificate", std::is_base_of<AdditionalCertificate, T>::value},
{"uses-sdk", std::is_base_of<UsesSdkBadging, T>::value},
};
@@ -2110,7 +2233,10 @@
{"uses-permission", &CreateType<UsesPermission>},
{"uses-permission-sdk-23", &CreateType<UsesPermissionSdk23>},
{"uses-library", &CreateType<UsesLibrary>},
+ {"static-library", &CreateType<StaticLibrary>},
+ {"uses-static-library", &CreateType<UsesStaticLibrary>},
{"uses-package", &CreateType<UsesPackage>},
+ {"additional-certificate", &CreateType<AdditionalCertificate>},
{"uses-sdk", &CreateType<UsesSdkBadging>},
};
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index fa6538d..85bf6f2 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -393,6 +393,10 @@
uses_static_library_action.Action(RequiredAndroidAttribute("certDigest"));
uses_static_library_action["additional-certificate"];
+ xml::XmlNodeAction& uses_package_action = application_action["uses-package"];
+ uses_package_action.Action(RequiredNameIsJavaPackage);
+ uses_package_action["additional-certificate"];
+
if (options_.debug_mode) {
application_action.Action([&](xml::Element* el) -> bool {
xml::Attribute *attr = el->FindOrCreateAttribute(xml::kSchemaAndroid, "debuggable");
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 58c1300..7472278 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -513,7 +513,7 @@
/**
* @hide
* Universal name for app creating the configuration
- * see {#link {@link PackageManager#getNameForUid(int)}
+ * see {@link PackageManager#getNameForUid(int)}
*/
@SystemApi
public String creatorName;
@@ -521,7 +521,7 @@
/**
* @hide
* Universal name for app updating the configuration
- * see {#link {@link PackageManager#getNameForUid(int)}
+ * see {@link PackageManager#getNameForUid(int)}
*/
@SystemApi
public String lastUpdateName;