Merge "Expose StaticLayout.Builder publicly" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index e6cd4d7..de401b2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1188,7 +1188,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 supportsAssistGesture = 16844011; // 0x10104eb
+ field public static final int supportsAssist = 16844011; // 0x10104eb
field public static final int supportsRtl = 16843695; // 0x10103af
field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
field public static final int supportsUploading = 16843419; // 0x101029b
@@ -12486,6 +12486,25 @@
enum_constant public static final android.graphics.drawable.GradientDrawable.Orientation TR_BL;
}
+ public final class Icon implements android.os.Parcelable {
+ method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
+ method public static android.graphics.drawable.Icon createWithContentUri(java.lang.String);
+ method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
+ method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
+ method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
+ method public static android.graphics.drawable.Icon createWithResource(android.content.res.Resources, int);
+ method public int describeContents();
+ method public android.graphics.drawable.Drawable loadDrawable(android.content.Context);
+ method public void loadDrawableAsync(android.content.Context, android.os.Message);
+ method public void loadDrawableAsync(android.content.Context, android.os.Handler, android.graphics.drawable.Icon.OnDrawableLoadedListener);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.graphics.drawable.Icon> CREATOR;
+ }
+
+ public static abstract interface Icon.OnDrawableLoadedListener {
+ method public abstract void onDrawableLoaded(android.graphics.drawable.Drawable);
+ }
+
public class InsetDrawable extends android.graphics.drawable.DrawableWrapper {
ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
@@ -18438,6 +18457,7 @@
method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
method public void onLosing(android.net.Network, int);
method public void onLost(android.net.Network);
+ method public void onPreCheck(android.net.Network);
}
public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -27163,7 +27183,8 @@
public static final class Telephony.Carriers implements android.provider.BaseColumns {
field public static final java.lang.String APN = "apn";
field public static final java.lang.String AUTH_TYPE = "authtype";
- field public static final java.lang.String BEARER = "bearer";
+ field public static final deprecated java.lang.String BEARER = "bearer";
+ field public static final java.lang.String BEARER_BITMASK = "bearer_bitmask";
field public static final java.lang.String CARRIER_ENABLED = "carrier_enabled";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String CURRENT = "current";
@@ -30306,17 +30327,17 @@
method public int getHandlePresentation();
method public android.telecom.StatusHints getStatusHints();
method public int getVideoState();
+ method public static boolean hasProperty(int, int);
+ method public boolean hasProperty(int);
+ method public static java.lang.String propertiesToString(int);
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
- field public static final int CAPABILITY_GENERIC_CONFERENCE = 16384; // 0x4000
- field public static final int CAPABILITY_HIGH_DEF_AUDIO = 32768; // 0x8000
field public static final int CAPABILITY_HOLD = 1; // 0x1
field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
field public static final int CAPABILITY_MERGE_CONFERENCE = 4; // 0x4
field public static final int CAPABILITY_MUTE = 64; // 0x40
field public static final int CAPABILITY_RESPOND_VIA_TEXT = 32; // 0x20
field public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 4096; // 0x1000
- field public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 131072; // 0x20000
field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 768; // 0x300
field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 256; // 0x100
field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 512; // 0x200
@@ -30325,12 +30346,11 @@
field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
- field public static final int CAPABILITY_WIFI = 65536; // 0x10000
- }
-
- public class CallProperties {
- ctor public CallProperties();
- field public static final int CONFERENCE = 1; // 0x1
+ field public static final int PROPERTY_CONFERENCE = 1; // 0x1
+ field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
+ field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
+ field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+ field public static final int PROPERTY_WIFI = 8; // 0x8
}
public final class CameraCapabilities implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index acfa300..59578c2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1263,7 +1263,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 supportsAssistGesture = 16844011; // 0x10104eb
+ field public static final int supportsAssist = 16844011; // 0x10104eb
field public static final int supportsRtl = 16843695; // 0x10103af
field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
field public static final int supportsUploading = 16843419; // 0x101029b
@@ -12780,6 +12780,25 @@
enum_constant public static final android.graphics.drawable.GradientDrawable.Orientation TR_BL;
}
+ public final class Icon implements android.os.Parcelable {
+ method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
+ method public static android.graphics.drawable.Icon createWithContentUri(java.lang.String);
+ method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
+ method public static android.graphics.drawable.Icon createWithData(byte[], int, int);
+ method public static android.graphics.drawable.Icon createWithFilePath(java.lang.String);
+ method public static android.graphics.drawable.Icon createWithResource(android.content.res.Resources, int);
+ method public int describeContents();
+ method public android.graphics.drawable.Drawable loadDrawable(android.content.Context);
+ method public void loadDrawableAsync(android.content.Context, android.os.Message);
+ method public void loadDrawableAsync(android.content.Context, android.os.Handler, android.graphics.drawable.Icon.OnDrawableLoadedListener);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.graphics.drawable.Icon> CREATOR;
+ }
+
+ public static abstract interface Icon.OnDrawableLoadedListener {
+ method public abstract void onDrawableLoaded(android.graphics.drawable.Drawable);
+ }
+
public class InsetDrawable extends android.graphics.drawable.DrawableWrapper {
ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
@@ -19906,6 +19925,7 @@
method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
method public void onLosing(android.net.Network, int);
method public void onLost(android.net.Network);
+ method public void onPreCheck(android.net.Network);
}
public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -29176,7 +29196,8 @@
public static final class Telephony.Carriers implements android.provider.BaseColumns {
field public static final java.lang.String APN = "apn";
field public static final java.lang.String AUTH_TYPE = "authtype";
- field public static final java.lang.String BEARER = "bearer";
+ field public static final deprecated java.lang.String BEARER = "bearer";
+ field public static final java.lang.String BEARER_BITMASK = "bearer_bitmask";
field public static final java.lang.String CARRIER_ENABLED = "carrier_enabled";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String CURRENT = "current";
@@ -32422,17 +32443,17 @@
method public int getHandlePresentation();
method public android.telecom.StatusHints getStatusHints();
method public int getVideoState();
+ method public static boolean hasProperty(int, int);
+ method public boolean hasProperty(int);
+ method public static java.lang.String propertiesToString(int);
field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
- field public static final int CAPABILITY_GENERIC_CONFERENCE = 16384; // 0x4000
- field public static final int CAPABILITY_HIGH_DEF_AUDIO = 32768; // 0x8000
field public static final int CAPABILITY_HOLD = 1; // 0x1
field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
field public static final int CAPABILITY_MERGE_CONFERENCE = 4; // 0x4
field public static final int CAPABILITY_MUTE = 64; // 0x40
field public static final int CAPABILITY_RESPOND_VIA_TEXT = 32; // 0x20
field public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 4096; // 0x1000
- field public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 131072; // 0x20000
field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 768; // 0x300
field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 256; // 0x100
field public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 512; // 0x200
@@ -32441,18 +32462,17 @@
field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
- field public static final int CAPABILITY_WIFI = 65536; // 0x10000
+ field public static final int PROPERTY_CONFERENCE = 1; // 0x1
+ field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
+ field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
+ field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+ field public static final int PROPERTY_WIFI = 8; // 0x8
}
public static abstract deprecated class Call.Listener extends android.telecom.Call.Callback {
ctor public Call.Listener();
}
- public class CallProperties {
- ctor public CallProperties();
- field public static final int CONFERENCE = 1; // 0x1
- }
-
public final class CameraCapabilities implements android.os.Parcelable {
ctor public CameraCapabilities(int, int);
method public int describeContents();
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 9d1d312..b0fda9c 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -26,6 +26,10 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.WorkSource;
+import android.text.TextUtils;
+import libcore.util.ZoneInfoDB;
+
+import java.io.IOException;
/**
* This class provides access to the system alarm services. These allow you
@@ -151,6 +155,7 @@
private final IAlarmManager mService;
private final boolean mAlwaysExact;
+ private final int mTargetSdkVersion;
/**
@@ -159,8 +164,8 @@
AlarmManager(IAlarmManager service, Context ctx) {
mService = service;
- final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;
- mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT);
+ mTargetSdkVersion = ctx.getApplicationInfo().targetSdkVersion;
+ mAlwaysExact = (mTargetSdkVersion < Build.VERSION_CODES.KITKAT);
}
private long legacyExactLength() {
@@ -585,12 +590,38 @@
}
/**
- * Set the system default time zone.
- * Requires the permission android.permission.SET_TIME_ZONE.
+ * Sets the system's persistent default time zone. This is the time zone for all apps, even
+ * after a reboot. Use {@link java.util.TimeZone#setDefault} if you just want to change the
+ * time zone within your app, and even then prefer to pass an explicit
+ * {@link java.util.TimeZone} to APIs that require it rather than changing the time zone for
+ * all threads.
*
- * @param timeZone in the format understood by {@link java.util.TimeZone}
+ * <p> On android M and above, it is an error to pass in a non-Olson timezone to this
+ * function. Note that this is a bad idea on all Android releases because POSIX and
+ * the {@code TimeZone} class have opposite interpretations of {@code '+'} and {@code '-'}
+ * in the same non-Olson ID.
+ *
+ * @param timeZone one of the Olson ids from the list returned by
+ * {@link java.util.TimeZone#getAvailableIDs}
*/
public void setTimeZone(String timeZone) {
+ if (TextUtils.isEmpty(timeZone)) {
+ return;
+ }
+
+ // Reject this timezone if it isn't an Olson zone we recognize.
+ if (mTargetSdkVersion >= Build.VERSION_CODES.MNC) {
+ boolean hasTimeZone = false;
+ try {
+ hasTimeZone = ZoneInfoDB.getInstance().hasTimeZone(timeZone);
+ } catch (IOException ignored) {
+ }
+
+ if (!hasTimeZone) {
+ throw new IllegalArgumentException("Timezone: " + timeZone + " is not an Olson ID");
+ }
+ }
+
try {
mService.setTimeZone(timeZone);
} catch (RemoteException ex) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 8a3c9c8..6b161b9 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -223,8 +223,10 @@
public static final int OP_PROCESS_OUTGOING_CALLS = 54;
/** @hide User the fingerprint API. */
public static final int OP_USE_FINGERPRINT = 55;
+ /** @hide Access to body sensors such as heart rate, etc. */
+ public static final int OP_BODY_SENSORS = 56;
/** @hide */
- public static final int _NUM_OP = 56;
+ public static final int _NUM_OP = 57;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -280,9 +282,6 @@
/** @hide Allows an application to send SMS messages. */
public static final String OPSTR_SEND_SMS
= "android:send_sms";
- /** @hide Allows an application to add system alert windows. */
- public static final String OPSTR_SYSTEM_ALERT_WINDOW
- = "android:system_alert_window";
/** @hide Required to be able to access the camera device. */
public static final String OPSTR_CAMERA
= "android:camera";
@@ -295,6 +294,15 @@
/** @hide Required to access phone state related information. */
public static final String OPSTR_ADD_VOICEMAIL
= "android:add_voicemail";
+ /** @hide Access APIs for SIP calling over VOIP or WiFi */
+ public static final String OPSTR_USE_SIP
+ = "android:use_sip";
+ /** @hide Use the fingerprint API. */
+ public static final String OPSTR_USE_FINGERPRINT
+ = "android:use_fingerprint";
+ /** @hide Access to body sensors such as heart rate, etc. */
+ public static final String OPSTR_BODY_SENSORS
+ = "android:body_sensors";
/**
* This maps each operation to the operation that serves as the
@@ -360,7 +368,8 @@
OP_ADD_VOICEMAIL,
OP_USE_SIP,
OP_PROCESS_OUTGOING_CALLS,
- OP_USE_FINGERPRINT
+ OP_USE_FINGERPRINT,
+ OP_BODY_SENSORS
};
/**
@@ -372,30 +381,30 @@
OPSTR_FINE_LOCATION,
null,
null,
+ OPSTR_READ_CONTACTS,
+ OPSTR_WRITE_CONTACTS,
+ OPSTR_READ_CALL_LOG,
+ OPSTR_WRITE_CALL_LOG,
+ OPSTR_READ_CALENDAR,
+ OPSTR_WRITE_CALENDAR,
+ null,
+ null,
+ null,
+ OPSTR_CALL_PHONE,
+ OPSTR_READ_SMS,
+ null,
+ OPSTR_RECEIVE_SMS,
+ null,
+ OPSTR_RECEIVE_MMS,
+ OPSTR_RECEIVE_WAP_PUSH,
+ OPSTR_SEND_SMS,
null,
null,
null,
null,
null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
- null,
+ OPSTR_CAMERA,
+ OPSTR_RECORD_AUDIO,
null,
null,
null,
@@ -419,11 +428,12 @@
null,
null,
null,
+ OPSTR_READ_PHONE_STATE,
+ OPSTR_ADD_VOICEMAIL,
+ OPSTR_USE_SIP,
null,
- null,
- null,
- null,
- null
+ OPSTR_USE_FINGERPRINT,
+ OPSTR_BODY_SENSORS
};
/**
@@ -486,7 +496,8 @@
"ADD_VOICEMAIL",
"USE_SIP",
"PROCESS_OUTGOING_CALLS",
- "USE_FINGERPRINT"
+ "USE_FINGERPRINT",
+ "BODY_SENSORS"
};
/**
@@ -549,7 +560,8 @@
Manifest.permission.ADD_VOICEMAIL,
Manifest.permission.USE_SIP,
Manifest.permission.PROCESS_OUTGOING_CALLS,
- Manifest.permission.USE_FINGERPRINT
+ Manifest.permission.USE_FINGERPRINT,
+ Manifest.permission.BODY_SENSORS
};
/**
@@ -613,7 +625,8 @@
null, // ADD_VOICEMAIL
null, // USE_SIP
null, // PROCESS_OUTGOING_CALLS
- null // USE_FINGERPRINT
+ null, // USE_FINGERPRINT
+ null // BODY_SENSORS
};
/**
@@ -676,7 +689,8 @@
false, //ADD_VOICEMAIL
false, // USE_SIP
false, // PROCESS_OUTGOING_CALLS
- false // USE_FINGERPRINT
+ false, // USE_FINGERPRINT
+ false // BODY_SENSORS
};
/**
@@ -738,6 +752,7 @@
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.MODE_ALLOWED,
AppOpsManager.MODE_ALLOWED
};
@@ -804,37 +819,19 @@
false,
false,
false,
+ false,
false
};
/**
- * This is a mapping from a permission name to public app op name.
+ * Mapping from an app op name to the app op code.
*/
- private static final ArrayMap<String, String> sPermToOp = new ArrayMap<>();
- static {
- sPermToOp.put(Manifest.permission.ACCESS_COARSE_LOCATION, OPSTR_COARSE_LOCATION);
- sPermToOp.put(Manifest.permission.ACCESS_FINE_LOCATION, OPSTR_FINE_LOCATION);
- sPermToOp.put(Manifest.permission.PACKAGE_USAGE_STATS, OPSTR_GET_USAGE_STATS);
- sPermToOp.put(Manifest.permission.READ_CONTACTS, OPSTR_READ_CONTACTS);
- sPermToOp.put(Manifest.permission.WRITE_CONTACTS, OPSTR_WRITE_CONTACTS);
- sPermToOp.put(Manifest.permission.READ_CALL_LOG, OPSTR_READ_CALL_LOG);
- sPermToOp.put(Manifest.permission.WRITE_CALL_LOG, OPSTR_WRITE_CALL_LOG);
- sPermToOp.put(Manifest.permission.READ_CALENDAR, OPSTR_READ_CALENDAR);
- sPermToOp.put(Manifest.permission.WRITE_CALENDAR, OPSTR_WRITE_CALENDAR);
- sPermToOp.put(Manifest.permission.CALL_PHONE, OPSTR_CALL_PHONE);
- sPermToOp.put(Manifest.permission.READ_SMS, OPSTR_READ_SMS);
- sPermToOp.put(Manifest.permission.RECEIVE_SMS, OPSTR_RECEIVE_SMS);
- sPermToOp.put(Manifest.permission.RECEIVE_MMS, OPSTR_RECEIVE_MMS);
- sPermToOp.put(Manifest.permission.RECEIVE_WAP_PUSH, OPSTR_RECEIVE_WAP_PUSH);
- sPermToOp.put(Manifest.permission.SEND_SMS, OPSTR_SEND_SMS);
- sPermToOp.put(Manifest.permission.SYSTEM_ALERT_WINDOW, OPSTR_SYSTEM_ALERT_WINDOW);
- sPermToOp.put(Manifest.permission.CAMERA, OPSTR_CAMERA);
- sPermToOp.put(Manifest.permission.RECORD_AUDIO, OPSTR_RECORD_AUDIO);
- sPermToOp.put(Manifest.permission.READ_PHONE_STATE, OPSTR_READ_PHONE_STATE);
- sPermToOp.put(Manifest.permission.ADD_VOICEMAIL, OPSTR_ADD_VOICEMAIL);
- }
+ private static HashMap<String, Integer> sOpStrToOp = new HashMap<>();
- private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
+ /**
+ * Mapping from a permission to the corresponding app op.
+ */
+ private static HashMap<String, Integer> sPermToOp = new HashMap<>();
static {
if (sOpToSwitch.length != _NUM_OP) {
@@ -874,6 +871,11 @@
sOpStrToOp.put(sOpToString[i], i);
}
}
+ for (int i=0; i<_NUM_OP; i++) {
+ if (sOpPerms[i] != null) {
+ sPermToOp.put(sOpPerms[i], i);
+ }
+ }
}
/**
@@ -922,6 +924,14 @@
}
/**
+ * Retrieve the app op code for a permission, or null if there is not one.
+ * @hide
+ */
+ public static int permissionToOpCode(String permission) {
+ return sPermToOp.get(permission);
+ }
+
+ /**
* Retrieve whether the op allows the system (and system ui) to
* bypass the user restriction.
* @hide
@@ -1185,7 +1195,11 @@
*/
@SystemApi
public static String permissionToOp(String permission) {
- return sPermToOp.get(permission);
+ final Integer opCode = sPermToOp.get(permission);
+ if (opCode == null) {
+ return null;
+ }
+ return sOpToString[opCode];
}
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index cf9813f..9f71ea5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2926,7 +2926,7 @@
* the user has already been set up.
*/
@SystemApi
- public boolean setActiveProfileOwner(ComponentName admin, String ownerName)
+ public boolean setActiveProfileOwner(ComponentName admin, @Deprecated String ownerName)
throws IllegalArgumentException {
if (mService != null) {
try {
@@ -2992,8 +2992,8 @@
* @throws IllegalArgumentException if admin is null, the package isn't installed, or the
* preconditions mentioned are not met.
*/
- public boolean setProfileOwner(ComponentName admin, String ownerName, int userHandle)
- throws IllegalArgumentException {
+ public boolean setProfileOwner(ComponentName admin, @Deprecated String ownerName,
+ int userHandle) throws IllegalArgumentException {
if (admin == null) {
throw new NullPointerException("admin cannot be null");
}
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 00248cc..1205708 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -1053,6 +1053,20 @@
}
}
+ /**
+ * @hide
+ */
+ public boolean isBoundWidgetPackage(String packageName, int userId) {
+ if (mService == null) {
+ return false;
+ }
+ try {
+ return mService.isBoundWidgetPackage(packageName, userId);
+ } catch (RemoteException re) {
+ throw new RuntimeException("system server dead?", re);
+ }
+ }
+
private boolean bindAppWidgetIdIfAllowed(int appWidgetId, int profileId,
ComponentName provider, Bundle options) {
if (mService == null) {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 3044a94..9b4dcc6 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -34,6 +34,7 @@
import android.os.ServiceManager;
import android.app.ActivityThread;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.os.Binder;
import android.util.Log;
import android.util.Pair;
@@ -389,7 +390,7 @@
* @hide
*/
public static final String ACTION_BLE_STATE_CHANGED =
- "anrdoid.bluetooth.adapter.action.BLE_STATE_CHANGED";
+ "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
/**
* Broadcast Action: The notifys Bluetooth ACL connected event. This will be
@@ -632,24 +633,6 @@
}
/**
- * Returns true if LE only mode is enabled, that is apps
- * have authorization to turn only BT ON and the calling
- * app has privilage to do so
- */
- private boolean isLEAlwaysOnEnabled() {
- boolean ret = false;
- if (SystemProperties.getBoolean("ro.bluetooth.blealwayson", true) == true) {
- Log.v(TAG, "LE always on mode is enabled");
- // TODO: System API authorization check
- ret = true;
- } else {
- Log.v(TAG, "LE always on mode is disabled");
- ret = false;
- }
- return ret;
- }
-
- /**
* Turns off Bluetooth LE which was earlier turned on by calling EnableBLE().
*
* <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition
@@ -676,7 +659,7 @@
* @hide
*/
public boolean disableBLE() {
- if (isLEAlwaysOnEnabled() != true) return false;
+ if (!isBleScanAlwaysAvailable()) return false;
int state = getLeState();
if (state == BluetoothAdapter.STATE_ON) {
@@ -738,7 +721,7 @@
* @hide
*/
public boolean enableBLE() {
- if (isLEAlwaysOnEnabled() != true) return false;
+ if (!isBleScanAlwaysAvailable()) return false;
if (isLeEnabled() == true) {
if (DBG) Log.d(TAG, "enableBLE(): BT is already enabled..!");
@@ -1243,8 +1226,12 @@
*/
@SystemApi
public boolean isBleScanAlwaysAvailable() {
- // TODO: implement after Settings UI change.
- return false;
+ try {
+ return mManagerService.isBleScanAlwaysAvailable();
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote expection when calling isBleScanAlwaysAvailable", e);
+ return false;
+ }
}
/**
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index 8d1ce99..0b81ee8 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -44,6 +44,8 @@
String getAddress();
String getName();
+
+ boolean isBleScanAlwaysAvailable();
int updateBleAppCount(IBinder b, boolean enable);
boolean isBleAppPresent();
}
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 123514e..dad486d 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -187,7 +187,7 @@
mScanResultType = scanResultType;
mReportDelayMillis = reportDelayMillis;
mNumOfMatchesPerFilter = numOfMatchesPerFilter;
- mMatchMode = numOfMatchesPerFilter;
+ mMatchMode = matchMode;
}
private ScanSettings(Parcel in) {
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java
index e50b0ff..96000dd 100644
--- a/core/java/android/content/pm/IntentFilterVerificationInfo.java
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java
@@ -48,19 +48,18 @@
private static final String ATTR_PACKAGE_NAME = "packageName";
private static final String ATTR_STATUS = "status";
- private ArrayList<String> mDomains;
+ private ArraySet<String> mDomains = new ArraySet<>();
private String mPackageName;
private int mMainStatus;
public IntentFilterVerificationInfo() {
mPackageName = null;
- mDomains = new ArrayList<>();
mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
}
public IntentFilterVerificationInfo(String packageName, ArrayList<String> domains) {
mPackageName = packageName;
- mDomains = domains;
+ mDomains.addAll(domains);
mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
}
@@ -73,14 +72,6 @@
readFromParcel(source);
}
- public ArrayList<String> getDomains() {
- return mDomains;
- }
-
- public ArraySet<String> getDomainsSet() {
- return new ArraySet<>(mDomains);
- }
-
public String getPackageName() {
return mPackageName;
}
@@ -98,6 +89,14 @@
}
}
+ public ArraySet<String> getDomains() {
+ return mDomains;
+ }
+
+ public void setDomains(ArrayList<String> list) {
+ mDomains = new ArraySet<>(list);
+ }
+
public String getDomainsString() {
StringBuilder sb = new StringBuilder();
for (String str : mDomains) {
@@ -145,7 +144,6 @@
}
mMainStatus = status;
- mDomains = new ArrayList<>();
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -201,15 +199,16 @@
private void readFromParcel(Parcel source) {
mPackageName = source.readString();
mMainStatus = source.readInt();
- mDomains = new ArrayList<>();
- source.readStringList(mDomains);
+ ArrayList<String> list = new ArrayList<>();
+ source.readStringList(list);
+ mDomains.addAll(list);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mPackageName);
dest.writeInt(mMainStatus);
- dest.writeStringList(mDomains);
+ dest.writeStringList(new ArrayList<>(mDomains));
}
public static final Creator<IntentFilterVerificationInfo> CREATOR =
@@ -221,5 +220,4 @@
return new IntentFilterVerificationInfo[size];
}
};
-
}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 11037fd..22a9e9c 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -41,16 +41,19 @@
*/
public class SystemSensorManager extends SensorManager {
private static native void nativeClassInit();
- private static native int nativeGetNextSensor(Sensor sensor, int next);
- private static native int nativeEnableDataInjection(boolean enable);
+ private static native long nativeCreate(String opPackageName);
+ private static native int nativeGetNextSensor(long nativeInstance, Sensor sensor, int next);
+ private static native int nativeEnableDataInjection(long nativeInstance, boolean enable);
private static boolean sSensorModuleInitialized = false;
- private static final Object sSensorModuleLock = new Object();
- private static final ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
- private static final SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
private static InjectEventQueue mInjectEventQueue = null;
private static boolean mDataInjectionMode = false;
+ private final Object mLock = new Object();
+
+ private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();
+ private final SparseArray<Sensor> mHandleToSensor = new SparseArray<>();
+
// Listener list
private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
new HashMap<SensorEventListener, SensorEventQueue>();
@@ -60,44 +63,44 @@
// Looper associated with the context in which this instance was created.
private final Looper mMainLooper;
private final int mTargetSdkLevel;
- private final String mPackageName;
+ private final Context mContext;
private final boolean mHasDataInjectionPermissions;
+ private final long mNativeInstance;
/** {@hide} */
public SystemSensorManager(Context context, Looper mainLooper) {
mMainLooper = mainLooper;
mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;
- mPackageName = context.getPackageName();
- synchronized(sSensorModuleLock) {
+ mContext = context;
+ mNativeInstance = nativeCreate(context.getOpPackageName());
+
+ synchronized(mLock) {
if (!sSensorModuleInitialized) {
sSensorModuleInitialized = true;
-
nativeClassInit();
-
- // initialize the sensor list
- final ArrayList<Sensor> fullList = sFullSensorsList;
- int i = 0;
- do {
- Sensor sensor = new Sensor();
- i = nativeGetNextSensor(sensor, i);
- if (i>=0) {
- //Log.d(TAG, "found sensor: " + sensor.getName() +
- // ", handle=" + sensor.getHandle());
- fullList.add(sensor);
- sHandleToSensor.append(sensor.getHandle(), sensor);
- }
- } while (i>0);
}
mHasDataInjectionPermissions = context.checkSelfPermission(
Manifest.permission.HARDWARE_TEST) == PackageManager.PERMISSION_GRANTED;
}
+
+ // initialize the sensor list
+ int i = 0;
+ while(true) {
+ Sensor sensor = new Sensor();
+ i = nativeGetNextSensor(mNativeInstance, sensor, i);
+ if (i <= 0) {
+ break;
+ }
+ mFullSensorsList.add(sensor);
+ mHandleToSensor.append(sensor.getHandle(), sensor);
+ }
}
/** @hide */
@Override
protected List<Sensor> getFullSensorList() {
- return sFullSensorsList;
+ return mFullSensorsList;
}
@@ -232,8 +235,8 @@
throw new SecurityException("Permission denial. Calling enableDataInjection without "
+ Manifest.permission.HARDWARE_TEST);
}
- synchronized (sSensorModuleLock) {
- int ret = nativeEnableDataInjection(enable);
+ synchronized (mLock) {
+ int ret = nativeEnableDataInjection(mNativeInstance, enable);
// The HAL does not support injection. Ignore.
if (ret != 0) {
Log.e(TAG, "HAL does not support data injection");
@@ -255,7 +258,7 @@
throw new SecurityException("Permission denial. Calling injectSensorData without "
+ Manifest.permission.HARDWARE_TEST);
}
- synchronized (sSensorModuleLock) {
+ synchronized (mLock) {
if (!mDataInjectionMode) {
Log.e(TAG, "Data injection mode not activated before calling injectSensorData");
return false;
@@ -284,15 +287,17 @@
* SensorManager instance.
*/
private static abstract class BaseEventQueue {
- private native long nativeInitBaseEventQueue(WeakReference<BaseEventQueue> eventQWeak,
- MessageQueue msgQ, float[] scratch, String packageName, int mode);
+ private static native long nativeInitBaseEventQueue(long nativeManager,
+ WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ, float[] scratch,
+ String packageName, int mode, String opPackageName);
private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
int maxBatchReportLatencyUs);
private static native int nativeDisableSensor(long eventQ, int handle);
private static native void nativeDestroySensorEventQueue(long eventQ);
private static native int nativeFlushSensor(long eventQ);
private static native int nativeInjectSensorData(long eventQ, int handle,
- float[] values,int accuracy, long timestamp);
+ float[] values,int accuracy, long timestamp);
+
private long nSensorEventQueue;
private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
@@ -305,8 +310,9 @@
protected static final int OPERATING_MODE_DATA_INJECTION = 1;
BaseEventQueue(Looper looper, SystemSensorManager manager, int mode) {
- nSensorEventQueue = nativeInitBaseEventQueue(new WeakReference<BaseEventQueue>(this),
- looper.getQueue(), mScratch, manager.mPackageName, mode);
+ nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,
+ new WeakReference<>(this), looper.getQueue(), mScratch,
+ manager.mContext.getPackageName(), mode, manager.mContext.getOpPackageName());
mCloseGuard.open("dispose");
mManager = manager;
}
@@ -339,7 +345,7 @@
for (int i=0 ; i<mActiveSensors.size(); i++) {
if (mActiveSensors.valueAt(i) == true) {
int handle = mActiveSensors.keyAt(i);
- Sensor sensor = sHandleToSensor.get(handle);
+ Sensor sensor = mManager.mHandleToSensor.get(handle);
if (sensor != null) {
disableSensor(sensor);
mActiveSensors.put(handle, false);
@@ -452,7 +458,7 @@
@Override
protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,
long timestamp) {
- final Sensor sensor = sHandleToSensor.get(handle);
+ final Sensor sensor = mManager.mHandleToSensor.get(handle);
SensorEvent t = null;
synchronized (mSensorsEvents) {
t = mSensorsEvents.get(handle);
@@ -481,7 +487,7 @@
@SuppressWarnings("unused")
protected void dispatchFlushCompleteEvent(int handle) {
if (mListener instanceof SensorEventListener2) {
- final Sensor sensor = sHandleToSensor.get(handle);
+ final Sensor sensor = mManager.mHandleToSensor.get(handle);
((SensorEventListener2)mListener).onFlushCompleted(sensor);
}
return;
@@ -519,7 +525,7 @@
@Override
protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
long timestamp) {
- final Sensor sensor = sHandleToSensor.get(handle);
+ final Sensor sensor = mManager.mHandleToSensor.get(handle);
TriggerEvent t = null;
synchronized (mTriggerEvents) {
t = mTriggerEvents.get(handle);
@@ -546,7 +552,7 @@
}
}
- static final class InjectEventQueue extends BaseEventQueue {
+ final class InjectEventQueue extends BaseEventQueue {
public InjectEventQueue(Looper looper, SystemSensorManager manager) {
super(looper, manager, OPERATING_MODE_DATA_INJECTION);
}
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index f6791a4..e9564b3 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -580,7 +580,8 @@
* indicating that the camera device is in use already.
*
* <p>
- * This error can be produced when opening the camera fails.
+ * This error can be produced when opening the camera fails due to the camera
+ * being used by a higher-priority camera API client.
* </p>
*
* @see #onError
@@ -678,7 +679,7 @@
* {@link CameraAccessException}. The disconnection could be due to a
* change in security policy or permissions; the physical disconnection
* of a removable camera device; or the camera being needed for a
- * higher-priority use case.</p>
+ * higher-priority camera API client.</p>
*
* <p>There may still be capture callbacks that are invoked
* after this method is called, or new image buffers that are delivered
@@ -688,8 +689,9 @@
* about the disconnection.</p>
*
* <p>You should clean up the camera with {@link CameraDevice#close} after
- * this happens, as it is not recoverable until opening the camera again
- * after it becomes {@link CameraManager.AvailabilityCallback#onCameraAvailable available}.
+ * this happens, as it is not recoverable until the camera can be opened
+ * again. For most use cases, this will be when the camera again becomes
+ * {@link CameraManager.AvailabilityCallback#onCameraAvailable available}.
* </p>
*
* @param camera the device that has been disconnected
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 1a00a05..e2d2f61 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -77,8 +77,8 @@
}
/**
- * Return the list of currently connected camera devices by
- * identifier.
+ * Return the list of currently connected camera devices by identifier, including
+ * cameras that may be in use by other camera API clients.
*
* <p>Non-removable cameras use integers starting at 0 for their
* identifiers, while removable cameras have a unique identifier for each
@@ -103,6 +103,11 @@
* <p>The first time a callback is registered, it is immediately called
* with the availability status of all currently known camera devices.</p>
*
+ * <p>{@link AvailabilityCallback#onCameraUnavailable(String)} will be called whenever a camera
+ * device is opened by any camera API client. As of API level 23, other camera API clients may
+ * still be able to open such a camera device, evicting the existing client if they have higher
+ * priority than the existing client of a camera device. See open() for more details.</p>
+ *
* <p>Since this callback will be registered with the camera service, remember to unregister it
* once it is no longer needed; otherwise the callback will continue to receive events
* indefinitely and it may prevent other resources from being released. Specifically, the
@@ -259,14 +264,14 @@
}
/**
- * Helper for openning a connection to a camera with the given ID.
+ * Helper for opening a connection to a camera with the given ID.
*
* @param cameraId The unique identifier of the camera device to open
* @param callback The callback for the camera. Must not be null.
* @param handler The handler to invoke the callback on. Must not be null.
*
* @throws CameraAccessException if the camera is disabled by device policy,
- * or too many camera devices are already open, or the cameraId does not match
+ * too many camera devices are already open, or the cameraId does not match
* any currently available camera device.
*
* @throws SecurityException if the application does not have permission to
@@ -330,7 +335,8 @@
deviceImpl.setRemoteFailure(e);
if (e.getReason() == CameraAccessException.CAMERA_DISABLED ||
- e.getReason() == CameraAccessException.CAMERA_DISCONNECTED) {
+ e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
+ e.getReason() == CameraAccessException.CAMERA_IN_USE) {
// Per API docs, these failures call onError and throw
throw e.asChecked();
}
@@ -369,7 +375,19 @@
* <p>Use {@link #getCameraIdList} to get the list of available camera
* devices. Note that even if an id is listed, open may fail if the device
* is disconnected between the calls to {@link #getCameraIdList} and
- * {@link #openCamera}.</p>
+ * {@link #openCamera}, or if a higher-priority camera API client begins using the
+ * camera device.</p>
+ *
+ * <p>As of API level 23, devices for which the
+ * {@link AvailabilityCallback#onCameraUnavailable(String)} callback has been called due to the
+ * device being in use by a lower-priority, background camera API client can still potentially
+ * be opened by calling this method when the calling camera API client has a higher priority
+ * than the current camera API client using this device. In general, if the top, foreground
+ * activity is running within your application process, your process will be given the highest
+ * priority when accessing the camera, and this method will succeed even if the camera device is
+ * in use by another camera API client. Any lower-priority application that loses control of the
+ * camera in this way will receive an
+ * {@link android.hardware.camera2.CameraDevice.StateCallback#onDisconnected} callback.</p>
*
* <p>Once the camera is successfully opened, {@link CameraDevice.StateCallback#onOpened} will
* be invoked with the newly opened {@link CameraDevice}. The camera device can then be set up
@@ -401,7 +419,7 @@
* {@code null} to use the current thread's {@link android.os.Looper looper}.
*
* @throws CameraAccessException if the camera is disabled by device policy,
- * or the camera has become or was disconnected.
+ * has been disconnected, or is being used by a higher-priority camera API client.
*
* @throws IllegalArgumentException if cameraId or the callback was null,
* or the cameraId does not match any currently or previously available
@@ -477,8 +495,7 @@
}
/**
- * A callback for camera devices becoming available or
- * unavailable to open.
+ * A callback for camera devices becoming available or unavailable to open.
*
* <p>Cameras become available when they are no longer in use, or when a new
* removable camera is connected. They become unavailable when some
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index c531e7e..2d63e3f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -341,7 +341,8 @@
* one. This is used by applications needing to talk to the carrier's
* Multimedia Messaging Service servers.
*
- * @deprecated Applications should instead use {@link #requestNetwork} to request a network that
+ * @deprecated Applications should instead use
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
* provides the {@link NetworkCapabilities#NET_CAPABILITY_MMS} capability.
*/
public static final int TYPE_MOBILE_MMS = 2;
@@ -351,7 +352,8 @@
* one. This is used by applications needing to talk to the carrier's
* Secure User Plane Location servers for help locating the device.
*
- * @deprecated Applications should instead use {@link #requestNetwork} to request a network that
+ * @deprecated Applications should instead use
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
* provides the {@link NetworkCapabilities#NET_CAPABILITY_SUPL} capability.
*/
public static final int TYPE_MOBILE_SUPL = 3;
@@ -367,7 +369,8 @@
* same network interface as {@link #TYPE_MOBILE} but the routing setup
* is different.
*
- * @deprecated Applications should instead use {@link #requestNetwork} to request a network that
+ * @deprecated Applications should instead use
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} to request a network that
* uses the {@link NetworkCapabilities#TRANSPORT_CELLULAR} transport.
*/
public static final int TYPE_MOBILE_HIPRI = 5;
@@ -910,7 +913,8 @@
* implementation+feature combination, except that the value {@code -1}
* always indicates failure.
*
- * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api.
+ * @deprecated Deprecated in favor of the cleaner
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} API.
* @removed
*/
public int startUsingNetworkFeature(int networkType, String feature) {
@@ -958,7 +962,7 @@
* implementation+feature combination, except that the value {@code -1}
* always indicates failure.
*
- * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api.
+ * @deprecated Deprecated in favor of the cleaner {@link unregisterNetworkCallback} API.
* @removed
*/
public int stopUsingNetworkFeature(int networkType, String feature) {
@@ -1236,8 +1240,9 @@
* @param hostAddress the IP address of the host to which the route is desired
* @return {@code true} on success, {@code false} on failure
*
- * @deprecated Deprecated in favor of the {@link #requestNetwork},
- * {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} api.
+ * @deprecated Deprecated in favor of the
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)},
+ * {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} API.
* @removed
*/
public boolean requestRouteToHost(int networkType, int hostAddress) {
@@ -1256,7 +1261,7 @@
* @return {@code true} on success, {@code false} on failure
* @hide
* @deprecated Deprecated in favor of the {@link #requestNetwork} and
- * {@link #bindProcessToNetwork} api.
+ * {@link #bindProcessToNetwork} API.
* @removed
*/
public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
@@ -2144,14 +2149,22 @@
public static final int CANCELED = 8;
/**
- * @hide
- * Called whenever the framework connects to a network that it may use to
- * satisfy this request
+ * Called when the framework connects to a new network to evaluate whether it satisfies this
+ * request. If evaluation succeeds, this callback may be followed by an {@link #onAvailable}
+ * callback. There is no guarantee that this new network will satisfy any requests, or that
+ * the network will stay connected for longer than the time necessary to evaluate it.
+ * <p>
+ * Most applications <b>should not</b> act on this callback, and should instead use
+ * {@link #onAvailable}. This callback is intended for use by applications that can assist
+ * the framework in properly evaluating the network — for example, an application that
+ * can automatically log in to a captive portal without user intervention.
+ *
+ * @param network The {@link Network} of the network that is being evaluated.
*/
public void onPreCheck(Network network) {}
/**
- * Called when the framework connects and has declared new network ready for use.
+ * Called when the framework connects and has declared a new network ready for use.
* This callback may be called more than once if the {@link Network} that is
* satisfying the request changes.
*
@@ -2251,116 +2264,82 @@
@Override
public void handleMessage(Message message) {
Log.d(TAG, "CM callback handler got msg " + message.what);
+ NetworkRequest request = (NetworkRequest) getObject(message, NetworkRequest.class);
+ Network network = (Network) getObject(message, Network.class);
switch (message.what) {
case CALLBACK_PRECHECK: {
- NetworkRequest request = (NetworkRequest)getObject(message,
- NetworkRequest.class);
- NetworkCallback callbacks = getCallbacks(request);
- if (callbacks != null) {
- callbacks.onPreCheck((Network)getObject(message, Network.class));
- } else {
- Log.e(TAG, "callback not found for PRECHECK message");
+ NetworkCallback callback = getCallback(request, "PRECHECK");
+ if (callback != null) {
+ callback.onPreCheck(network);
}
break;
}
case CALLBACK_AVAILABLE: {
- NetworkRequest request = (NetworkRequest)getObject(message,
- NetworkRequest.class);
- NetworkCallback callbacks = getCallbacks(request);
- if (callbacks != null) {
- callbacks.onAvailable((Network)getObject(message, Network.class));
- } else {
- Log.e(TAG, "callback not found for AVAILABLE message");
+ NetworkCallback callback = getCallback(request, "AVAILABLE");
+ if (callback != null) {
+ callback.onAvailable(network);
}
break;
}
case CALLBACK_LOSING: {
- NetworkRequest request = (NetworkRequest)getObject(message,
- NetworkRequest.class);
- NetworkCallback callbacks = getCallbacks(request);
- if (callbacks != null) {
- callbacks.onLosing((Network)getObject(message, Network.class),
- message.arg1);
- } else {
- Log.e(TAG, "callback not found for LOSING message");
+ NetworkCallback callback = getCallback(request, "LOSING");
+ if (callback != null) {
+ callback.onLosing(network, message.arg1);
}
break;
}
case CALLBACK_LOST: {
- NetworkRequest request = (NetworkRequest)getObject(message,
- NetworkRequest.class);
-
- NetworkCallback callbacks = getCallbacks(request);
- if (callbacks != null) {
- callbacks.onLost((Network)getObject(message, Network.class));
- } else {
- Log.e(TAG, "callback not found for LOST message");
+ NetworkCallback callback = getCallback(request, "LOST");
+ if (callback != null) {
+ callback.onLost(network);
}
break;
}
case CALLBACK_UNAVAIL: {
- NetworkRequest request = (NetworkRequest)getObject(message,
- NetworkRequest.class);
- NetworkCallback callbacks = null;
- synchronized(mCallbackMap) {
- callbacks = mCallbackMap.get(request);
- }
- if (callbacks != null) {
- callbacks.onUnavailable();
- } else {
- Log.e(TAG, "callback not found for UNAVAIL message");
+ NetworkCallback callback = getCallback(request, "UNAVAIL");
+ if (callback != null) {
+ callback.onUnavailable();
}
break;
}
case CALLBACK_CAP_CHANGED: {
- NetworkRequest request = (NetworkRequest)getObject(message,
- NetworkRequest.class);
- NetworkCallback callbacks = getCallbacks(request);
- if (callbacks != null) {
- Network network = (Network)getObject(message, Network.class);
+ NetworkCallback callback = getCallback(request, "CAP_CHANGED");
+ if (callback != null) {
NetworkCapabilities cap = (NetworkCapabilities)getObject(message,
NetworkCapabilities.class);
- callbacks.onCapabilitiesChanged(network, cap);
- } else {
- Log.e(TAG, "callback not found for CAP_CHANGED message");
+ callback.onCapabilitiesChanged(network, cap);
}
break;
}
case CALLBACK_IP_CHANGED: {
- NetworkRequest request = (NetworkRequest)getObject(message,
- NetworkRequest.class);
- NetworkCallback callbacks = getCallbacks(request);
- if (callbacks != null) {
- Network network = (Network)getObject(message, Network.class);
+ NetworkCallback callback = getCallback(request, "IP_CHANGED");
+ if (callback != null) {
LinkProperties lp = (LinkProperties)getObject(message,
LinkProperties.class);
- callbacks.onLinkPropertiesChanged(network, lp);
- } else {
- Log.e(TAG, "callback not found for IP_CHANGED message");
+ callback.onLinkPropertiesChanged(network, lp);
}
break;
}
case CALLBACK_RELEASED: {
- NetworkRequest req = (NetworkRequest)getObject(message, NetworkRequest.class);
- NetworkCallback callbacks = null;
+ NetworkCallback callback = null;
synchronized(mCallbackMap) {
- callbacks = mCallbackMap.remove(req);
+ callback = mCallbackMap.remove(request);
}
- if (callbacks != null) {
+ if (callback != null) {
synchronized(mRefCount) {
if (mRefCount.decrementAndGet() == 0) {
getLooper().quit();
}
}
} else {
- Log.e(TAG, "callback not found for CANCELED message");
+ Log.e(TAG, "callback not found for RELEASED message");
}
break;
}
case CALLBACK_EXIT: {
- Log.d(TAG, "Listener quiting");
+ Log.d(TAG, "Listener quitting");
getLooper().quit();
break;
}
@@ -2374,10 +2353,16 @@
private Object getObject(Message msg, Class c) {
return msg.getData().getParcelable(c.getSimpleName());
}
- private NetworkCallback getCallbacks(NetworkRequest req) {
+
+ private NetworkCallback getCallback(NetworkRequest req, String name) {
+ NetworkCallback callback;
synchronized(mCallbackMap) {
- return mCallbackMap.get(req);
+ callback = mCallbackMap.get(req);
}
+ if (callback == null) {
+ Log.e(TAG, "callback not found for " + name + " message");
+ }
+ return callback;
}
}
@@ -2601,10 +2586,10 @@
/**
* Unregisters callbacks about and possibly releases networks originating from
- * {@link #requestNetwork} and {@link #registerNetworkCallback} calls. If the
- * given {@code NetworkCallback} had previously been used with {@code #requestNetwork},
- * any networks that had been connected to only to satisfy that request will be
- * disconnected.
+ * {@link #requestNetwork(NetworkRequest, NetworkCallback)} and {@link #registerNetworkCallback}
+ * calls. If the given {@code NetworkCallback} had previously been used with
+ * {@code #requestNetwork}, any networks that had been connected to only to satisfy that request
+ * will be disconnected.
*
* @param networkCallback The {@link NetworkCallback} used when making the request.
*/
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 8c8bfab..ab70485 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -37,6 +37,11 @@
* @hide
*/
public NetworkCapabilities() {
+ clearAll();
+ mNetworkCapabilities =
+ (1 << NET_CAPABILITY_NOT_RESTRICTED) |
+ (1 << NET_CAPABILITY_TRUSTED) |
+ (1 << NET_CAPABILITY_NOT_VPN);
}
public NetworkCapabilities(NetworkCapabilities nc) {
@@ -50,11 +55,21 @@
}
/**
+ * Completely clears the contents of this object, removing even the capabilities that are set
+ * by default when the object is constructed.
+ * @hide
+ */
+ public void clearAll() {
+ mNetworkCapabilities = mTransportTypes = 0;
+ mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = 0;
+ mNetworkSpecifier = null;
+ }
+
+ /**
* Represents the network's capabilities. If any are specified they will be satisfied
* by any Network that matches all of them.
*/
- private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED) |
- (1 << NET_CAPABILITY_TRUSTED) | (1 << NET_CAPABILITY_NOT_VPN);
+ private long mNetworkCapabilities;
/**
* Indicates this is a network that has the ability to reach the
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index e3e16eb..8e0584a 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
+import android.text.TextUtils;
import android.util.Log;
import java.io.File;
@@ -242,6 +243,15 @@
return DATA_DIRECTORY;
}
+ /** {@hide} */
+ public static File getDataAppDirectory(String volumeUuid) {
+ if (TextUtils.isEmpty(volumeUuid)) {
+ return new File("/data/app");
+ } else {
+ return new File("/mnt/expand/" + volumeUuid + "/app");
+ }
+ }
+
/**
* Return the primary external storage directory. This directory may not
* currently be accessible if it has been mounted by the user on their
diff --git a/core/java/android/os/IPermissionController.aidl b/core/java/android/os/IPermissionController.aidl
index 0cc1603..5e8590a 100644
--- a/core/java/android/os/IPermissionController.aidl
+++ b/core/java/android/os/IPermissionController.aidl
@@ -21,4 +21,5 @@
interface IPermissionController {
boolean checkPermission(String permission, int pid, int uid);
String[] getPackagesForUid(int uid);
+ boolean isRuntimePermission(String permission);
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 8c1f44f..1273772b 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -502,7 +502,25 @@
* {@SystemApi}
*/
public final void writeBlob(byte[] b) {
- nativeWriteBlob(mNativePtr, b, 0, (b != null) ? b.length : 0);
+ writeBlob(b, 0, (b != null) ? b.length : 0);
+ }
+
+ /**
+ * Write a blob of data into the parcel at the current {@link #dataPosition},
+ * growing {@link #dataCapacity} if needed.
+ * @param b Bytes to place into the parcel.
+ * @param offset Index of first byte to be written.
+ * @param len Number of bytes to write.
+ * {@hide}
+ * {@SystemApi}
+ */
+ public final void writeBlob(byte[] b, int offset, int len) {
+ if (b == null) {
+ writeInt(-1);
+ return;
+ }
+ Arrays.checkOffsetAndCount(b.length, offset, len);
+ nativeWriteBlob(mNativePtr, b, offset, len);
}
/**
diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
index 4bc97c9..997d586 100644
--- a/core/java/android/service/voice/VoiceInteractionServiceInfo.java
+++ b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
@@ -43,7 +43,7 @@
private String mSessionService;
private String mRecognitionService;
private String mSettingsActivity;
- private boolean mSupportsAssistGesture;
+ private boolean mSupportsAssist;
public VoiceInteractionServiceInfo(PackageManager pm, ComponentName comp)
throws PackageManager.NameNotFoundException {
@@ -95,8 +95,8 @@
com.android.internal.R.styleable.VoiceInteractionService_recognitionService);
mSettingsActivity = array.getString(
com.android.internal.R.styleable.VoiceInteractionService_settingsActivity);
- mSupportsAssistGesture = array.getBoolean(
- com.android.internal.R.styleable.VoiceInteractionService_supportsAssistGesture,
+ mSupportsAssist = array.getBoolean(
+ com.android.internal.R.styleable.VoiceInteractionService_supportsAssist,
false);
array.recycle();
if (mSessionService == null) {
@@ -145,7 +145,7 @@
return mSettingsActivity;
}
- public boolean getSupportsAssistGesture() {
- return mSupportsAssistGesture;
+ public boolean getSupportsAssist() {
+ return mSupportsAssist;
}
}
diff --git a/core/java/android/view/GhostView.java b/core/java/android/view/GhostView.java
index d58e7c0..bc38e1a 100644
--- a/core/java/android/view/GhostView.java
+++ b/core/java/android/view/GhostView.java
@@ -41,7 +41,7 @@
final ViewGroup parent = (ViewGroup) mView.getParent();
setGhostedVisibility(View.INVISIBLE);
parent.mRecreateDisplayList = true;
- parent.getDisplayList();
+ parent.updateDisplayListIfDirty();
}
@Override
@@ -49,7 +49,7 @@
if (canvas instanceof DisplayListCanvas) {
DisplayListCanvas dlCanvas = (DisplayListCanvas) canvas;
mView.mRecreateDisplayList = true;
- RenderNode renderNode = mView.getDisplayList();
+ RenderNode renderNode = mView.updateDisplayListIfDirty();
if (renderNode.isValid()) {
dlCanvas.insertReorderBarrier(); // enable shadow for this rendernode
dlCanvas.drawRenderNode(renderNode);
@@ -84,7 +84,7 @@
final ViewGroup parent = (ViewGroup) mView.getParent();
if (parent != null) {
parent.mRecreateDisplayList = true;
- parent.getDisplayList();
+ parent.updateDisplayListIfDirty();
}
}
}
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 6db46e9..85b22fb 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -246,6 +246,9 @@
mSurface = null;
mLayer = null;
+ // Make sure if/when new layer gets re-created, transform matrix will
+ // be re-applied.
+ mMatrixChanged = true;
mHadSurface = true;
}
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 87d5d9a..390d81d 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -269,7 +269,7 @@
view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
== View.PFLAG_INVALIDATED;
view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
- view.getDisplayList();
+ view.updateDisplayListIfDirty();
view.mRecreateDisplayList = false;
}
@@ -285,7 +285,7 @@
callbacks.onHardwarePreDraw(canvas);
canvas.insertReorderBarrier();
- canvas.drawRenderNode(view.getDisplayList());
+ canvas.drawRenderNode(view.updateDisplayListIfDirty());
canvas.insertInorderBarrier();
callbacks.onHardwarePostDraw(canvas);
@@ -360,7 +360,7 @@
@Override
boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
return nCopyLayerInto(mNativeProxy,
- layer.getDeferredLayerUpdater(), bitmap.getSkBitmap());
+ layer.getDeferredLayerUpdater(), bitmap);
}
@Override
@@ -531,7 +531,7 @@
private static native long nCreateTextureLayer(long nativeProxy);
private static native void nBuildLayer(long nativeProxy, long node);
- private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
+ private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
private static native void nPushLayerUpdate(long nativeProxy, long layer);
private static native void nCancelLayerUpdate(long nativeProxy, long layer);
private static native void nDetachSurfaceTexture(long nativeProxy, long layer);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 81ad5ad..963b7a6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11091,25 +11091,34 @@
}
/**
- * <p>Sets the opacity of the view. This is a value from 0 to 1, where 0 means the view is
- * completely transparent and 1 means the view is completely opaque.</p>
+ * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is
+ * completely transparent and 1 means the view is completely opaque.
*
- * <p> Note that setting alpha to a translucent value (0 < alpha < 1) can have significant
- * performance implications, especially for large views. It is best to use the alpha property
- * sparingly and transiently, as in the case of fading animations.</p>
+ * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1)
+ * can have significant performance implications, especially for large views. It is best to use
+ * the alpha property sparingly and transiently, as in the case of fading animations.</p>
*
* <p>For a view with a frequently changing alpha, such as during a fading animation, it is
* strongly recommended for performance reasons to either override
- * {@link #hasOverlappingRendering()} to return false if appropriate, or setting a
- * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view.</p>
+ * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a
+ * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration
+ * of the animation. On versions {@link android.os.Build.VERSION_CODES#MNC} and below,
+ * the default path for rendering an unlayered View with alpha could add multiple milliseconds
+ * of rendering cost, even for simple or small views. Starting with
+ * {@link android.os.Build.VERSION_CODES#MNC}, {@link #LAYER_TYPE_HARDWARE} is automatically
+ * applied to the view at the rendering level.</p>
*
* <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is
* responsible for applying the opacity itself.</p>
*
- * <p>Note that if the view is backed by a
- * {@link #setLayerType(int, android.graphics.Paint) layer} and is associated with a
- * {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an alpha value less than
- * 1.0 will supersede the alpha of the layer paint.</p>
+ * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if
+ * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is
+ * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an
+ * alpha value less than 1.0 will supersede the alpha of the layer paint.</p>
+ *
+ * <p>Starting with {@link android.os.Build.VERSION_CODES#MNC}, setting a translucent alpha
+ * value will clip a View to its bounds, unless the View returns <code>false</code> from
+ * {@link #hasOverlappingRendering}.</p>
*
* @param alpha The opacity of the view.
*
@@ -14702,11 +14711,16 @@
return !(mAttachInfo == null || mAttachInfo.mHardwareRenderer == null);
}
- private void updateDisplayListIfDirty() {
+ /**
+ * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported)
+ * @hide
+ */
+ @NonNull
+ public RenderNode updateDisplayListIfDirty() {
final RenderNode renderNode = mRenderNode;
if (!canHaveDisplayList()) {
// can't populate RenderNode, don't try
- return;
+ return renderNode;
}
if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
@@ -14720,7 +14734,7 @@
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
dispatchGetDisplayList();
- return; // no work needed
+ return renderNode; // no work needed
}
// If we got here, we're recreating it. Mark it as such to ensure that
@@ -14769,19 +14783,7 @@
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
}
- }
-
- /**
- * Returns a RenderNode with View draw content recorded, which can be
- * used to draw this view again without executing its draw method.
- *
- * @return A RenderNode ready to replay, or null if caching is not enabled.
- *
- * @hide
- */
- public RenderNode getDisplayList() {
- updateDisplayListIfDirty();
- return mRenderNode;
+ return renderNode;
}
private void resetDisplayList() {
@@ -15543,7 +15545,7 @@
if (drawingWithRenderNode) {
// Delay getting the display list until animation-driven alpha values are
// set up and possibly passed on to the view
- renderNode = getDisplayList();
+ renderNode = updateDisplayListIfDirty();
if (!renderNode.isValid()) {
// Uncommon, but possible. If a view is removed from the hierarchy during the call
// to getDisplayList(), the display list will be marked invalid and we should not
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d0d4201..ef57dc3 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3524,10 +3524,9 @@
}
private void recreateChildDisplayList(View child) {
- child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED)
- == PFLAG_INVALIDATED;
+ child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED) != 0;
child.mPrivateFlags &= ~PFLAG_INVALIDATED;
- child.getDisplayList();
+ child.updateDisplayListIfDirty();
child.mRecreateDisplayList = false;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4158340..fda6e63 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2322,10 +2322,8 @@
* @hide
*/
void outputDisplayList(View view) {
- RenderNode renderNode = view.getDisplayList();
- if (renderNode != null) {
- renderNode.output();
- }
+ RenderNode renderNode = view.updateDisplayListIfDirty();
+ renderNode.output();
}
/**
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index c9d9a8c..1df43d0 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3638,11 +3638,8 @@
startNestedScroll(SCROLL_AXIS_VERTICAL);
- if (mFastScroll != null) {
- boolean intercepted = mFastScroll.onTouchEvent(ev);
- if (intercepted) {
- return true;
- }
+ if (mFastScroll != null && mFastScroll.onTouchEvent(ev)) {
+ return true;
}
initVelocityTrackerIfNotExists();
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 35e7389..9b36b84 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -578,7 +578,12 @@
}
private void hideCursorControllers() {
- if (mSuggestionsPopupWindow != null && !mSuggestionsPopupWindow.isShowingUp()) {
+ // When mTextView is not ExtractEditText, we need to distinguish two kinds of focus-lost.
+ // One is the true focus lost where suggestions pop-up (if any) should be dismissed, and the
+ // other is an side effect of showing the suggestions pop-up itself. We use isShowingUp()
+ // to distinguish one from the other.
+ if (mSuggestionsPopupWindow != null && ((mTextView instanceof ExtractEditText) ||
+ !mSuggestionsPopupWindow.isShowingUp())) {
// Should be done before hide insertion point controller since it triggers a show of it
mSuggestionsPopupWindow.hide();
}
@@ -1397,12 +1402,11 @@
InputMethodManager imm = InputMethodManager.peekInstance();
if (imm != null) {
if (imm.isActive(mTextView)) {
- boolean reported = false;
if (ims.mContentChanged || ims.mSelectionModeChanged) {
// We are in extract mode and the content has changed
// in some way... just report complete new text to the
// input method.
- reported = reportExtractedText();
+ reportExtractedText();
}
}
}
@@ -1919,10 +1923,6 @@
mSuggestionsPopupWindow.show();
}
- boolean areSuggestionsShown() {
- return mSuggestionsPopupWindow != null && mSuggestionsPopupWindow.isShowing();
- }
-
void onScrollChanged() {
if (mPositionListener != null) {
mPositionListener.onScrollChanged();
@@ -4620,8 +4620,6 @@
}
static class InputMethodState {
- Rect mCursorRectInWindow = new Rect();
- float[] mTmpOffset = new float[2];
ExtractedTextRequest mExtractedTextRequest;
final ExtractedText mExtractedText = new ExtractedText();
int mBatchEditNesting;
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 552b274..f06f3c21 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -1389,7 +1389,8 @@
// to intercept events. If it does, we will receive a CANCEL
// event.
if (!mList.isInScrollingContainer()) {
- beginDrag();
+ // This will get dispatched to onTouchEvent(). Start
+ // dragging there.
return true;
}
@@ -1406,6 +1407,8 @@
final float pos = getPosFromMotionEvent(mInitialTouchY);
scrollTo(pos);
+ // This may get dispatched to onTouchEvent(), but it
+ // doesn't really matter since we'll already be in a drag.
return onTouchEvent(ev);
}
break;
@@ -1440,6 +1443,15 @@
}
switch (me.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN: {
+ if (isPointInside(me.getX(), me.getY())) {
+ if (!mList.isInScrollingContainer()) {
+ beginDrag();
+ return true;
+ }
+ }
+ } break;
+
case MotionEvent.ACTION_UP: {
if (mPendingDrag >= 0) {
// Allow a tap to scroll.
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 99bf9f3..86c1b2f 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -30,6 +30,7 @@
void startWatchingMode(int op, String packageName, IAppOpsCallback callback);
void stopWatchingMode(IAppOpsCallback callback);
IBinder getToken(IBinder clientToken);
+ int permissionToOpCode(String permission);
// Remaining methods are only used in Java.
int checkPackage(int uid, String packageName);
@@ -42,5 +43,4 @@
void setUserRestrictions(in Bundle restrictions, int userHandle);
void removeUser(int userHandle);
-
}
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index d149c5b9..4c6db24 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -105,5 +105,5 @@
* Indicates whether the currently active voice interaction service is capable of handling the
* assist gesture.
*/
- boolean activeServiceSupportsAssistGesture();
+ boolean activeServiceSupportsAssist();
}
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index 008d38b..7d3db02 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -65,5 +65,6 @@
in IBinder connection);
void unbindRemoteViewsService(String callingPackage, int appWidgetId, in Intent intent);
int[] getAppWidgetIds(in ComponentName providerComponent);
+ boolean isBoundWidgetPackage(String packageName, int userId);
}
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 3f96174..6173832 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -32,6 +32,7 @@
public static final int NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
public static final int ACTION_BAN_APP_NOTES = 146;
public static final int NOTIFICATION_ZEN_MODE_EVENT_RULE = 147;
+ public static final int ACTION_DISMISS_ALL_NOTES = 148;
public static void visible(Context context, int category) throws IllegalArgumentException {
if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
index 191662c..6d4e058 100644
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java
@@ -216,6 +216,8 @@
if (mVelocityTracker == null) {
return super.onTouchEvent(ev);
}
+ // offset because the view is translated during swipe
+ ev.offsetLocation(mTranslationX, 0);
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_UP:
updateDismiss(ev);
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 6591d29..d0f7591 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -80,11 +80,12 @@
///////////////////////////////////////////////////////////////////////////////////////////////
-static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong bitmapHandle,
+static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jobject jbitmap,
jint tileModeX, jint tileModeY)
{
- const SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle);
- SkShader* s = SkShader::CreateBitmapShader(*bitmap,
+ SkBitmap bitmap;
+ GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+ SkShader* s = SkShader::CreateBitmapShader(bitmap,
(SkShader::TileMode)tileModeX,
(SkShader::TileMode)tileModeY);
@@ -249,7 +250,7 @@
};
static JNINativeMethod gBitmapShaderMethods[] = {
- { "nativeCreate", "(JII)J", (void*)BitmapShader_constructor },
+ { "nativeCreate", "(Landroid/graphics/Bitmap;II)J", (void*)BitmapShader_constructor },
};
static JNINativeMethod gLinearGradientMethods[] = {
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 5d08532..50a1069 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -40,22 +40,21 @@
// Native wrapper constructor used by Canvas(Bitmap)
static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
- SkBitmap* bitmap = nullptr;
+ SkBitmap bitmap;
if (jbitmap != NULL) {
- bitmap = GraphicsJNI::getSkBitmapDeprecated(env, jbitmap);
+ GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
}
- return reinterpret_cast<jlong>(Canvas::create_canvas(
- bitmap ? *bitmap : SkBitmap()));
+ return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
}
// Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
// optionally copying canvas matrix & clip state.
static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) {
- SkBitmap* bitmap = nullptr;
+ SkBitmap bitmap;
if (jbitmap != NULL) {
- bitmap = GraphicsJNI::getSkBitmapDeprecated(env, jbitmap);
+ GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
}
- get_canvas(canvasHandle)->setBitmap(bitmap ? *bitmap : SkBitmap());
+ get_canvas(canvasHandle)->setBitmap(bitmap);
}
static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 0cf596c..f5f8b1f 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -134,13 +134,21 @@
return internedString;
}
-static jint
-nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next)
+static jlong
+nativeCreate
+(JNIEnv *env, jclass clazz, jstring opPackageName)
{
- SensorManager& mgr(SensorManager::getInstance());
+ ScopedUtfChars opPackageNameUtf(env, opPackageName);
+ return (jlong) new SensorManager(String16(opPackageNameUtf.c_str()));
+}
+
+static jint
+nativeGetNextSensor(JNIEnv *env, jclass clazz, jlong sensorManager, jobject sensor, jint next)
+{
+ SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
Sensor const* const* sensorList;
- size_t count = mgr.getSensorList(&sensorList);
+ size_t count = mgr->getSensorList(&sensorList);
if (size_t(next) >= count) {
return -1;
}
@@ -174,9 +182,10 @@
return size_t(next) < count ? next : 0;
}
-static int nativeEnableDataInjection(JNIEnv *_env, jclass _this, jboolean enable) {
- SensorManager& mgr(SensorManager::getInstance());
- return mgr.enableDataInjection(enable);
+static int nativeEnableDataInjection(JNIEnv *_env, jclass _this, jlong sensorManager,
+ jboolean enable) {
+ SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
+ return mgr->enableDataInjection(enable);
}
//----------------------------------------------------------------------------
@@ -281,12 +290,12 @@
}
};
-static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQWeak, jobject msgQ,
- jfloatArray scratch, jstring packageName, jint mode) {
- SensorManager& mgr(SensorManager::getInstance());
+static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jlong sensorManager,
+ jobject eventQWeak, jobject msgQ, jfloatArray scratch, jstring packageName, jint mode) {
+ SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
ScopedUtfChars packageUtf(env, packageName);
String8 clientName(packageUtf.c_str());
- sp<SensorEventQueue> queue(mgr.createEventQueue(clientName, mode));
+ sp<SensorEventQueue> queue(mgr->createEventQueue(clientName, mode));
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
if (messageQueue == NULL) {
@@ -339,20 +348,23 @@
{"nativeClassInit",
"()V",
(void*)nativeClassInit },
+ {"nativeCreate",
+ "(Ljava/lang/String;)J",
+ (void*)nativeCreate },
{"nativeGetNextSensor",
- "(Landroid/hardware/Sensor;I)I",
+ "(JLandroid/hardware/Sensor;I)I",
(void*)nativeGetNextSensor },
{"nativeEnableDataInjection",
- "(Z)I",
+ "(JZ)I",
(void*)nativeEnableDataInjection },
};
static JNINativeMethod gBaseEventQueueMethods[] = {
{"nativeInitBaseEventQueue",
- "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;I)J",
- (void*)nativeInitSensorEventQueue },
+ "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;ILjava/lang/String;)J",
+ (void*)nativeInitSensorEventQueue },
{"nativeEnableSensor",
"(JIII)I",
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index d4fb572..2692ad8 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -270,49 +270,10 @@
if ((strstr(name, "[heap]") == name)) {
whichHeap = HEAP_NATIVE;
- } else if (strncmp(name, "/dev/ashmem", 11) == 0) {
- if (strncmp(name, "/dev/ashmem/dalvik-", 19) == 0) {
- whichHeap = HEAP_DALVIK_OTHER;
- if (strstr(name, "/dev/ashmem/dalvik-LinearAlloc") == name) {
- subHeap = HEAP_DALVIK_LINEARALLOC;
- } else if ((strstr(name, "/dev/ashmem/dalvik-alloc space") == name) ||
- (strstr(name, "/dev/ashmem/dalvik-main space") == name)) {
- // This is the regular Dalvik heap.
- whichHeap = HEAP_DALVIK;
- subHeap = HEAP_DALVIK_NORMAL;
- } else if (strstr(name, "/dev/ashmem/dalvik-large object space") == name) {
- whichHeap = HEAP_DALVIK;
- subHeap = HEAP_DALVIK_LARGE;
- } else if (strstr(name, "/dev/ashmem/dalvik-non moving space") == name) {
- whichHeap = HEAP_DALVIK;
- subHeap = HEAP_DALVIK_NON_MOVING;
- } else if (strstr(name, "/dev/ashmem/dalvik-zygote space") == name) {
- whichHeap = HEAP_DALVIK;
- subHeap = HEAP_DALVIK_ZYGOTE;
- } else if (strstr(name, "/dev/ashmem/dalvik-indirect ref") == name) {
- subHeap = HEAP_DALVIK_INDIRECT_REFERENCE_TABLE;
- } else if (strstr(name, "/dev/ashmem/dalvik-jit-code-cache") == name) {
- subHeap = HEAP_DALVIK_CODE_CACHE;
- } else {
- subHeap = HEAP_DALVIK_ACCOUNTING; // Default to accounting.
- }
- } else if (strncmp(name, "/dev/ashmem/CursorWindow", 24) == 0) {
- whichHeap = HEAP_CURSOR;
- } else if (strncmp(name, "/dev/ashmem/libc malloc", 23) == 0) {
- whichHeap = HEAP_NATIVE;
- } else {
- whichHeap = HEAP_ASHMEM;
- }
} else if (strncmp(name, "[anon:libc_malloc]", 18) == 0) {
whichHeap = HEAP_NATIVE;
} else if (strncmp(name, "[stack", 6) == 0) {
whichHeap = HEAP_STACK;
- } else if (strncmp(name, "/dev/", 5) == 0) {
- if (strncmp(name, "/dev/kgsl-3d0", 13) == 0) {
- whichHeap = HEAP_GL_DEV;
- } else {
- whichHeap = HEAP_UNKNOWN_DEV;
- }
} else if (nameLen > 3 && strcmp(name+nameLen-3, ".so") == 0) {
whichHeap = HEAP_SO;
is_swappable = true;
@@ -325,7 +286,7 @@
} else if (nameLen > 4 && strcmp(name+nameLen-4, ".ttf") == 0) {
whichHeap = HEAP_TTF;
is_swappable = true;
- } else if ((nameLen > 4 && strcmp(name+nameLen-4, ".dex") == 0) ||
+ } else if ((nameLen > 4 && strstr(name, ".dex") != NULL) ||
(nameLen > 5 && strcmp(name+nameLen-5, ".odex") == 0)) {
whichHeap = HEAP_DEX;
is_swappable = true;
@@ -335,6 +296,45 @@
} else if (nameLen > 4 && strcmp(name+nameLen-4, ".art") == 0) {
whichHeap = HEAP_ART;
is_swappable = true;
+ } else if (strncmp(name, "/dev/", 5) == 0) {
+ if (strncmp(name, "/dev/kgsl-3d0", 13) == 0) {
+ whichHeap = HEAP_GL_DEV;
+ } else if (strncmp(name, "/dev/ashmem", 11) == 0) {
+ if (strncmp(name, "/dev/ashmem/dalvik-", 19) == 0) {
+ whichHeap = HEAP_DALVIK_OTHER;
+ if (strstr(name, "/dev/ashmem/dalvik-LinearAlloc") == name) {
+ subHeap = HEAP_DALVIK_LINEARALLOC;
+ } else if ((strstr(name, "/dev/ashmem/dalvik-alloc space") == name) ||
+ (strstr(name, "/dev/ashmem/dalvik-main space") == name)) {
+ // This is the regular Dalvik heap.
+ whichHeap = HEAP_DALVIK;
+ subHeap = HEAP_DALVIK_NORMAL;
+ } else if (strstr(name, "/dev/ashmem/dalvik-large object space") == name) {
+ whichHeap = HEAP_DALVIK;
+ subHeap = HEAP_DALVIK_LARGE;
+ } else if (strstr(name, "/dev/ashmem/dalvik-non moving space") == name) {
+ whichHeap = HEAP_DALVIK;
+ subHeap = HEAP_DALVIK_NON_MOVING;
+ } else if (strstr(name, "/dev/ashmem/dalvik-zygote space") == name) {
+ whichHeap = HEAP_DALVIK;
+ subHeap = HEAP_DALVIK_ZYGOTE;
+ } else if (strstr(name, "/dev/ashmem/dalvik-indirect ref") == name) {
+ subHeap = HEAP_DALVIK_INDIRECT_REFERENCE_TABLE;
+ } else if (strstr(name, "/dev/ashmem/dalvik-jit-code-cache") == name) {
+ subHeap = HEAP_DALVIK_CODE_CACHE;
+ } else {
+ subHeap = HEAP_DALVIK_ACCOUNTING; // Default to accounting.
+ }
+ } else if (strncmp(name, "/dev/ashmem/CursorWindow", 24) == 0) {
+ whichHeap = HEAP_CURSOR;
+ } else if (strncmp(name, "/dev/ashmem/libc malloc", 23) == 0) {
+ whichHeap = HEAP_NATIVE;
+ } else {
+ whichHeap = HEAP_ASHMEM;
+ }
+ } else {
+ whichHeap = HEAP_UNKNOWN_DEV;
+ }
} else if (strncmp(name, "[anon:", 6) == 0) {
whichHeap = HEAP_UNKNOWN;
} else if (nameLen > 0) {
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 11b3805..4ccbb41 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -21,6 +21,7 @@
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
+#include <GraphicsJNI.h>
#include <ScopedPrimitiveArray.h>
#include <EGL/egl.h>
@@ -347,10 +348,11 @@
}
static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
+ jlong proxyPtr, jlong layerPtr, jobject jbitmap) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
- SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
+ SkBitmap bitmap;
+ GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
return proxy->copyLayerInto(layer, bitmap);
}
@@ -458,7 +460,7 @@
{ "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
{ "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
{ "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
- { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
+ { "nCopyLayerInto", "(JJLandroid/graphics/Bitmap;)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
{ "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
{ "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
{ "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 52b31b2..fe5862b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7304,8 +7304,8 @@
<attr name="recognitionService" format="string" />
<attr name="settingsActivity" />
<!-- Flag indicating whether this voice interaction service is capable of handling the
- assist gesture. -->
- <attr name="supportsAssistGesture" format="boolean" />
+ assist action. -->
+ <attr name="supportsAssist" format="boolean" />
</declare-styleable>
<!-- Use <code>voice-enrollment-application</code>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cf21a1c..79b81a7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2663,7 +2663,7 @@
<public type="attr" name="autoVerify" />
<public type="attr" name="breakStrategy" />
- <public type="attr" name="supportsAssistGesture" />
+ <public type="attr" name="supportsAssist" />
<public type="attr" name="thumbPosition" />
<!-- Placeholder for a removed attribute. Remove this before M release. -->
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index dc364a12..0aa588b 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -402,12 +402,12 @@
</family>
<family>
<fileset>
- <file lang="zh-Hans">NotoSansHans-Regular.otf</file>
+ <file lang="zh-Hans">NotoSansSC-Regular.otf</file>
</fileset>
</family>
<family>
<fileset>
- <file lang="zh-Hant">NotoSansHant-Regular.otf</file>
+ <file lang="zh-Hant">NotoSansTC-Regular.otf</file>
</fileset>
</family>
<family>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 44ea1c9..f903aab 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -329,10 +329,10 @@
<font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
</family>
<family lang="zh-Hans">
- <font weight="400" style="normal">NotoSansHans-Regular.otf</font>
+ <font weight="400" style="normal">NotoSansSC-Regular.otf</font>
</family>
<family lang="zh-Hant">
- <font weight="400" style="normal">NotoSansHant-Regular.otf</font>
+ <font weight="400" style="normal">NotoSansTC-Regular.otf</font>
</family>
<family lang="ja">
<font weight="400" style="normal">NotoSansJP-Regular.otf</font>
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index f2f890e..bd74bc8 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -42,8 +42,7 @@
mBitmap = bitmap;
mTileX = tileX;
mTileY = tileY;
- final long b = bitmap.getSkBitmap();
- init(nativeCreate(b, tileX.nativeInt, tileY.nativeInt));
+ init(nativeCreate(bitmap, tileX.nativeInt, tileY.nativeInt));
}
/**
@@ -56,6 +55,6 @@
return copy;
}
- private static native long nativeCreate(long native_bitmap, int shaderTileModeX,
+ private static native long nativeCreate(Bitmap bitmap, int shaderTileModeX,
int shaderTileModeY);
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 9fe8e0c..7a1ecf7 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -81,10 +81,6 @@
*/
protected int mScreenDensity = Bitmap.DENSITY_NONE;
- // Used by native code
- @SuppressWarnings("UnusedDeclaration")
- private int mSurfaceFormat;
-
// Maximum bitmap size as defined in Skia's native code
// (see SkCanvas.cpp, SkDraw.cpp)
private static final int MAXMIMUM_BITMAP_SIZE = 32766;
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
new file mode 100644
index 0000000..47a1f77
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import android.annotation.DrawableRes;
+import android.content.ContentResolver;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.lang.IllegalArgumentException;
+import java.lang.Override;
+
+/**
+ * An umbrella container for several serializable graphics representations, including Bitmaps,
+ * compressed bitmap images (e.g. JPG or PNG), and drawable resources (including vectors).
+ *
+ * <a href="https://developer.android.com/training/displaying-bitmaps/index.html">Much ink</a>
+ * has been spilled on the best way to load images, and many clients may have different needs when
+ * it comes to threading and fetching. This class is therefore focused on encapsulation rather than
+ * behavior.
+ */
+
+public final class Icon implements Parcelable {
+ private static final String TAG = "Icon";
+
+ private static final int TYPE_BITMAP = 1;
+ private static final int TYPE_RESOURCE = 2;
+ private static final int TYPE_DATA = 3;
+ private static final int TYPE_URI = 4;
+
+ private final int mType;
+
+ // To avoid adding unnecessary overhead, we have a few basic objects that get repurposed
+ // based on the value of mType.
+
+ // TYPE_BITMAP: Bitmap
+ // TYPE_RESOURCE: Resources
+ // TYPE_DATA: DataBytes
+ private Object mObj1;
+
+ // TYPE_RESOURCE: package name
+ // TYPE_URI: uri string
+ private String mString1;
+
+ // TYPE_RESOURCE: resId
+ // TYPE_DATA: data length
+ private int mInt1;
+
+ // TYPE_DATA: data offset
+ private int mInt2;
+
+ // Internal accessors for different mType variants
+ private Bitmap getBitmap() {
+ if (mType != TYPE_BITMAP) {
+ throw new IllegalStateException("called getBitmap() on " + this);
+ }
+ return (Bitmap) mObj1;
+ }
+
+ private int getDataLength() {
+ if (mType != TYPE_DATA) {
+ throw new IllegalStateException("called getDataLength() on " + this);
+ }
+ synchronized (this) {
+ return mInt1;
+ }
+ }
+
+ private int getDataOffset() {
+ if (mType != TYPE_DATA) {
+ throw new IllegalStateException("called getDataOffset() on " + this);
+ }
+ synchronized (this) {
+ return mInt2;
+ }
+ }
+
+ private byte[] getDataBytes() {
+ if (mType != TYPE_DATA) {
+ throw new IllegalStateException("called getDataBytes() on " + this);
+ }
+ synchronized (this) {
+ return (byte[]) mObj1;
+ }
+ }
+
+ private Resources getResources() {
+ if (mType != TYPE_RESOURCE) {
+ throw new IllegalStateException("called getResources() on " + this);
+ }
+ return (Resources) mObj1;
+ }
+
+ private String getResPackage() {
+ if (mType != TYPE_RESOURCE) {
+ throw new IllegalStateException("called getResPackage() on " + this);
+ }
+ return mString1;
+ }
+
+ private int getResId() {
+ if (mType != TYPE_RESOURCE) {
+ throw new IllegalStateException("called getResId() on " + this);
+ }
+ return mInt1;
+ }
+
+ private String getUriString() {
+ if (mType != TYPE_URI) {
+ throw new IllegalStateException("called getUriString() on " + this);
+ }
+ return mString1;
+ }
+
+ private Uri getUri() {
+ return Uri.parse(getUriString());
+ }
+
+ // Convert a int32 into a four-char string
+ private static final String typeToString(int x) {
+ switch (x) {
+ case TYPE_BITMAP: return "BITMAP";
+ case TYPE_DATA: return "DATA";
+ case TYPE_RESOURCE: return "RESOURCE";
+ case TYPE_URI: return "URI";
+ default: return "UNKNOWN";
+ }
+ }
+
+ /**
+ * Invokes {@link #loadDrawable(Context)} on the given {@link android.os.Handler Handler}
+ * and then sends <code>andThen</code> to the same Handler when finished.
+ *
+ * @param context {@link android.content.Context Context} in which to load the drawable; see
+ * {@link #loadDrawable(Context)}
+ * @param andThen {@link android.os.Message} to send to its target once the drawable
+ * is available. The {@link android.os.Message#obj obj}
+ * property is populated with the Drawable.
+ */
+ public void loadDrawableAsync(Context context, Message andThen) {
+ if (andThen.getTarget() == null) {
+ throw new IllegalArgumentException("callback message must have a target handler");
+ }
+ new LoadDrawableTask(context, andThen).runAsync();
+ }
+
+ /**
+ * Invokes {@link #loadDrawable(Context)} on a background thread
+ * and then runs <code>andThen</code> on the UI thread when finished.
+ *
+ * @param context {@link android.content.Context Context} in which to load the drawable; see
+ * {@link #loadDrawable(Context)}
+ * @param handler {@link android.os.Handler} on which to run <code>andThen</code>.
+ * @param listener a callback to run on the provided
+ * Handler once the drawable is available.
+ */
+ public void loadDrawableAsync(Context context, Handler handler,
+ final OnDrawableLoadedListener listener) {
+ new LoadDrawableTask(context, handler, listener).runAsync();
+ }
+
+ /**
+ * Returns a Drawable that can be used to draw the image inside this Icon, constructing it
+ * if necessary. Depending on the type of image, this may not be something you want to do on
+ * the UI thread, so consider using
+ * {@link #loadDrawableAsync(Context, Message) loadDrawableAsync} instead.
+ *
+ * @param context {@link android.content.Context Context} in which to load the drawable; used
+ * to access {@link android.content.res.Resources Resources}, for example.
+ * @return A fresh instance of a drawable for this image, yours to keep.
+ */
+ public Drawable loadDrawable(Context context) {
+ switch (mType) {
+ case TYPE_BITMAP:
+ return new BitmapDrawable(context.getResources(), getBitmap());
+ case TYPE_RESOURCE:
+ if (getResources() == null) {
+ if (getResPackage() == null || "android".equals(getResPackage())) {
+ mObj1 = Resources.getSystem();
+ } else {
+ final PackageManager pm = context.getPackageManager();
+ try {
+ mObj1 = pm.getResourcesForApplication(getResPackage());
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG,
+ String.format("Unable to find package '%s'", getResPackage()),
+ e);
+ break;
+ }
+ }
+ }
+ return getResources().getDrawable(getResId(), context.getTheme());
+ case TYPE_DATA:
+ return new BitmapDrawable(context.getResources(),
+ BitmapFactory.decodeByteArray(getDataBytes(), getDataOffset(), getDataLength())
+ );
+ case TYPE_URI:
+ final Uri uri = getUri();
+ final String scheme = uri.getScheme();
+ InputStream is = null;
+ if (ContentResolver.SCHEME_CONTENT.equals(scheme)
+ || ContentResolver.SCHEME_FILE.equals(scheme)) {
+ try {
+ is = context.getContentResolver().openInputStream(uri);
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to load image from URI: " + uri, e);
+ }
+ } else {
+ try {
+ is = new FileInputStream(new File(mString1));
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Unable to load image from path: " + uri, e);
+ }
+ }
+ if (is != null) {
+ return new BitmapDrawable(context.getResources(),
+ BitmapFactory.decodeStream(is));
+ }
+ break;
+ }
+ return null;
+ }
+
+ private Icon(int mType) {
+ this.mType = mType;
+ }
+
+ /**
+ * Create a Icon pointing to a drawable resource.
+ * @param res Resources for a package containing the resource in question
+ * @param resid ID of the drawable resource
+ */
+ public static Icon createWithResource(Resources res, @DrawableRes int resid) {
+ final Icon rep = new Icon(TYPE_RESOURCE);
+ rep.mObj1 = res;
+ rep.mInt1 = resid;
+ rep.mString1 = res.getResourcePackageName(resid);
+ return rep;
+ }
+
+ /**
+ * Create a Icon pointing to a bitmap in memory.
+ * @param bits A valid {@link android.graphics.Bitmap} object
+ */
+ public static Icon createWithBitmap(Bitmap bits) {
+ final Icon rep = new Icon(TYPE_BITMAP);
+ rep.mObj1 = bits;
+ return rep;
+ }
+
+ /**
+ * Create a Icon pointing to a compressed bitmap stored in a byte array.
+ * @param data Byte array storing compressed bitmap data of a type that
+ * {@link android.graphics.BitmapFactory}
+ * can decode (see {@link android.graphics.Bitmap.CompressFormat}).
+ * @param offset Offset into <code>data</code> at which the bitmap data starts
+ * @param length Length of the bitmap data
+ */
+ public static Icon createWithData(byte[] data, int offset, int length) {
+ final Icon rep = new Icon(TYPE_DATA);
+ rep.mObj1 = data;
+ rep.mInt1 = length;
+ rep.mInt2 = offset;
+ return rep;
+ }
+
+ /**
+ * Create a Icon pointing to a content specified by URI.
+ *
+ * @param uri A uri referring to local content:// or file:// image data.
+ */
+ public static Icon createWithContentUri(String uri) {
+ final Icon rep = new Icon(TYPE_URI);
+ rep.mString1 = uri;
+ return rep;
+ }
+
+ /**
+ * Create a Icon pointing to a content specified by URI.
+ *
+ * @param uri A uri referring to local content:// or file:// image data.
+ */
+ public static Icon createWithContentUri(Uri uri) {
+ final Icon rep = new Icon(TYPE_URI);
+ rep.mString1 = uri.toString();
+ return rep;
+ }
+
+ /**
+ * Create a Icon pointing to
+ *
+ * @param path A path to a file that contains compressed bitmap data of
+ * a type that {@link android.graphics.BitmapFactory} can decode.
+ */
+ public static Icon createWithFilePath(String path) {
+ final Icon rep = new Icon(TYPE_URI);
+ rep.mString1 = path;
+ return rep;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("Icon(typ=").append(typeToString(mType));
+ switch (mType) {
+ case TYPE_BITMAP:
+ sb.append(" size=")
+ .append(getBitmap().getWidth())
+ .append("x")
+ .append(getBitmap().getHeight());
+ break;
+ case TYPE_RESOURCE:
+ sb.append(" pkg=")
+ .append(getResPackage())
+ .append(" id=")
+ .append(String.format("%08x", getResId()));
+ break;
+ case TYPE_DATA:
+ sb.append(" len=").append(getDataLength());
+ if (getDataOffset() != 0) {
+ sb.append(" off=").append(getDataOffset());
+ }
+ break;
+ case TYPE_URI:
+ sb.append(" uri=").append(getUriString());
+ break;
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ /**
+ * Parcelable interface
+ */
+ public int describeContents() {
+ return (mType == TYPE_BITMAP || mType == TYPE_DATA)
+ ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
+ }
+
+ // ===== Parcelable interface ======
+
+ private Icon(Parcel in) {
+ this(in.readInt());
+ switch (mType) {
+ case TYPE_BITMAP:
+ final Bitmap bits = Bitmap.CREATOR.createFromParcel(in);
+ mObj1 = bits;
+ break;
+ case TYPE_RESOURCE:
+ final String pkg = in.readString();
+ final int resId = in.readInt();
+ mString1 = pkg;
+ mInt1 = resId;
+ break;
+ case TYPE_DATA:
+ final int len = in.readInt();
+ final byte[] a = in.readBlob();
+ if (len != a.length) {
+ throw new RuntimeException("internal unparceling error: blob length ("
+ + a.length + ") != expected length (" + len + ")");
+ }
+ mInt1 = len;
+ mObj1 = a;
+ break;
+ case TYPE_URI:
+ final String uri = in.readString();
+ mString1 = uri;
+ break;
+ default:
+ throw new RuntimeException("invalid "
+ + this.getClass().getSimpleName() + " type in parcel: " + mType);
+ }
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ switch (mType) {
+ case TYPE_BITMAP:
+ final Bitmap bits = getBitmap();
+ dest.writeInt(TYPE_BITMAP);
+ getBitmap().writeToParcel(dest, flags);
+ break;
+ case TYPE_RESOURCE:
+ dest.writeInt(TYPE_RESOURCE);
+ dest.writeString(getResPackage());
+ dest.writeInt(getResId());
+ break;
+ case TYPE_DATA:
+ dest.writeInt(TYPE_DATA);
+ dest.writeInt(getDataLength());
+ dest.writeBlob(getDataBytes(), getDataOffset(), getDataLength());
+ break;
+ case TYPE_URI:
+ dest.writeInt(TYPE_URI);
+ dest.writeString(getUriString());
+ break;
+ }
+ }
+
+ public static final Parcelable.Creator<Icon> CREATOR
+ = new Parcelable.Creator<Icon>() {
+ public Icon createFromParcel(Parcel in) {
+ return new Icon(in);
+ }
+
+ public Icon[] newArray(int size) {
+ return new Icon[size];
+ }
+ };
+
+ /**
+ * Implement this interface to receive notification when
+ * {@link #loadDrawableAsync(Context, Handler, OnDrawableLoadedListener) loadDrawableAsync}
+ * is finished and your Drawable is ready.
+ */
+ public interface OnDrawableLoadedListener {
+ void onDrawableLoaded(Drawable d);
+ }
+
+ /**
+ * Wrapper around loadDrawable that does its work on a pooled thread and then
+ * fires back the given (targeted) Message.
+ */
+ private class LoadDrawableTask implements Runnable {
+ final Context mContext;
+ final Message mMessage;
+
+ public LoadDrawableTask(Context context, final Handler handler,
+ final OnDrawableLoadedListener listener) {
+ mContext = context;
+ mMessage = Message.obtain(handler, new Runnable() {
+ @Override
+ public void run() {
+ listener.onDrawableLoaded((Drawable) mMessage.obj);
+ }
+ });
+ }
+
+ public LoadDrawableTask(Context context, Message message) {
+ mContext = context;
+ mMessage = message;
+ }
+
+ @Override
+ public void run() {
+ mMessage.obj = loadDrawable(mContext);
+ mMessage.sendToTarget();
+ }
+
+ public void runAsync() {
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(this);
+ }
+ }
+}
diff --git a/graphics/tests/graphicstests/AndroidManifest.xml b/graphics/tests/graphicstests/AndroidManifest.xml
index 5fb5959..e019e28 100644
--- a/graphics/tests/graphicstests/AndroidManifest.xml
+++ b/graphics/tests/graphicstests/AndroidManifest.xml
@@ -24,6 +24,7 @@
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
diff --git a/graphics/tests/graphicstests/res/drawable-nodpi/landscape.png b/graphics/tests/graphicstests/res/drawable-nodpi/landscape.png
new file mode 100644
index 0000000..ddb3180
--- /dev/null
+++ b/graphics/tests/graphicstests/res/drawable-nodpi/landscape.png
Binary files differ
diff --git a/graphics/tests/graphicstests/src/android/graphics/drawable/IconTest.java b/graphics/tests/graphicstests/src/android/graphics/drawable/IconTest.java
new file mode 100644
index 0000000..2b9bf50
--- /dev/null
+++ b/graphics/tests/graphicstests/src/android/graphics/drawable/IconTest.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Parcel;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.lang.Override;
+import java.util.Arrays;
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+import com.android.frameworks.graphicstests.R;
+
+public class IconTest extends AndroidTestCase {
+ public static final String TAG = IconTest.class.getSimpleName();
+ public static void L(String s, Object... parts) {
+ Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts));
+ }
+
+ @SmallTest
+ public void testWithBitmap() throws Exception {
+ final Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
+ final Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
+ final Bitmap bm3 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
+ .getBitmap();
+
+ final Canvas can1 = new Canvas(bm1);
+ can1.drawColor(0xFFFF0000);
+ final Canvas can2 = new Canvas(bm2);
+ can2.drawColor(0xFF00FF00);
+
+ final Icon im1 = Icon.createWithBitmap(bm1);
+ final Icon im2 = Icon.createWithBitmap(bm2);
+ final Icon im3 = Icon.createWithBitmap(bm3);
+
+ final Drawable draw1 = im1.loadDrawable(mContext);
+ final Drawable draw2 = im2.loadDrawable(mContext);
+ final Drawable draw3 = im3.loadDrawable(mContext);
+
+ final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(),
+ draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ final Bitmap test2 = Bitmap.createBitmap(draw2.getIntrinsicWidth(),
+ draw2.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ final Bitmap test3 = Bitmap.createBitmap(draw3.getIntrinsicWidth(),
+ draw3.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+
+ draw1.setBounds(0, 0, draw1.getIntrinsicWidth(), draw1.getIntrinsicHeight());
+ draw1.draw(new Canvas(test1));
+
+ draw2.setBounds(0, 0, draw2.getIntrinsicWidth(), draw2.getIntrinsicHeight());
+ draw2.draw(new Canvas(test2));
+
+ draw3.setBounds(0, 0, draw3.getIntrinsicWidth(), draw3.getIntrinsicHeight());
+ draw3.draw(new Canvas(test3));
+
+ final File dir = getContext().getExternalFilesDir(null);
+ L("writing temp bitmaps to %s...", dir);
+
+ bm1.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(new File(dir, "bitmap1-original.png")));
+ test1.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(new File(dir, "bitmap1-test.png")));
+ if (!equalBitmaps(bm1, test1)) {
+ findBitmapDifferences(bm1, test1);
+ fail("bitmap1 differs, check " + dir);
+ }
+
+ bm2.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(new File(dir, "bitmap2-original.png")));
+ test2.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(new File(dir, "bitmap2-test.png")));
+ if (!equalBitmaps(bm2, test2)) {
+ findBitmapDifferences(bm2, test2);
+ fail("bitmap2 differs, check " + dir);
+ }
+
+ bm3.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(new File(dir, "bitmap3-original.png")));
+ test3.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(new File(dir, "bitmap3-test.png")));
+ if (!equalBitmaps(bm3, test3)) {
+ findBitmapDifferences(bm3, test3);
+ fail("bitmap3 differs, check " + dir);
+ }
+ }
+
+ @SmallTest
+ public void testWithBitmapResource() throws Exception {
+ final Bitmap res1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
+ .getBitmap();
+
+ final Icon im1 = Icon.createWithResource(getContext().getResources(),
+ R.drawable.landscape);
+ final Drawable draw1 = im1.loadDrawable(mContext);
+ final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(),
+ draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight());
+ draw1.draw(new Canvas(test1));
+
+ final File dir = getContext().getExternalFilesDir(null);
+ res1.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(new File(dir, "res1-original.png")));
+ test1.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(new File(dir, "res1-test.png")));
+ if (!equalBitmaps(res1, test1)) {
+ findBitmapDifferences(res1, test1);
+ fail("res1 differs, check " + dir);
+ }
+ }
+
+ @SmallTest
+ public void testWithFile() throws Exception {
+ final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
+ .getBitmap();
+ final File dir = getContext().getExternalFilesDir(null);
+ final File file1 = new File(dir, "file1-original.png");
+ bit1.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(file1));
+
+ final Icon im1 = Icon.createWithFilePath(file1.toString());
+ final Drawable draw1 = im1.loadDrawable(mContext);
+ final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(),
+ draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight());
+ draw1.draw(new Canvas(test1));
+
+ test1.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(new File(dir, "file1-test.png")));
+ if (!equalBitmaps(bit1, test1)) {
+ findBitmapDifferences(bit1, test1);
+ fail("testWithFile: file1 differs, check " + dir);
+ }
+ }
+
+ @SmallTest
+ public void testAsync() throws Exception {
+ final Bitmap bit1 = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
+ .getBitmap();
+ final File dir = getContext().getExternalFilesDir(null);
+ final File file1 = new File(dir, "async-original.png");
+ bit1.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(file1));
+
+ final Icon im1 = Icon.createWithFilePath(file1.toString());
+ final HandlerThread thd = new HandlerThread("testAsync");
+ thd.start();
+ final Handler h = new Handler(thd.getLooper());
+ L(TAG, "asyncTest: dispatching load to thread: " + thd);
+ im1.loadDrawableAsync(mContext, h, new Icon.OnDrawableLoadedListener() {
+ @Override
+ public void onDrawableLoaded(Drawable draw1) {
+ L(TAG, "asyncTest: thread: loading drawable");
+ L(TAG, "asyncTest: thread: loaded: %dx%d", draw1.getIntrinsicWidth(),
+ draw1.getIntrinsicHeight());
+ final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(),
+ draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight());
+ draw1.draw(new Canvas(test1));
+
+ try {
+ test1.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(new File(dir, "async-test.png")));
+ } catch (java.io.FileNotFoundException ex) {
+ fail("couldn't create test file: " + ex);
+ }
+ if (!equalBitmaps(bit1, test1)) {
+ findBitmapDifferences(bit1, test1);
+ fail("testAsync: file1 differs, check " + dir);
+ }
+ }
+ });
+ L(TAG, "asyncTest: awaiting result");
+ Thread.sleep(500); // ;_;
+ assertTrue("async-test.png does not exist!", new File(dir, "async-test.png").exists());
+ L(TAG, "asyncTest: done");
+ }
+
+ @SmallTest
+ public void testParcel() throws Exception {
+ final Bitmap originalbits = ((BitmapDrawable) getContext().getDrawable(R.drawable.landscape))
+ .getBitmap();
+
+ final ByteArrayOutputStream ostream = new ByteArrayOutputStream(
+ originalbits.getWidth() * originalbits.getHeight() * 2); // guess 50% compression
+ originalbits.compress(Bitmap.CompressFormat.PNG, 100, ostream);
+ final byte[] pngdata = ostream.toByteArray();
+
+ L("starting testParcel; bitmap: %d bytes, PNG: %d bytes",
+ originalbits.getByteCount(),
+ pngdata.length);
+
+ final File dir = getContext().getExternalFilesDir(null);
+ final File originalfile = new File(dir, "parcel-original.png");
+ new FileOutputStream(originalfile).write(pngdata);
+
+ ArrayList<Icon> imgs = new ArrayList<>();
+ final Icon file1 = Icon.createWithFilePath(originalfile.getAbsolutePath());
+ imgs.add(file1);
+ final Icon bit1 = Icon.createWithBitmap(originalbits);
+ imgs.add(bit1);
+ final Icon data1 = Icon.createWithData(pngdata, 0, pngdata.length);
+ imgs.add(data1);
+ final Icon res1 = Icon.createWithResource(getContext().getResources(), R.drawable.landscape);
+ imgs.add(res1);
+
+ ArrayList<Icon> test = new ArrayList<>();
+ final Parcel parcel = Parcel.obtain();
+ int pos = 0;
+ parcel.writeInt(imgs.size());
+ for (Icon img : imgs) {
+ img.writeToParcel(parcel, 0);
+ L("used %d bytes parceling: %s", parcel.dataPosition() - pos, img);
+ pos = parcel.dataPosition();
+ }
+
+ parcel.setDataPosition(0); // rewind
+ final int N = parcel.readInt();
+ for (int i=0; i<N; i++) {
+ Icon img = Icon.CREATOR.createFromParcel(parcel);
+ L("test %d: read from parcel: %s", i, img);
+ final File testfile = new File(dir,
+ String.format("parcel-test%02d.png", i));
+
+ final Drawable draw1 = img.loadDrawable(mContext);
+ if (draw1 == null) {
+ fail("null drawable from img: " + img);
+ }
+ final Bitmap test1 = Bitmap.createBitmap(draw1.getIntrinsicWidth(),
+ draw1.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
+ draw1.setBounds(0, 0, test1.getWidth(), test1.getHeight());
+ draw1.draw(new Canvas(test1));
+
+ try {
+ test1.compress(Bitmap.CompressFormat.PNG, 100,
+ new FileOutputStream(testfile));
+ } catch (java.io.FileNotFoundException ex) {
+ fail("couldn't create test file " + testfile + ": " + ex);
+ }
+ if (!equalBitmaps(originalbits, test1)) {
+ findBitmapDifferences(originalbits, test1);
+ fail(testfile + " differs from original: " + originalfile);
+ }
+
+ }
+ }
+
+
+ // ======== utils ========
+
+ static final char[] GRADIENT = " .:;+=xX$#".toCharArray();
+ static float[] hsv = new float[3];
+ static char colorToChar(int color) {
+ int sum = ((color >> 16) & 0xff)
+ + ((color >> 8) & 0xff)
+ + ((color) & 0xff);
+ return GRADIENT[sum * (GRADIENT.length-1) / (3*0xff)];
+ }
+ static void printBits(int[] a, int w, int h) {
+ final StringBuilder sb = new StringBuilder();
+ for (int i=0; i<w; i++) {
+ for (int j=0; j<h; j++) {
+ sb.append(colorToChar(a[i+w*j]));
+ }
+ sb.append('\n');
+ }
+ L(sb.toString());
+ }
+ static void printBits(Bitmap a) {
+ final int w = a.getWidth();
+ final int h = a.getHeight();
+ int[] aPix = new int[w * h];
+ printBits(aPix, w, h);
+ }
+ boolean equalBitmaps(Bitmap a, Bitmap b) {
+ if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) return false;
+
+ final int w = a.getWidth();
+ final int h = a.getHeight();
+ int[] aPix = new int[w * h];
+ int[] bPix = new int[w * h];
+
+ a.getPixels(aPix, 0, w, 0, 0, w, h);
+ b.getPixels(bPix, 0, w, 0, 0, w, h);
+
+ return Arrays.equals(aPix, bPix);
+ }
+
+ void findBitmapDifferences(Bitmap a, Bitmap b) {
+ if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) {
+ L("different sizes: %dx%d vs %dx%d",
+ a.getWidth(), a.getHeight(), b.getWidth(), b.getHeight());
+ return;
+ }
+
+ final int w = a.getWidth();
+ final int h = a.getHeight();
+ int[] aPix = new int[w * h];
+ int[] bPix = new int[w * h];
+
+ a.getPixels(aPix, 0, w, 0, 0, w, h);
+ b.getPixels(bPix, 0, w, 0, 0, w, h);
+
+ L("bitmap a (%dx%d)", w, h);
+ printBits(aPix, w, h);
+ L("bitmap b (%dx%d)", w, h);
+ printBits(bPix, w, h);
+
+ StringBuffer sb = new StringBuffer("Different pixels: ");
+ for (int i=0; i<w; i++) {
+ for (int j=0; j<h; j++) {
+ if (aPix[i+w*j] != bPix[i+w*j]) {
+ sb.append(" ").append(i).append(",").append(j);
+ }
+ }
+ }
+ L(sb.toString());
+ }
+}
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index cc87241..d15fa39 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -293,11 +293,11 @@
return (void*) success;
}
-bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) {
SETUP_TASK(copyLayerInto);
args->context = mContext;
args->layer = layer;
- args->bitmap = bitmap;
+ args->bitmap = &bitmap;
return (bool) postAndWait(task);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 29c6f08..cc475fa 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -83,7 +83,7 @@
ANDROID_API DeferredLayerUpdater* createTextureLayer();
ANDROID_API void buildLayer(RenderNode* node);
- ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
+ ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap);
ANDROID_API void pushLayerUpdate(DeferredLayerUpdater* layer);
ANDROID_API void cancelLayerUpdate(DeferredLayerUpdater* layer);
ANDROID_API void detachSurfaceTexture(DeferredLayerUpdater* layer);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index a33fa59..77adb39 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1953,21 +1953,16 @@
TrackInfo(Parcel in) {
mTrackType = in.readInt();
- // TODO: parcel in the full MediaFormat
+ // TODO: parcel in the full MediaFormat; currently we are using createSubtitleFormat
+ // even for audio/video tracks, meaning we only set the mime and language.
+ String mime = in.readString();
String language = in.readString();
+ mFormat = MediaFormat.createSubtitleFormat(mime, language);
- if (mTrackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
- mFormat = MediaFormat.createSubtitleFormat(
- MEDIA_MIMETYPE_TEXT_SUBRIP, language);
- } else if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
- String mime = in.readString();
- mFormat = MediaFormat.createSubtitleFormat(mime, language);
+ if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) {
mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt());
mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt());
mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt());
- } else {
- mFormat = new MediaFormat();
- mFormat.setString(MediaFormat.KEY_LANGUAGE, language);
}
}
diff --git a/media/java/android/media/MediaSync.java b/media/java/android/media/MediaSync.java
index dc6760d..ecc87e7 100644
--- a/media/java/android/media/MediaSync.java
+++ b/media/java/android/media/MediaSync.java
@@ -199,6 +199,7 @@
private final Object mAudioLock = new Object();
private AudioTrack mAudioTrack = null;
private List<AudioBuffer> mAudioBuffers = new LinkedList<AudioBuffer>();
+ // this is only used for paused/running decisions, so it is not affected by clock drift
private float mPlaybackRate = 0.0f;
private long mNativeContext;
@@ -459,36 +460,11 @@
* @throws IllegalArgumentException if the settings are not supported.
*/
public void setPlaybackSettings(@NonNull PlaybackSettings settings) {
- float rate;
- try {
- rate = settings.getSpeed();
-
- // rate is specified
- if (mAudioTrack != null) {
- try {
- if (rate == 0.0) {
- mAudioTrack.pause();
- } else {
- mAudioTrack.setPlaybackSettings(settings);
- mAudioTrack.play();
- }
- } catch (IllegalStateException e) {
- throw e;
- }
- }
-
- synchronized(mAudioLock) {
- mPlaybackRate = rate;
- }
- if (mPlaybackRate != 0.0 && mAudioThread != null) {
- postRenderAudio(0);
- }
- native_setPlaybackRate(mPlaybackRate);
- } catch (IllegalStateException e) {
- // rate is not specified; still, propagate settings to audio track
- if (mAudioTrack != null) {
- mAudioTrack.setPlaybackSettings(settings);
- }
+ synchronized(mAudioLock) {
+ mPlaybackRate = native_setPlaybackSettings(settings);;
+ }
+ if (mPlaybackRate != 0.0 && mAudioThread != null) {
+ postRenderAudio(0);
}
}
@@ -501,18 +477,9 @@
* been initialized.
*/
@NonNull
- public PlaybackSettings getPlaybackSettings() {
- if (mAudioTrack != null) {
- return mAudioTrack.getPlaybackSettings();
- } else {
- PlaybackSettings settings = new PlaybackSettings();
- settings.allowDefaults();
- settings.setSpeed(mPlaybackRate);
- return settings;
- }
- }
+ public native PlaybackSettings getPlaybackSettings();
- private native final void native_setPlaybackRate(float rate);
+ private native float native_setPlaybackSettings(@NonNull PlaybackSettings settings);
/**
* Sets A/V sync mode.
@@ -523,7 +490,16 @@
* initialized.
* @throws IllegalArgumentException if settings are not supported.
*/
- public native void setSyncSettings(@NonNull SyncSettings settings);
+ public void setSyncSettings(@NonNull SyncSettings settings) {
+ synchronized(mAudioLock) {
+ mPlaybackRate = native_setSyncSettings(settings);;
+ }
+ if (mPlaybackRate != 0.0 && mAudioThread != null) {
+ postRenderAudio(0);
+ }
+ }
+
+ private native float native_setSyncSettings(@NonNull SyncSettings settings);
/**
* Gets the A/V sync mode.
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 2c61779..5b55a61 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -174,6 +174,8 @@
} else { // Throw exception!
if ( opStatus == (status_t) INVALID_OPERATION ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ } else if ( opStatus == (status_t) BAD_VALUE ) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
} else if ( opStatus == (status_t) PERMISSION_DENIED ) {
jniThrowException(env, "java/lang/SecurityException", NULL);
} else if ( opStatus != (status_t) OK ) {
@@ -442,8 +444,33 @@
pbs.audioFallbackModeSet, pbs.audioRate.mFallbackMode,
pbs.audioStretchModeSet, pbs.audioRate.mStretchMode);
- // TODO: pass playback settings to mediaplayer when audiotrack supports it
- process_media_player_call(env, thiz, mp->setPlaybackRate(pbs.audioRate.mSpeed), NULL, NULL);
+ AudioPlaybackRate rate;
+ status_t err = mp->getPlaybackSettings(&rate);
+ if (err == OK) {
+ bool updatedRate = false;
+ if (pbs.speedSet) {
+ rate.mSpeed = pbs.audioRate.mSpeed;
+ updatedRate = true;
+ }
+ if (pbs.pitchSet) {
+ rate.mPitch = pbs.audioRate.mPitch;
+ updatedRate = true;
+ }
+ if (pbs.audioFallbackModeSet) {
+ rate.mFallbackMode = pbs.audioRate.mFallbackMode;
+ updatedRate = true;
+ }
+ if (pbs.audioStretchModeSet) {
+ rate.mStretchMode = pbs.audioRate.mStretchMode;
+ updatedRate = true;
+ }
+ if (updatedRate) {
+ err = mp->setPlaybackSettings(rate);
+ }
+ }
+ process_media_player_call(
+ env, thiz, err,
+ "java/lang/IllegalStateException", "unexpected error");
}
static jobject
@@ -457,15 +484,9 @@
PlaybackSettings pbs;
AudioPlaybackRate &audioRate = pbs.audioRate;
-
- audioRate.mSpeed = 1.0f;
- audioRate.mPitch = 1.0f;
- audioRate.mFallbackMode = AUDIO_TIMESTRETCH_FALLBACK_DEFAULT;
- audioRate.mStretchMode = AUDIO_TIMESTRETCH_STRETCH_DEFAULT;
-
- // TODO: get this from mediaplayer when audiotrack supports it
- // process_media_player_call(
- // env, thiz, mp->getPlaybackSettings(&audioRate), NULL, NULL);
+ process_media_player_call(
+ env, thiz, mp->getPlaybackSettings(&audioRate),
+ "java/lang/IllegalStateException", "unexpected error");
ALOGV("getPlaybackSettings: %f %f %d %d",
audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
@@ -489,13 +510,35 @@
SyncSettings scs;
scs.fillFromJobject(env, gSyncSettingsFields, settings);
ALOGV("setSyncSettings: %d:%d %d:%d %d:%f %d:%f",
- scs.syncSourceSet, scs.syncSource,
- scs.audioAdjustModeSet, scs.audioAdjustMode,
- scs.toleranceSet, scs.tolerance,
- scs.frameRateSet, scs.frameRate);
+ scs.syncSourceSet, scs.sync.mSource,
+ scs.audioAdjustModeSet, scs.sync.mAudioAdjustMode,
+ scs.toleranceSet, scs.sync.mTolerance,
+ scs.frameRateSet, scs.frameRate);
- // TODO: pass sync settings to mediaplayer when it supports it
- // process_media_player_call(env, thiz, mp->setSyncSettings(scs), NULL, NULL);
+ AVSyncSettings avsync;
+ float videoFrameRate;
+ status_t err = mp->getSyncSettings(&avsync, &videoFrameRate);
+ if (err == OK) {
+ bool updatedSync = scs.frameRateSet;
+ if (scs.syncSourceSet) {
+ avsync.mSource = scs.sync.mSource;
+ updatedSync = true;
+ }
+ if (scs.audioAdjustModeSet) {
+ avsync.mAudioAdjustMode = scs.sync.mAudioAdjustMode;
+ updatedSync = true;
+ }
+ if (scs.toleranceSet) {
+ avsync.mTolerance = scs.sync.mTolerance;
+ updatedSync = true;
+ }
+ if (updatedSync) {
+ err = mp->setSyncSettings(avsync, scs.frameRateSet ? scs.frameRate : -1.f);
+ }
+ }
+ process_media_player_call(
+ env, thiz, err,
+ "java/lang/IllegalStateException", "unexpected error");
}
static jobject
@@ -508,21 +551,27 @@
}
SyncSettings scs;
- scs.syncSource = 0; // SYNC_SOURCE_DEFAULT
- scs.audioAdjustMode = 0; // AUDIO_ADJUST_MODE_DEFAULT
- scs.tolerance = 0.f;
- scs.frameRate = 0.f;
+ scs.frameRate = -1.f;
+ process_media_player_call(
+ env, thiz, mp->getSyncSettings(&scs.sync, &scs.frameRate),
+ "java/lang/IllegalStateException", "unexpected error");
- // TODO: get this from mediaplayer when it supports it
- // process_media_player_call(
- // env, thiz, mp->getSyncSettings(&scs), NULL, NULL);
ALOGV("getSyncSettings: %d %d %f %f",
- scs.syncSource, scs.audioAdjustMode, scs.tolerance, scs.frameRate);
+ scs.sync.mSource, scs.sync.mAudioAdjustMode, scs.sync.mTolerance, scs.frameRate);
+
+ // sanity check settings
+ if (scs.sync.mSource >= AVSYNC_SOURCE_MAX
+ || scs.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
+ || scs.sync.mTolerance < 0.f
+ || scs.sync.mTolerance >= AVSYNC_TOLERANCE_MAX) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
scs.syncSourceSet = true;
scs.audioAdjustModeSet = true;
scs.toleranceSet = true;
- scs.frameRateSet = false;
+ scs.frameRateSet = scs.frameRate >= 0.f;
return scs.asJobject(env, gSyncSettingsFields);
}
diff --git a/media/jni/android_media_MediaSync.cpp b/media/jni/android_media_MediaSync.cpp
index f192262..8ad4b71 100644
--- a/media/jni/android_media_MediaSync.cpp
+++ b/media/jni/android_media_MediaSync.cpp
@@ -21,6 +21,7 @@
#include "android_media_MediaSync.h"
#include "android_media_AudioTrack.h"
+#include "android_media_PlaybackSettings.h"
#include "android_media_SyncSettings.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/android_view_Surface.h"
@@ -29,6 +30,7 @@
#include <gui/Surface.h>
+#include <media/AudioResamplerPublic.h>
#include <media/AudioTrack.h>
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MediaSync.h>
@@ -47,6 +49,7 @@
};
static fields_t gFields;
+static PlaybackSettings::fields_t gPlaybackSettingsFields;
static SyncSettings::fields_t gSyncSettingsFields;
////////////////////////////////////////////////////////////////////////////////
@@ -62,10 +65,8 @@
return mSync->configureSurface(bufferProducer);
}
-status_t JMediaSync::configureAudioTrack(
- const sp<AudioTrack> &audioTrack,
- int32_t nativeSampleRateInHz) {
- return mSync->configureAudioTrack(audioTrack, nativeSampleRateInHz);
+status_t JMediaSync::configureAudioTrack(const sp<AudioTrack> &audioTrack) {
+ return mSync->configureAudioTrack(audioTrack);
}
status_t JMediaSync::createInputSurface(
@@ -73,14 +74,34 @@
return mSync->createInputSurface(bufferProducer);
}
-status_t JMediaSync::setPlaybackRate(float rate) {
- return mSync->setPlaybackRate(rate);
-}
-
sp<const MediaClock> JMediaSync::getMediaClock() {
return mSync->getMediaClock();
}
+status_t JMediaSync::setPlaybackSettings(const AudioPlaybackRate& rate) {
+ return mSync->setPlaybackSettings(rate);
+}
+
+void JMediaSync::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) {
+ mSync->getPlaybackSettings(rate);
+}
+
+status_t JMediaSync::setSyncSettings(const AVSyncSettings& syncSettings) {
+ return mSync->setSyncSettings(syncSettings);
+}
+
+void JMediaSync::getSyncSettings(AVSyncSettings* syncSettings /* nonnull */) {
+ mSync->getSyncSettings(syncSettings);
+}
+
+status_t JMediaSync::setVideoFrameRateHint(float rate) {
+ return mSync->setVideoFrameRateHint(rate);
+}
+
+float JMediaSync::getVideoFrameRate() {
+ return mSync->getVideoFrameRate();
+}
+
status_t JMediaSync::updateQueuedAudioData(
int sizeInBytes, int64_t presentationTimeUs) {
return mSync->updateQueuedAudioData(sizeInBytes, presentationTimeUs);
@@ -176,7 +197,7 @@
}
static void android_media_MediaSync_native_configureAudioTrack(
- JNIEnv *env, jobject thiz, jobject jaudioTrack, jint nativeSampleRateInHz) {
+ JNIEnv *env, jobject thiz, jobject jaudioTrack) {
ALOGV("android_media_MediaSync_configureAudioTrack");
sp<JMediaSync> sync = getMediaSync(env, thiz);
@@ -194,7 +215,7 @@
}
}
- status_t err = sync->configureAudioTrack(audioTrack, nativeSampleRateInHz);
+ status_t err = sync->configureAudioTrack(audioTrack);
if (err == INVALID_OPERATION) {
throwExceptionAsNecessary(
@@ -287,29 +308,132 @@
return (jlong)playTimeUs;
}
-static void
-android_media_MediaSync_setSyncSettings(JNIEnv *env, jobject thiz, jobject settings)
-{
+static jfloat android_media_MediaSync_setPlaybackSettings(
+ JNIEnv *env, jobject thiz, jobject settings) {
sp<JMediaSync> sync = getMediaSync(env, thiz);
if (sync == NULL) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
- return;
+ return (jfloat)0.f;
+ }
+
+ PlaybackSettings pbs;
+ pbs.fillFromJobject(env, gPlaybackSettingsFields, settings);
+ ALOGV("setPlaybackSettings: %d:%f %d:%f %d:%u %d:%u",
+ pbs.speedSet, pbs.audioRate.mSpeed,
+ pbs.pitchSet, pbs.audioRate.mPitch,
+ pbs.audioFallbackModeSet, pbs.audioRate.mFallbackMode,
+ pbs.audioStretchModeSet, pbs.audioRate.mStretchMode);
+
+ AudioPlaybackRate rate;
+ sync->getPlaybackSettings(&rate);
+ bool updatedRate = false;
+ if (pbs.speedSet) {
+ rate.mSpeed = pbs.audioRate.mSpeed;
+ updatedRate = true;
+ }
+ if (pbs.pitchSet) {
+ rate.mPitch = pbs.audioRate.mPitch;
+ updatedRate = true;
+ }
+ if (pbs.audioFallbackModeSet) {
+ rate.mFallbackMode = pbs.audioRate.mFallbackMode;
+ updatedRate = true;
+ }
+ if (pbs.audioStretchModeSet) {
+ rate.mStretchMode = pbs.audioRate.mStretchMode;
+ updatedRate = true;
+ }
+ if (updatedRate) {
+ status_t err = sync->setPlaybackSettings(rate);
+ if (err != OK) {
+ throwExceptionAsNecessary(env, err);
+ return (jfloat)0.f;
+ }
+ }
+
+ sp<const MediaClock> mediaClock = sync->getMediaClock();
+ if (mediaClock == NULL) {
+ return (jfloat)0.f;
+ }
+
+ return (jfloat)mediaClock->getPlaybackRate();
+}
+
+static jobject android_media_MediaSync_getPlaybackSettings(
+ JNIEnv *env, jobject thiz) {
+ sp<JMediaSync> sync = getMediaSync(env, thiz);
+ if (sync == NULL) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return NULL;
+ }
+
+ PlaybackSettings pbs;
+ AudioPlaybackRate &audioRate = pbs.audioRate;
+ sync->getPlaybackSettings(&audioRate);
+ ALOGV("getPlaybackSettings: %f %f %d %d",
+ audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
+
+ pbs.speedSet = true;
+ pbs.pitchSet = true;
+ pbs.audioFallbackModeSet = true;
+ pbs.audioStretchModeSet = true;
+
+ return pbs.asJobject(env, gPlaybackSettingsFields);
+}
+
+static jfloat android_media_MediaSync_setSyncSettings(
+ JNIEnv *env, jobject thiz, jobject settings) {
+ sp<JMediaSync> sync = getMediaSync(env, thiz);
+ if (sync == NULL) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return (jfloat)0.f;
}
SyncSettings scs;
scs.fillFromJobject(env, gSyncSettingsFields, settings);
ALOGV("setSyncSettings: %d:%d %d:%d %d:%f %d:%f",
- scs.syncSourceSet, scs.syncSource,
- scs.audioAdjustModeSet, scs.audioAdjustMode,
- scs.toleranceSet, scs.tolerance,
+ scs.syncSourceSet, scs.sync.mSource,
+ scs.audioAdjustModeSet, scs.sync.mAudioAdjustMode,
+ scs.toleranceSet, scs.sync.mTolerance,
scs.frameRateSet, scs.frameRate);
- // TODO: pass sync settings to mediasync when it supports it
+ AVSyncSettings avsync;
+ sync->getSyncSettings(&avsync);
+ bool updatedSync = false;
+ status_t err = OK;
+ if (scs.syncSourceSet) {
+ avsync.mSource = scs.sync.mSource;
+ updatedSync = true;
+ }
+ if (scs.audioAdjustModeSet) {
+ avsync.mAudioAdjustMode = scs.sync.mAudioAdjustMode;
+ updatedSync = true;
+ }
+ if (scs.toleranceSet) {
+ avsync.mTolerance = scs.sync.mTolerance;
+ updatedSync = true;
+ }
+ if (updatedSync) {
+ err = sync->setSyncSettings(avsync);
+ }
+
+ if (scs.frameRateSet && err == OK) {
+ err = sync->setVideoFrameRateHint(scs.frameRate);
+ }
+ if (err != OK) {
+ throwExceptionAsNecessary(env, err);
+ return (jfloat)0.f;
+ }
+
+ sp<const MediaClock> mediaClock = sync->getMediaClock();
+ if (mediaClock == NULL) {
+ return (jfloat)0.f;
+ }
+
+ return (jfloat)mediaClock->getPlaybackRate();
}
-static jobject
-android_media_MediaSync_getSyncSettings(JNIEnv *env, jobject thiz)
-{
+static jobject android_media_MediaSync_getSyncSettings(JNIEnv *env, jobject thiz) {
sp<JMediaSync> sync = getMediaSync(env, thiz);
if (sync == NULL) {
throwExceptionAsNecessary(env, INVALID_OPERATION);
@@ -317,21 +441,25 @@
}
SyncSettings scs;
- scs.syncSource = 0; // SYNC_SOURCE_DEFAULT
- scs.audioAdjustMode = 0; // AUDIO_ADJUST_MODE_DEFAULT
- scs.tolerance = 0.f;
- scs.frameRate = 0.f;
+ sync->getSyncSettings(&scs.sync);
+ scs.frameRate = sync->getVideoFrameRate();
- // TODO: get this from mediaplayer when it supports it
- // process_media_player_call(
- // env, thiz, mp->getSyncSettings(&scs), NULL, NULL);
ALOGV("getSyncSettings: %d %d %f %f",
- scs.syncSource, scs.audioAdjustMode, scs.tolerance, scs.frameRate);
+ scs.sync.mSource, scs.sync.mAudioAdjustMode, scs.sync.mTolerance, scs.frameRate);
+
+ // sanity check settings
+ if (scs.sync.mSource >= AVSYNC_SOURCE_MAX
+ || scs.sync.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX
+ || scs.sync.mTolerance < 0.f
+ || scs.sync.mTolerance >= AVSYNC_TOLERANCE_MAX) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return NULL;
+ }
scs.syncSourceSet = true;
scs.audioAdjustModeSet = true;
scs.toleranceSet = true;
- scs.frameRateSet = false;
+ scs.frameRateSet = scs.frameRate >= 0.f;
return scs.asJobject(env, gSyncSettingsFields);
}
@@ -359,6 +487,7 @@
CHECK(gFields.mediaTimestampClockRateID != NULL);
gSyncSettingsFields.init(env);
+ gPlaybackSettingsFields.init(env);
}
static void android_media_MediaSync_native_setup(JNIEnv *env, jobject thiz) {
@@ -367,21 +496,6 @@
setMediaSync(env, thiz, sync);
}
-static void android_media_MediaSync_native_setPlaybackRate(
- JNIEnv *env, jobject thiz, jfloat rate) {
- sp<JMediaSync> sync = getMediaSync(env, thiz);
- if (sync == NULL) {
- throwExceptionAsNecessary(env, INVALID_OPERATION);
- return;
- }
-
- status_t err = sync->setPlaybackRate(rate);
- if (err != NO_ERROR) {
- throwExceptionAsNecessary(env, err);
- return;
- }
-}
-
static void android_media_MediaSync_native_finalize(JNIEnv *env, jobject thiz) {
android_media_MediaSync_release(env, thiz);
}
@@ -416,11 +530,17 @@
{ "native_release", "()V", (void *)android_media_MediaSync_release },
- { "native_setPlaybackRate", "(F)V", (void *)android_media_MediaSync_native_setPlaybackRate },
+ { "native_setPlaybackSettings", "(Landroid/media/PlaybackSettings;)F",
+ (void *)android_media_MediaSync_setPlaybackSettings },
- { "setSyncSettings", "(Landroid/media/SyncSettings;)V", (void *)android_media_MediaSync_setSyncSettings},
+ { "getPlaybackSettings", "()Landroid/media/PlaybackSettings;",
+ (void *)android_media_MediaSync_getPlaybackSettings },
- { "getSyncSettings", "()Landroid/media/SyncSettings;", (void *)android_media_MediaSync_getSyncSettings},
+ { "native_setSyncSettings", "(Landroid/media/SyncSettings;)F",
+ (void *)android_media_MediaSync_setSyncSettings },
+
+ { "getSyncSettings", "()Landroid/media/SyncSettings;",
+ (void *)android_media_MediaSync_getSyncSettings },
{ "native_finalize", "()V", (void *)android_media_MediaSync_native_finalize },
};
diff --git a/media/jni/android_media_MediaSync.h b/media/jni/android_media_MediaSync.h
index cf81a72..80f5d63 100644
--- a/media/jni/android_media_MediaSync.h
+++ b/media/jni/android_media_MediaSync.h
@@ -18,11 +18,13 @@
#define _ANDROID_MEDIA_MEDIASYNC_H_
#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaSync.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
namespace android {
+struct AudioPlaybackRate;
class AudioTrack;
struct IGraphicBufferProducer;
struct MediaClock;
@@ -32,17 +34,21 @@
JMediaSync();
status_t configureSurface(const sp<IGraphicBufferProducer> &bufferProducer);
- status_t configureAudioTrack(
- const sp<AudioTrack> &audioTrack, int32_t nativeSampleRateInHz);
+ status_t configureAudioTrack(const sp<AudioTrack> &audioTrack);
status_t createInputSurface(sp<IGraphicBufferProducer>* bufferProducer);
status_t updateQueuedAudioData(int sizeInBytes, int64_t presentationTimeUs);
- status_t setPlaybackRate(float rate);
-
status_t getPlayTimeForPendingAudioFrames(int64_t *outTimeUs);
+ status_t setPlaybackSettings(const AudioPlaybackRate& rate);
+ void getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */);
+ status_t setSyncSettings(const AVSyncSettings& syncSettings);
+ void getSyncSettings(AVSyncSettings* syncSettings /* nonnull */);
+ status_t setVideoFrameRateHint(float rate);
+ float getVideoFrameRate();
+
sp<const MediaClock> getMediaClock();
protected:
diff --git a/media/jni/android_media_SyncSettings.cpp b/media/jni/android_media_SyncSettings.cpp
index 2f0605e..5da35e7 100644
--- a/media/jni/android_media_SyncSettings.cpp
+++ b/media/jni/android_media_SyncSettings.cpp
@@ -57,9 +57,9 @@
}
void SyncSettings::fillFromJobject(JNIEnv *env, const fields_t& fields, jobject settings) {
- syncSource = env->GetIntField(settings, fields.sync_source);
- audioAdjustMode = env->GetIntField(settings, fields.audio_adjust_mode);
- tolerance = env->GetFloatField(settings, fields.tolerance);
+ sync.mSource = (AVSyncSource)env->GetIntField(settings, fields.sync_source);
+ sync.mAudioAdjustMode = (AVSyncAudioAdjustMode)env->GetIntField(settings, fields.audio_adjust_mode);
+ sync.mTolerance = env->GetFloatField(settings, fields.tolerance);
frameRate = env->GetFloatField(settings, fields.frame_rate);
int set = env->GetIntField(settings, fields.set);
@@ -74,9 +74,9 @@
if (settings == NULL) {
return NULL;
}
- env->SetIntField(settings, fields.sync_source, (jint)syncSource);
- env->SetIntField(settings, fields.audio_adjust_mode, (jint)audioAdjustMode);
- env->SetFloatField(settings, fields.tolerance, (jfloat)tolerance);
+ env->SetIntField(settings, fields.sync_source, (jint)sync.mSource);
+ env->SetIntField(settings, fields.audio_adjust_mode, (jint)sync.mAudioAdjustMode);
+ env->SetFloatField(settings, fields.tolerance, (jfloat)sync.mTolerance);
env->SetFloatField(settings, fields.frame_rate, (jfloat)frameRate);
env->SetIntField(
settings, fields.set,
diff --git a/media/jni/android_media_SyncSettings.h b/media/jni/android_media_SyncSettings.h
index 586533f..23530db 100644
--- a/media/jni/android_media_SyncSettings.h
+++ b/media/jni/android_media_SyncSettings.h
@@ -19,13 +19,12 @@
#include "jni.h"
+#include <media/stagefright/MediaSync.h>
+
namespace android {
struct SyncSettings {
- // keep this here until it is implemented
- int syncSource;
- int audioAdjustMode;
- float tolerance;
+ AVSyncSettings sync;
float frameRate;
bool syncSourceSet;
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 73b52aa..4e7c6be 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -38,11 +38,6 @@
/*****************************************************************************/
-ASensorManager* ASensorManager_getInstance()
-{
- return &SensorManager::getInstance();
-}
-
int ASensorManager_getSensorList(ASensorManager* manager,
ASensorList* list)
{
diff --git a/packages/IntentFilterVerifier/Android.mk b/packages/IntentFilterVerifier/Android.mk
deleted file mode 100644
index 99feda5..0000000
--- a/packages/IntentFilterVerifier/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# Build the IntentFilterVerifier.
-include $(CLEAR_VARS)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- volley \
-
-LOCAL_JAVA_LIBRARIES += org.apache.http.legacy
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := IntentFilterVerifier
-
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_PROGUARD_FLAGS := $(proguard.flags)
-
-include $(BUILD_PACKAGE)
-
-# Build the test package.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/IntentFilterVerifier/AndroidManifest.xml b/packages/IntentFilterVerifier/AndroidManifest.xml
deleted file mode 100644
index 3829cc5..0000000
--- a/packages/IntentFilterVerifier/AndroidManifest.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.verifier.intentfilter"
- coreApp="true">
- <uses-permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
-
- <application
- android:label="@string/service_name"
- android:allowBackup="false">
-
- <receiver
- android:name="com.android.verifier.intentfilter.IntentVerificationReceiver"
- android:permission="android.permission.BIND_INTENT_FILTER_VERIFIER" >
- <intent-filter
- android:priority="-1" >
- <action android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION" />
- <data android:mimeType="application/vnd.android.package-archive" />
- </intent-filter>
- </receiver>
-
- <service android:name=".IntentVerificationService"
- android:label="@string/service_name"
- android:exported="false"/>
-
- </application>
-
-</manifest>
diff --git a/packages/IntentFilterVerifier/CleanSpec.mk b/packages/IntentFilterVerifier/CleanSpec.mk
deleted file mode 100644
index e4575ae..0000000
--- a/packages/IntentFilterVerifier/CleanSpec.mk
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# If you don't need to do a full clean build but would like to touch
-# a file or delete some intermediate files, add a clean step to the end
-# of the list. These steps will only be run once, if they haven't been
-# run before.
-#
-# E.g.:
-# $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
-# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
-#
-# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
-# files that are missing or have been moved.
-#
-# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
-# Use $(OUT_DIR) to refer to the "out" directory.
-#
-# If you need to re-do something that's already mentioned, just copy
-# the command and add it to the bottom of the list. E.g., if a change
-# that you made last week required touching a file and a change you
-# made today requires touching the same file, just copy the old
-# touch step and add it to the end of the list.
-#
-# *****************************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER
-# *****************************************************************
-
-# For example:
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
-#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
-#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
-#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
-
-# ******************************************************************
-# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
-# ******************************************************************
diff --git a/packages/IntentFilterVerifier/proguard.flags b/packages/IntentFilterVerifier/proguard.flags
deleted file mode 100644
index 6e4bec3..0000000
--- a/packages/IntentFilterVerifier/proguard.flags
+++ /dev/null
@@ -1 +0,0 @@
--verbose
\ No newline at end of file
diff --git a/packages/IntentFilterVerifier/res/values/strings.xml b/packages/IntentFilterVerifier/res/values/strings.xml
deleted file mode 100644
index 22f3cd5..0000000
--- a/packages/IntentFilterVerifier/res/values/strings.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Package name shown to users when they look at installed applications
- and running processes. This service verifies packages that are
- requested to be installed. [CHAR LIMIT=50] -->
- <string name="service_name">Basic Intent Filter Verification Service</string>
-
-</resources>
diff --git a/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationReceiver.java b/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationReceiver.java
deleted file mode 100644
index de25f8c..0000000
--- a/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationReceiver.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.verifier.intentfilter;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.os.Bundle;
-import android.util.Log;
-import android.util.Slog;
-
-import java.util.Arrays;
-import java.util.List;
-
-public class IntentVerificationReceiver extends BroadcastReceiver {
- static final String TAG = IntentVerificationReceiver.class.getName();
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION.equals(action)) {
- Bundle extras = intent.getExtras();
- if (extras != null) {
- int verificationId = extras.getInt(
- PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID);
- String hosts = extras.getString(
- PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS);
-
- Log.d(TAG, "Received IntentFilter verification broadcast with verificationId: "
- + verificationId);
-
- if (canDoVerification(context)) {
- Intent serviceIntent = new Intent(context, IntentVerificationService.class);
- serviceIntent.fillIn(intent, 0);
- serviceIntent.putExtras(intent.getExtras());
-
- Slog.d(TAG, "Starting Intent Verification Service.");
-
- context.startService(serviceIntent);
- } else {
- sendVerificationFailure(context, verificationId, hosts);
- }
- }
-
- } else {
- Log.w(TAG, "Unexpected action: " + action);
- }
- }
-
- private void sendVerificationFailure(Context context, int verificationId, String hosts) {
- List<String> list = Arrays.asList(hosts.split(" "));
- context.getPackageManager().verifyIntentFilter(
- verificationId, PackageManager.INTENT_FILTER_VERIFICATION_FAILURE, list);
-
- Log.d(TAG, "No network! Failing IntentFilter verification with verificationId: " +
- verificationId + " and hosts: " + hosts);
- }
-
- private boolean canDoVerification(Context context) {
- return hasNetwork(context);
- }
-
- public boolean hasNetwork(Context context) {
- ConnectivityManager cm =
- (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- if (cm != null) {
- NetworkInfo info = cm.getActiveNetworkInfo();
- return (info != null) && info.isConnected();
- } else {
- return false;
- }
- }
-}
diff --git a/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationRequest.java b/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationRequest.java
deleted file mode 100644
index 8f9c86f..0000000
--- a/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationRequest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.verifier.intentfilter;
-
-import com.android.volley.Response;
-import com.android.volley.toolbox.JsonArrayRequest;
-import org.json.JSONArray;
-
-public class IntentVerificationRequest extends JsonArrayRequest {
-
- public IntentVerificationRequest(String url, Response.Listener<JSONArray> listener,
- Response.ErrorListener errorListener) {
- super(url, listener, errorListener);
- }
-}
diff --git a/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationService.java b/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationService.java
deleted file mode 100644
index 3e4db6c..0000000
--- a/packages/IntentFilterVerifier/src/com/android/verifier/intentfilter/IntentVerificationService.java
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.verifier.intentfilter;
-
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.Signature;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Slog;
-import com.android.volley.RequestQueue;
-import com.android.volley.Response;
-import com.android.volley.VolleyError;
-import com.android.volley.toolbox.Volley;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
-
-public class IntentVerificationService extends Service {
- private static final String TAG = "IntentVerificationService";
-
- private static final String WELL_KNOWN_ASSOCIATIONS_JSON = "/.well-known/associations.json";
- private static final String DEFAULT_SCHEME = "https";
-
- private static final String JSON_KEY_TARGET = "target";
- private static final String JSON_KEY_NAMESPACE = "namespace";
- private static final String JSON_KEY_PACKAGE_NAME = "package_name";
- private static final String JSON_KEY_CERT_FINGERPRINTS = "sha256_cert_fingerprints";
-
- private static final String JSON_VAL_ANDROID_APP = "android_app";
-
- private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'A', 'B', 'C', 'D', 'E', 'F' };
-
- private ConnectivityManager mConnectivityManager;
- private Looper mHandlerLooper;
- private VerificationHandler mHandler;
- private RequestQueue mRequestQueue;
-
- private static class VerificationState {
- public final int verificationId;
- public final String hosts;
- public final String packageName;
- public final Set<String> fingerprints;
- public int responseCode = PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS;
- public int counter;
- public int numberOfHosts;
- public ArrayList<String> failedHosts = new ArrayList<>();
-
- private final Object lock = new Object();
-
- public VerificationState(int id, String h, String p, Set<String> fps) {
- verificationId = id;
- hosts = h;
- packageName = p;
- fingerprints = fps;
- numberOfHosts = hosts.split(" ").length;
- }
- public boolean setResponseCodeAndCheckMax(int code) {
- synchronized (lock) {
- if (code == PackageManager.INTENT_FILTER_VERIFICATION_FAILURE) {
- responseCode = code;
- counter++;
- } else if (code == PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS) {
- counter++;
- }
- return (counter == numberOfHosts);
- }
- }
-
- public void addFailedHost(String host) {
- synchronized (failedHosts) {
- failedHosts.add(host);
- }
- }
-
- public ArrayList<String> getFailedHosts() {
- return failedHosts;
- }
- }
-
- private HashMap<Integer, VerificationState> mVerificationMap =
- new HashMap<Integer, VerificationState>();
-
- private class VerificationHandler extends Handler {
- private static final int MSG_STOP_SERVICE = 0;
- private static final int MSG_VERIFY_INTENT_START = 1;
- private static final int MSG_VERIFY_INTENT_DONE = 2;
-
- private static final long SHUTDOWN_DELAY_MILLIS = 8 * 1000;
-
- private final Context mContext;
-
- public VerificationHandler(Context context, Looper looper) {
- super(looper);
-
- mContext = context;
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_VERIFY_INTENT_START:
- final Intent intent = (Intent) msg.obj;
- Bundle extras = intent.getExtras();
- boolean immediate = false;
-
- if (extras != null) {
- immediate = doVerification(extras);
- }
-
- // There was no network, so we can stop soon
- if (immediate) {
- stopDelayed();
- }
- break;
-
- case MSG_VERIFY_INTENT_DONE:
- VerificationState vs = (VerificationState) msg.obj;
- processVerificationDone(mContext, vs);
- clearVerificationState(vs);
- break;
-
- case MSG_STOP_SERVICE:
- stopSelf();
- break;
-
- default:
- Slog.i(TAG, "Unknown message posted " + msg.toString());
- break;
-
- }
- }
-
- private void stopDelayed() {
- removeMessages(MSG_STOP_SERVICE);
- sendEmptyMessageDelayed(MSG_STOP_SERVICE, SHUTDOWN_DELAY_MILLIS);
- }
- }
-
- private VerificationState getVerificationState(int id, String hosts, String packageName,
- Set<String> fingerprints) {
- synchronized (mVerificationMap) {
- VerificationState vs = mVerificationMap.get(id);
- if (vs == null) {
- vs = new VerificationState(id, hosts, packageName, fingerprints);
- }
- return vs;
- }
- }
-
- private void clearVerificationState(VerificationState vs) {
- mVerificationMap.remove(vs);
- }
-
- private boolean doVerification(Bundle extras) {
- String scheme = extras.getString(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_URI_SCHEME);
- if (TextUtils.isEmpty(scheme)) {
- scheme = DEFAULT_SCHEME;
- }
-
- int verificationId = extras.getInt(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID);
- String hosts = extras.getString(PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS);
- String packageName = extras.getString(
- PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME);
-
- Set<String> fingerprints = getFingerprints(packageName);
-
- Log.d(TAG, "Received IntentFilter verification broadcast with verificationId:" +
- verificationId + " hosts:'" + hosts + "' scheme:" + scheme);
-
- VerificationState vs = getVerificationState(verificationId, hosts, packageName,
- fingerprints);
-
- if (hasNetwork()) {
- sendNetworkVerifications(scheme, vs);
- return false;
- }
-
- // No network, so fail immediately
- sendFailureResponseIfNeeded(vs);
-
- return true;
- }
-
- private Set<String> getFingerprints(String packageName) {
- Context context = getApplicationContext();
- try {
- Signature[] signatures = context.getPackageManager().getPackageInfo(packageName,
- PackageManager.GET_SIGNATURES).signatures;
- if (signatures.length > 0) {
- HashSet<String> result = new HashSet<String>();
- for (Signature sig : signatures) {
- String fingerprint = computeNormalizedSha256Fingerprint(sig.toByteArray());
- result.add(fingerprint);
- }
- return result;
- }
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Cannot get signatures for package name: " + packageName);
- }
- return Collections.EMPTY_SET;
- }
-
- private static String computeNormalizedSha256Fingerprint(byte[] signature) {
- MessageDigest digester;
- try {
- digester = MessageDigest.getInstance("SHA-256");
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError("No SHA-256 implementation found.");
- }
- digester.update(signature);
- return byteArrayToHexString(digester.digest());
- }
-
- private static String byteArrayToHexString(byte[] array) {
- if (array.length == 0) {
- return "";
- }
- char[] buf = new char[array.length * 3 - 1];
-
- int bufIndex = 0;
- for (int i = 0; i < array.length; i++) {
- byte b = array[i];
- if (i > 0) {
- buf[bufIndex++] = ':';
- }
- buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
- buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
- }
- return new String(buf);
- }
-
- private static String getAssociationPath() {
- return WELL_KNOWN_ASSOCIATIONS_JSON;
- }
-
- private void sendNetworkVerifications(String scheme, final VerificationState vs) {
- final int verificationId = vs.verificationId;
- final String hosts = vs.hosts;
-
- String[] array = hosts.split(" ");
- for (final String host : array) {
- try {
- final URL url = new URL(scheme, host, getAssociationPath());
- final String urlStr = url.toString();
- Log.d(TAG, "Using verification URL: " + urlStr);
- IntentVerificationRequest req = new IntentVerificationRequest(urlStr,
- new Response.Listener<JSONArray>() {
- @Override
- public void onResponse(JSONArray response) {
- Log.d(TAG, "From: " + urlStr + " received response: "
- + response.toString());
- handleResponse(vs, host, response);
- }
- }, new Response.ErrorListener() {
- @Override
- public void onErrorResponse(VolleyError error) {
- Slog.d(TAG, "From: " + urlStr + " got error: " + error.getMessage()
- + (error.networkResponse != null ? " with status code: "
- + error.networkResponse.statusCode : ""));
- handleError(vs, host);
- }
- }
- );
- mRequestQueue.add(req);
- } catch (MalformedURLException e) {
- Log.w(TAG, "Cannot send verificationId: " + verificationId + " to host: " + host);
- }
- }
- }
-
- private void handleError(VerificationState vs, String host) {
- vs.addFailedHost(host);
- sendFailureResponseIfNeeded(vs);
- }
-
- private void handleResponse(VerificationState vs, String host, JSONArray response) {
- try {
- if (response.length() == 0) {
- Log.d(TAG, "Domain response is empty!");
- handleError(vs, host);
- return;
- }
-
- JSONObject firstRelation = (JSONObject) response.get(0);
- if (firstRelation == null) {
- Log.d(TAG, "Domain response is should have a relation!");
- handleError(vs, host);
- return;
- }
-
- JSONObject target = (JSONObject) firstRelation.get(JSON_KEY_TARGET);
- if (target == null) {
- Log.d(TAG, "Domain response target is empty!");
- handleError(vs, host);
- return;
- }
-
- String nameSpace = target.getString(JSON_KEY_NAMESPACE);
- if (TextUtils.isEmpty(nameSpace) || !nameSpace.equals(JSON_VAL_ANDROID_APP)) {
- Log.d(TAG, "Domain response target name space is not valid: " + nameSpace);
- handleError(vs, host);
- return;
- }
-
- String packageName = target.getString(JSON_KEY_PACKAGE_NAME);
- JSONArray certFingerprints = target.getJSONArray(JSON_KEY_CERT_FINGERPRINTS);
-
- // Early exits is the JSON response is not correct for the package name or signature
- if (TextUtils.isEmpty(packageName)) {
- Log.d(TAG, "Domain response has empty package name!");
- handleError(vs, host);
- return;
- }
- if (certFingerprints.length() == 0) {
- Log.d(TAG, "Domain response has empty cert signature!");
- handleError(vs, host);
- return;
- }
- // Now do the real test on package name and signature
- if (!packageName.equalsIgnoreCase(vs.packageName)) {
- Log.d(TAG, "Domain response has package name mismatch!" + packageName +
- " vs " + vs.packageName);
- handleError(vs, host);
- return;
- }
- final int count = certFingerprints.length();
- for (int i = 0; i < count; i++) {
- String fingerprint = certFingerprints.getString(i);
- if (!vs.fingerprints.contains(fingerprint)) {
- Log.d(TAG, "Domain response has cert fingerprint mismatch! " +
- "The domain fingerprint '" + fingerprint + "' is not from the App");
- handleError(vs, host);
- return;
- }
- }
- sendSuccessResponseIfNeeded(vs);
- } catch (JSONException e) {
- Log.d(TAG, "Domain response is not well formed", e);
- handleError(vs, host);
- }
- }
-
- private void sendSuccessResponseIfNeeded(VerificationState vs) {
- if (vs.setResponseCodeAndCheckMax(PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS)) {
- sendMessage(vs);
- }
- }
-
- private void sendFailureResponseIfNeeded(VerificationState vs) {
- if (vs.setResponseCodeAndCheckMax(PackageManager.INTENT_FILTER_VERIFICATION_FAILURE)) {
- sendMessage(vs);
- }
- }
-
- private void sendMessage(VerificationState vs) {
- Message msg = mHandler.obtainMessage(VerificationHandler.MSG_VERIFY_INTENT_DONE);
- msg.obj = vs;
- mHandler.sendMessage(msg);
- }
-
- private void processVerificationDone(Context context, VerificationState state) {
- int verificationId = state.verificationId;
- String hosts = state.hosts;
- int responseCode = state.responseCode;
-
- final PackageManager pm = context.getPackageManager();
-
- // Callback the PackageManager
- pm.verifyIntentFilter(verificationId, responseCode, state.getFailedHosts());
- Log.d(TAG, "IntentFilter with verificationId: " + verificationId + " and hosts: " +
- hosts + " got verification code: " + responseCode);
- }
-
- /**
- * We only connect to this service from the same process.
- */
- public class LocalBinder extends Binder {
- IntentVerificationService getService() { return IntentVerificationService.this; }
- }
-
- private final IBinder mBinder = new LocalBinder();
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- Slog.i(TAG, "Received start id " + startId + ": " + intent);
-
- final Message msg = mHandler.obtainMessage(VerificationHandler.MSG_VERIFY_INTENT_START);
- msg.obj = intent;
- mHandler.sendMessage(msg);
-
- return START_STICKY;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- Slog.d(TAG, "Starting up...");
-
- final HandlerThread handlerThread = new HandlerThread("IntentVerificationService");
- handlerThread.start();
- mHandlerLooper = handlerThread.getLooper();
-
- mHandler = new VerificationHandler(getApplicationContext(), mHandlerLooper);
-
- mRequestQueue = Volley.newRequestQueue(this);
- mRequestQueue.start();
-
- mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- Slog.d(TAG, "Shutting down...");
-
- mHandlerLooper.quit();
- mRequestQueue.stop();
- }
-
- private boolean hasNetwork() {
- NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
- return (info != null) && info.isConnected();
- }
-}
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a0ef5e2..b0b78f2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -16,9 +16,6 @@
*/
-->
<resources>
- <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
- <dimen name="status_bar_edge_ignore">5dp</dimen>
-
<!-- Recent Applications parameters -->
<!-- Upper width limit for application icon -->
<dimen name="status_bar_recents_app_icon_max_width">48dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f3a2912..00b8df2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -400,6 +400,8 @@
<string name="accessibility_recents_all_items_dismissed">All recent applications dismissed.</string>
<!-- Content description to tell the user an application has been launched from recents -->
<string name="accessibility_recents_item_launched">Starting <xliff:g id="app" example="Calendar">%s</xliff:g>.</string>
+ <!-- Content description of individual recents task. -->
+ <string name="accessibility_recents_task_header"><xliff:g id="app" example="Chrome">%1$s</xliff:g> <xliff:g id="activity_label" example="www.google.com">%2$s</xliff:g></string>
<!-- Content description to tell the user a notification has been removed from the notification shade -->
<string name="accessibility_notification_dismissed">Notification dismissed.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistGestureManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistGestureManager.java
index 36be355..d9f2324 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistGestureManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistGestureManager.java
@@ -196,7 +196,7 @@
private boolean getVoiceInteractorSupportsAssistGesture() {
try {
- return mVoiceInteractionManagerService.activeServiceSupportsAssistGesture();
+ return mVoiceInteractionManagerService.activeServiceSupportsAssist();
} catch (RemoteException e) {
Log.w(TAG, "Failed to call activeServiceSupportsAssistGesture", e);
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index d60df9c..e3fb16a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -438,6 +438,33 @@
return info.loadLabel(mPm).toString();
}
+ /** Returns the application label */
+ public String getApplicationLabel(Intent baseIntent, int userId) {
+ if (mPm == null) return null;
+
+ // If we are mocking, then return a mock label
+ if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
+ return "Recent Task";
+ }
+
+ ResolveInfo ri = mPm.resolveActivityAsUser(baseIntent, 0, userId);
+ CharSequence label = (ri != null) ? ri.loadLabel(mPm) : null;
+ return (label != null) ? label.toString() : null;
+ }
+
+ /** Returns the content description for a given task */
+ public String getContentDescription(Intent baseIntent, int userId, String activityLabel,
+ Resources res) {
+ String applicationLabel = getApplicationLabel(baseIntent, userId);
+ if (applicationLabel == null) {
+ return getBadgedLabel(activityLabel, userId);
+ }
+ String badgedApplicationLabel = getBadgedLabel(applicationLabel, userId);
+ return applicationLabel.equals(activityLabel) ? badgedApplicationLabel
+ : res.getString(R.string.accessibility_recents_task_header,
+ badgedApplicationLabel, activityLabel);
+ }
+
/**
* Returns the activity icon for the ActivityInfo for a user, badging if
* necessary.
@@ -464,6 +491,16 @@
return icon;
}
+ /**
+ * Returns the given label for a user, badging if necessary.
+ */
+ public String getBadgedLabel(String label, int userId) {
+ if (userId != UserHandle.myUserId()) {
+ label = mPm.getUserBadgedLabel(label, new UserHandle(userId)).toString();
+ }
+ return label;
+ }
+
/** Returns the package name of the home activity. */
public String getHomeActivityPackageName() {
if (mPm == null) return null;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 5d98dda..40cd211 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -130,6 +130,8 @@
// Load the label, icon, and color
String activityLabel = loader.getAndUpdateActivityLabel(taskKey, t.taskDescription,
mSystemServicesProxy, infoHandle);
+ String contentDescription = loader.getAndUpdateContentDescription(taskKey,
+ activityLabel, mSystemServicesProxy, res);
Drawable activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription,
mSystemServicesProxy, res, infoHandle, false);
int activityColor = loader.getActivityPrimaryColor(t.taskDescription, mConfig);
@@ -148,9 +150,9 @@
// Add the task to the stack
Task task = new Task(taskKey, (t.id != RecentsTaskLoader.INVALID_TASK_ID),
- t.affiliatedTaskId, t.affiliatedTaskColor, activityLabel, activityIcon,
- activityColor, (i == (taskCount - 1)), mConfig.lockToAppEnabled, icon,
- iconFilename);
+ t.affiliatedTaskId, t.affiliatedTaskColor, activityLabel, contentDescription,
+ activityIcon, activityColor, (i == (taskCount - 1)), mConfig.lockToAppEnabled,
+ icon, iconFilename);
task.thumbnail = loader.getAndUpdateThumbnail(taskKey, mSystemServicesProxy, false);
if (DEBUG) Log.d(TAG, "\tthumbnail: " + taskKey + ", " + task.thumbnail);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 3192fe6..b2aa2b6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -259,6 +259,7 @@
DrawableLruCache mApplicationIconCache;
BitmapLruCache mThumbnailCache;
StringLruCache mActivityLabelCache;
+ StringLruCache mContentDescriptionCache;
TaskResourceLoadQueue mLoadQueue;
TaskResourceLoader mLoader;
@@ -298,6 +299,7 @@
mApplicationIconCache = new DrawableLruCache(iconCacheSize);
mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
mActivityLabelCache = new StringLruCache(100);
+ mContentDescriptionCache = new StringLruCache(100);
mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,
mDefaultThumbnail, mDefaultApplicationIcon);
}
@@ -348,6 +350,24 @@
return label;
}
+ /** Returns the content description using as many cached values as we can. */
+ public String getAndUpdateContentDescription(Task.TaskKey taskKey, String activityLabel,
+ SystemServicesProxy ssp, Resources res) {
+ // Return the cached content description if it exists
+ String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey);
+ if (label != null) {
+ return label;
+ }
+ label = ssp.getContentDescription(taskKey.baseIntent, taskKey.userId, activityLabel, res);
+ if (label != null) {
+ mContentDescriptionCache.put(taskKey, label);
+ } else {
+ Log.w(TAG, "Missing content description for " + taskKey.baseIntent.getComponent()
+ + " u=" + taskKey.userId);
+ }
+ return label;
+ }
+
/** Returns the activity icon using as many cached values as we can. */
public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey,
ActivityManager.TaskDescription td, SystemServicesProxy ssp,
@@ -541,6 +561,7 @@
mApplicationIconCache.evictAll();
// The cache is small, only clear the label cache when we are critical
mActivityLabelCache.evictAll();
+ mContentDescriptionCache.evictAll();
break;
default:
break;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 0cd55d7..c14adf4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -124,6 +124,7 @@
public boolean isLaunchTarget;
public Drawable applicationIcon;
public Drawable activityIcon;
+ public String contentDescription;
public String activityLabel;
public int colorPrimary;
public boolean useLightOnPrimaryColor;
@@ -140,8 +141,8 @@
}
public Task(TaskKey key, boolean isActive, int taskAffiliation, int taskAffiliationColor,
- String activityTitle, Drawable activityIcon, int colorPrimary,
- boolean lockToThisTask, boolean lockToTaskEnabled, Bitmap icon,
+ String activityTitle, String contentDescription, Drawable activityIcon,
+ int colorPrimary, boolean lockToThisTask, boolean lockToTaskEnabled, Bitmap icon,
String iconFilename) {
boolean isInAffiliationGroup = (taskAffiliation != key.id);
boolean hasAffiliationGroupColor = isInAffiliationGroup && (taskAffiliationColor != 0);
@@ -149,6 +150,7 @@
this.taskAffiliation = taskAffiliation;
this.taskAffiliationColor = taskAffiliationColor;
this.activityLabel = activityTitle;
+ this.contentDescription = contentDescription;
this.activityIcon = activityIcon;
this.colorPrimary = hasAffiliationGroupColor ? taskAffiliationColor : colorPrimary;
this.useLightOnPrimaryColor = Utilities.computeContrastBetweenColors(this.colorPrimary,
@@ -166,6 +168,7 @@
this.taskAffiliation = o.taskAffiliation;
this.taskAffiliationColor = o.taskAffiliationColor;
this.activityLabel = o.activityLabel;
+ this.contentDescription = o.contentDescription;
this.activityIcon = o.activityIcon;
this.colorPrimary = o.colorPrimary;
this.useLightOnPrimaryColor = o.useLightOnPrimaryColor;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 60a91bf..f397bc3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -190,10 +190,12 @@
} else if (t.applicationIcon != null) {
mApplicationIcon.setImageDrawable(t.applicationIcon);
}
- mApplicationIcon.setContentDescription(t.activityLabel);
+ mApplicationIcon.setContentDescription(t.contentDescription);
if (!mActivityDescription.getText().toString().equals(t.activityLabel)) {
mActivityDescription.setText(t.activityLabel);
}
+ mActivityDescription.setContentDescription(t.contentDescription);
+
// Try and apply the system ui tint
int existingBgColor = getBackgroundColor();
if (existingBgColor != t.colorPrimary) {
@@ -207,7 +209,7 @@
mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
mLightDismissDrawable : mDarkDismissDrawable);
mDismissButton.setContentDescription(String.format(mDismissContentDescription,
- t.activityLabel));
+ t.contentDescription));
mMoveTaskButton.setVisibility((mConfig.multiStackEnabled) ? View.VISIBLE : View.INVISIBLE);
if (mConfig.multiStackEnabled) {
updateResizeTaskBarIcon(t);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 9a6a80e..1c46d42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -91,6 +91,7 @@
import android.widget.ImageView;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.keyguard.ViewMediatorCallback;
@@ -297,7 +298,6 @@
int mTrackingPosition; // the position of the top of the tracking view.
// Tracking finger for opening/closing.
- int mEdgeBorder; // corresponds to R.dimen.status_bar_edge_ignore
boolean mTracking;
VelocityTracker mVelocityTracker;
@@ -691,6 +691,7 @@
mDismissView.setOnButtonClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+ MetricsLogger.action(mContext, MetricsLogger.ACTION_DISMISS_ALL_NOTES);
clearAllNotifications();
}
});
@@ -724,8 +725,6 @@
R.id.keyguard_indication_text));
mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController);
- mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
// set the inital view visibility
setAreThereNotifications();
@@ -2818,8 +2817,6 @@
mNaturalBarHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
- mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore);
-
mRowMinHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
mRowMaxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
index 149c0be..5e28d3f 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBLAS.java
@@ -1288,7 +1288,7 @@
} else {
K = A.getType().getX();
}
- mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, A.getID(mRS), B.getID(mRS), beta, C.getID(mRS), 0, 0, 0, 0);
+ mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dsyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha, A.getID(mRS), B.getID(mRS), beta, C.getID(mRS), 0, 0, 0, 0);
}
public void CSYR2K(@Uplo int Uplo, @Transpose int Trans, Float2 alpha, Allocation A, Allocation B, Float2 beta, Allocation C) {
validateUplo(Uplo);
@@ -1299,7 +1299,7 @@
} else {
K = A.getType().getX();
}
- mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
+ mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_csyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
}
public void ZSYR2K(@Uplo int Uplo, @Transpose int Trans, Double2 alpha, Allocation A, Allocation B, Double2 beta, Allocation C) {
validateUplo(Uplo);
@@ -1310,7 +1310,7 @@
} else {
K = A.getType().getX();
}
- mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ssyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
+ mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_zsyr2k, Trans, 0, 0, Uplo, 0, 0, C.getType().getX(), K, alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), beta.x, beta.y, C.getID(mRS), 0, 0, 0, 0);
}
static void validateTRMM(Element e, @Side int Side, @Transpose int TransA, Allocation A, Allocation B) {
@@ -1351,21 +1351,21 @@
validateUplo(Uplo);
validateDiag(Diag);
validateTRMM(Element.F64(mRS), Side, TransA, A, B);
- mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
- alpha, A.getID(mRS), B.getID(mRS), 0.f, 0, 0, 0, 0, 0);
+ mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+ alpha, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0);
}
public void CTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
validateUplo(Uplo);
validateDiag(Diag);
validateTRMM(Element.F32_2(mRS), Side, TransA, A, B);
- mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+ mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
}
public void ZTRMM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
validateUplo(Uplo);
validateDiag(Diag);
validateTRMM(Element.F64_2(mRS), Side, TransA, A, B);
- mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_strmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+ mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrmm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
}
@@ -1409,21 +1409,21 @@
validateUplo(Uplo);
validateDiag(Diag);
validateTRSM(Element.F64(mRS), Side, TransA, A, B);
- mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+ mRS.nScriptIntrinsicBLAS_Double(getID(mRS), RsBlas_dtrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
alpha, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0);
}
public void CTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Float2 alpha, Allocation A, Allocation B) {
validateUplo(Uplo);
validateDiag(Diag);
validateTRSM(Element.F32_2(mRS), Side, TransA, A, B);
- mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+ mRS.nScriptIntrinsicBLAS_Complex(getID(mRS), RsBlas_ctrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
}
public void ZTRSM(@Side int Side, @Uplo int Uplo, @Transpose int TransA, @Diag int Diag, Double2 alpha, Allocation A, Allocation B) {
validateUplo(Uplo);
validateDiag(Diag);
validateTRSM(Element.F64_2(mRS), Side, TransA, A, B);
- mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_strsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
+ mRS.nScriptIntrinsicBLAS_Z(getID(mRS), RsBlas_ztrsm, TransA, 0, Side, Uplo, Diag, B.getType().getY(), B.getType().getX(), 0,
alpha.x, alpha.y, A.getID(mRS), B.getID(mRS), 0, 0, 0, 0, 0, 0, 0);
}
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 17c7e0c..78cbac9 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -63,6 +63,7 @@
import android.util.AttributeSet;
import android.util.Pair;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.util.Xml;
@@ -171,6 +172,8 @@
private final SparseIntArray mLoadedUserIds = new SparseIntArray();
+ private final SparseArray<ArraySet<String>> mWidgetPackages = new SparseArray<>();
+
private final BackupRestoreController mBackupRestoreController;
private final Context mContext;
@@ -572,7 +575,7 @@
widget.host = host;
host.widgets.add(widget);
- mWidgets.add(widget);
+ addWidgetLocked(widget);
saveGroupStateAsync(userId);
@@ -800,6 +803,8 @@
widget.provider = provider;
widget.options = (options != null) ? cloneIfLocalBinder(options) : new Bundle();
+ onWidgetProviderAddedOrChangedLocked(widget);
+
// We need to provide a default value for the widget category if it is not specified
if (!widget.options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) {
widget.options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
@@ -1410,7 +1415,7 @@
host.widgets.remove(widget);
pruneHostLocked(host);
- mWidgets.remove(widget);
+ removeWidgetLocked(widget);
Provider provider = widget.provider;
if (provider != null) {
@@ -1874,7 +1879,7 @@
updateAppWidgetInstanceLocked(widget, null, false);
// clear out references to this appWidgetId
widget.host.widgets.remove(widget);
- mWidgets.remove(widget);
+ removeWidgetLocked(widget);
widget.provider = null;
pruneHostLocked(widget.host);
widget.host = null;
@@ -2277,14 +2282,14 @@
if (version >= 0) {
// Hooke'm up...
- bindLoadedWidgets(loadedWidgets);
+ bindLoadedWidgetsLocked(loadedWidgets);
// upgrade the database if needed
performUpgradeLocked(version);
} else {
// failed reading, clean up
Slog.w(TAG, "Failed to read state, clearing widgets and hosts.");
- mWidgets.clear();
+ clearWidgetsLocked();
mHosts.clear();
final int N = mProviders.size();
for (int i = 0; i < N; i++) {
@@ -2293,7 +2298,7 @@
}
}
- private void bindLoadedWidgets(List<LoadedWidgetState> loadedWidgets) {
+ private void bindLoadedWidgetsLocked(List<LoadedWidgetState> loadedWidgets) {
final int loadedWidgetCount = loadedWidgets.size();
for (int i = loadedWidgetCount - 1; i >= 0; i--) {
LoadedWidgetState loadedWidget = loadedWidgets.remove(i);
@@ -2314,7 +2319,7 @@
widget.provider.widgets.add(widget);
widget.host.widgets.add(widget);
- mWidgets.add(widget);
+ addWidgetLocked(widget);
}
}
@@ -2346,6 +2351,91 @@
return null;
}
+ /**
+ * Adds the widget to mWidgets and tracks the package name in mWidgetPackages.
+ */
+ void addWidgetLocked(Widget widget) {
+ mWidgets.add(widget);
+
+ onWidgetProviderAddedOrChangedLocked(widget);
+ }
+
+ /**
+ * Checks if the provider is assigned and updates the mWidgetPackages to track packages
+ * that have bound widgets.
+ */
+ void onWidgetProviderAddedOrChangedLocked(Widget widget) {
+ if (widget.provider == null) return;
+
+ int userId = widget.provider.getUserId();
+ ArraySet<String> packages = mWidgetPackages.get(userId);
+ if (packages == null) {
+ mWidgetPackages.put(userId, packages = new ArraySet<String>());
+ }
+ packages.add(widget.provider.info.provider.getPackageName());
+ }
+
+ /**
+ * Removes a widget from mWidgets and updates the cache of bound widget provider packages.
+ * If there are other widgets with the same package, leaves it in the cache, otherwise it
+ * removes the associated package from the cache.
+ */
+ void removeWidgetLocked(Widget widget) {
+ mWidgets.remove(widget);
+
+ onWidgetRemovedLocked(widget);
+ }
+
+ private void onWidgetRemovedLocked(Widget widget) {
+ if (widget.provider == null) return;
+
+ final int userId = widget.provider.getUserId();
+ final String packageName = widget.provider.info.provider.getPackageName();
+ ArraySet<String> packages = mWidgetPackages.get(userId);
+ if (packages == null) {
+ return;
+ }
+ // Check if there is any other widget with the same package name.
+ // Remove packageName if none.
+ final int N = mWidgets.size();
+ for (int i = 0; i < N; i++) {
+ Widget w = mWidgets.get(i);
+ if (w.provider == null) continue;
+ if (w.provider.getUserId() == userId
+ && packageName.equals(w.provider.info.provider.getPackageName())) {
+ return;
+ }
+ }
+ packages.remove(packageName);
+ }
+
+ /**
+ * Clears all widgets and associated cache of packages with bound widgets.
+ */
+ void clearWidgetsLocked() {
+ mWidgets.clear();
+
+ onWidgetsClearedLocked();
+ }
+
+ private void onWidgetsClearedLocked() {
+ mWidgetPackages.clear();
+ }
+
+ @Override
+ public boolean isBoundWidgetPackage(String packageName, int userId) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Only the system process can call this");
+ }
+ synchronized (mLock) {
+ final ArraySet<String> packages = mWidgetPackages.get(userId);
+ if (packages != null) {
+ return packages.contains(packageName);
+ }
+ }
+ return false;
+ }
+
private void saveStateLocked(int userId) {
tagProvidersAndHosts();
@@ -2692,7 +2782,7 @@
// as we do not want to make host callbacks and provider broadcasts
// as the host and the provider will be killed.
if (hostInUser && (!hasProvider || providerInUser)) {
- mWidgets.remove(i);
+ removeWidgetLocked(widget);
widget.host.widgets.remove(widget);
widget.host = null;
if (hasProvider) {
@@ -3751,7 +3841,7 @@
Slog.i(TAG, "New restored id " + restoredId
+ " now " + id);
}
- mWidgets.add(id);
+ addWidgetLocked(id);
}
if (id.provider.info != null) {
stashProviderRestoreUpdateLocked(id.provider,
@@ -4013,7 +4103,7 @@
host.widgets.remove(widget);
provider.widgets.remove(widget);
unbindAppWidgetRemoteViewsServicesLocked(widget);
- mWidgets.remove(i);
+ removeWidgetLocked(widget);
}
}
mPrunedApps.add(pkg);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 17b4939..1366149 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -744,6 +744,11 @@
}
}
+ @Override
+ public int permissionToOpCode(String permission) {
+ return AppOpsManager.permissionToOpCode(permission);
+ }
+
void finishOperationLocked(Op op) {
if (op.nesting <= 1) {
if (op.nesting == 1) {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index ef82bb7..1019faa 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -48,6 +48,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
import java.io.FileDescriptor;
@@ -443,6 +444,16 @@
/** Internal death rec list */
Map<IBinder, ClientDeathRecipient> mBleApps = new HashMap<IBinder, ClientDeathRecipient>();
+ @Override
+ public boolean isBleScanAlwaysAvailable() {
+ try {
+ return (Settings.Global.getInt(mContentResolver,
+ Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE)) != 0;
+ } catch (SettingNotFoundException e) {
+ }
+ return false;
+ }
+
public int updateBleAppCount(IBinder token, boolean enable) {
if (enable) {
ClientDeathRecipient r = mBleApps.get(token);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 069878e..eea6234 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -47,6 +47,7 @@
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
+import android.content.pm.PermissionInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Point;
@@ -6619,6 +6620,18 @@
return mActivityManagerService.mContext.getPackageManager()
.getPackagesForUid(uid);
}
+
+ @Override
+ public boolean isRuntimePermission(String permission) {
+ try {
+ PermissionInfo info = mActivityManagerService.mContext.getPackageManager()
+ .getPermissionInfo(permission, 0);
+ return info.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS;
+ } catch (NameNotFoundException nnfe) {
+ Slog.e(TAG, "No such permission: "+ permission, nnfe);
+ }
+ return false;
+ }
}
class IntentFirewallInterface implements IntentFirewall.AMSInterface {
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 0f3b4e6..fb98d94 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -264,9 +264,9 @@
return mInstaller.execute(builder.toString());
}
- public int moveUserDataDirs(String fromUuid, String toUuid, String packageName, int appId,
- String seinfo) {
- StringBuilder builder = new StringBuilder("mvuserdata");
+ public int moveCompleteApp(String fromUuid, String toUuid, String packageName,
+ String dataAppName, int appId, String seinfo) {
+ StringBuilder builder = new StringBuilder("mvcompleteapp");
builder.append(' ');
builder.append(escapeNull(fromUuid));
builder.append(' ');
@@ -274,6 +274,8 @@
builder.append(' ');
builder.append(packageName);
builder.append(' ');
+ builder.append(dataAppName);
+ builder.append(' ');
builder.append(appId);
builder.append(' ');
builder.append(seinfo);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 11ab042..66dd8f1 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -171,6 +171,7 @@
import android.util.ExceptionUtils;
import android.util.Log;
import android.util.LogPrinter;
+import android.util.MathUtils;
import android.util.PrintStreamPrinter;
import android.util.Slog;
import android.util.SparseArray;
@@ -241,6 +242,8 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -2158,6 +2161,8 @@
mSettings.mFingerprint = Build.FINGERPRINT;
}
+ primeDomainVerificationsLPw(false);
+
// All the changes are done during package scanning.
mSettings.updateInternalDatabaseVersion();
@@ -2175,8 +2180,6 @@
mIntentFilterVerifier = new IntentVerifierProxy(mContext,
mIntentFilterVerifierComponent);
- primeDomainVerificationsLPw(false);
-
} // synchronized (mPackages)
} // synchronized (mInstallLock)
@@ -2274,9 +2277,9 @@
}
private void primeDomainVerificationsLPw(boolean logging) {
- Slog.d(TAG, "Start priming domain verification");
+ Slog.d(TAG, "Start priming domain verifications");
boolean updated = false;
- ArrayList<String> allHosts = new ArrayList<>();
+ ArraySet<String> allHostsSet = new ArraySet<>();
for (PackageParser.Package pkg : mPackages.values()) {
final String packageName = pkg.packageName;
if (!hasDomainURLs(pkg)) {
@@ -2296,18 +2299,20 @@
for (PackageParser.Activity a : pkg.activities) {
for (ActivityIntentInfo filter : a.intents) {
if (hasValidDomains(filter, false)) {
- allHosts.addAll(filter.getHostsList());
+ allHostsSet.addAll(filter.getHostsList());
}
}
}
- if (allHosts.size() == 0) {
- allHosts.add("*");
+ if (allHostsSet.size() == 0) {
+ allHostsSet.add("*");
}
+ ArrayList<String> allHostsList = new ArrayList<>(allHostsSet);
IntentFilterVerificationInfo ivi =
- mSettings.createIntentFilterVerificationIfNeededLPw(packageName, allHosts);
+ mSettings.createIntentFilterVerificationIfNeededLPw(packageName, allHostsList);
if (ivi != null) {
// We will always log this
- Slog.d(TAG, "Priming domain verifications for package: " + packageName);
+ Slog.d(TAG, "Priming domain verifications for package: " + packageName +
+ " with hosts:" + ivi.getDomainsString());
ivi.setStatus(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS);
updated = true;
}
@@ -2316,12 +2321,14 @@
Slog.d(TAG, "No priming domain verifications for package: " + packageName);
}
}
- allHosts.clear();
+ allHostsSet.clear();
}
if (updated) {
- scheduleWriteSettingsLocked();
+ if (logging) {
+ Slog.d(TAG, "Will need to write primed domain verifications");
+ }
}
- Slog.d(TAG, "End priming domain verification");
+ Slog.d(TAG, "End priming domain verifications");
}
@Override
@@ -5049,8 +5056,7 @@
+ " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
- ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
- getAppDexInstructionSets(ps));
+ ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
@@ -5116,8 +5122,7 @@
+ " reverting from " + ps.codePathString + ": new version "
+ pkg.mVersionCode + " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
- ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
- getAppDexInstructionSets(ps));
+ ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
synchronized (mInstallLock) {
args.cleanUpResourcesLI();
}
@@ -8499,46 +8504,53 @@
}
};
- static final void sendPackageBroadcast(String action, String pkg,
- Bundle extras, String targetPkg, IIntentReceiver finishedReceiver,
- int[] userIds) {
- IActivityManager am = ActivityManagerNative.getDefault();
- if (am != null) {
- try {
- if (userIds == null) {
- userIds = am.getRunningUserIds();
+ final void sendPackageBroadcast(final String action, final String pkg,
+ final Bundle extras, final String targetPkg, final IIntentReceiver finishedReceiver,
+ final int[] userIds) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ final IActivityManager am = ActivityManagerNative.getDefault();
+ if (am == null) return;
+ final int[] resolvedUserIds;
+ if (userIds == null) {
+ resolvedUserIds = am.getRunningUserIds();
+ } else {
+ resolvedUserIds = userIds;
+ }
+ for (int id : resolvedUserIds) {
+ final Intent intent = new Intent(action,
+ pkg != null ? Uri.fromParts("package", pkg, null) : null);
+ if (extras != null) {
+ intent.putExtras(extras);
+ }
+ if (targetPkg != null) {
+ intent.setPackage(targetPkg);
+ }
+ // Modify the UID when posting to other users
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (uid > 0 && UserHandle.getUserId(uid) != id) {
+ uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
+ intent.putExtra(Intent.EXTRA_UID, uid);
+ }
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ if (DEBUG_BROADCASTS) {
+ RuntimeException here = new RuntimeException("here");
+ here.fillInStackTrace();
+ Slog.d(TAG, "Sending to user " + id + ": "
+ + intent.toShortString(false, true, false, false)
+ + " " + intent.getExtras(), here);
+ }
+ am.broadcastIntent(null, intent, null, finishedReceiver,
+ 0, null, null, null, android.app.AppOpsManager.OP_NONE,
+ finishedReceiver != null, false, id);
+ }
+ } catch (RemoteException ex) {
}
- for (int id : userIds) {
- final Intent intent = new Intent(action,
- pkg != null ? Uri.fromParts("package", pkg, null) : null);
- if (extras != null) {
- intent.putExtras(extras);
- }
- if (targetPkg != null) {
- intent.setPackage(targetPkg);
- }
- // Modify the UID when posting to other users
- int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- if (uid > 0 && UserHandle.getUserId(uid) != id) {
- uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
- intent.putExtra(Intent.EXTRA_UID, uid);
- }
- intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- if (DEBUG_BROADCASTS) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.d(TAG, "Sending to user " + id + ": "
- + intent.toShortString(false, true, false, false)
- + " " + intent.getExtras(), here);
- }
- am.broadcastIntent(null, intent, null, finishedReceiver,
- 0, null, null, null, android.app.AppOpsManager.OP_NONE,
- finishedReceiver != null, false, id);
- }
- } catch (RemoteException ex) {
}
- }
+ });
}
/**
@@ -8665,8 +8677,8 @@
final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
final Message msg = mHandler.obtainMessage(INIT_COPY);
- msg.obj = new InstallParams(origin, observer, installFlags,
- installerPackageName, null, verificationParams, user, packageAbiOverride);
+ msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
+ null, verificationParams, user, packageAbiOverride);
mHandler.sendMessage(msg);
}
@@ -8684,7 +8696,7 @@
}
final Message msg = mHandler.obtainMessage(INIT_COPY);
- msg.obj = new InstallParams(origin, observer, params.installFlags,
+ msg.obj = new InstallParams(origin, null, observer, params.installFlags,
installerPackageName, params.volumeUuid, verifParams, user, params.abiOverride);
mHandler.sendMessage(msg);
}
@@ -9517,8 +9529,30 @@
}
}
+ class MoveInfo {
+ final int moveId;
+ final String fromUuid;
+ final String toUuid;
+ final String packageName;
+ final String dataAppName;
+ final int appId;
+ final String seinfo;
+
+ public MoveInfo(int moveId, String fromUuid, String toUuid, String packageName,
+ String dataAppName, int appId, String seinfo) {
+ this.moveId = moveId;
+ this.fromUuid = fromUuid;
+ this.toUuid = toUuid;
+ this.packageName = packageName;
+ this.dataAppName = dataAppName;
+ this.appId = appId;
+ this.seinfo = seinfo;
+ }
+ }
+
class InstallParams extends HandlerParams {
final OriginInfo origin;
+ final MoveInfo move;
final IPackageInstallObserver2 observer;
int installFlags;
final String installerPackageName;
@@ -9528,11 +9562,12 @@
private int mRet;
final String packageAbiOverride;
- InstallParams(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags,
- String installerPackageName, String volumeUuid,
+ InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
+ int installFlags, String installerPackageName, String volumeUuid,
VerificationParams verificationParams, UserHandle user, String packageAbiOverride) {
super(user);
this.origin = origin;
+ this.move = move;
this.observer = observer;
this.installFlags = installFlags;
this.installerPackageName = installerPackageName;
@@ -9911,7 +9946,9 @@
}
private InstallArgs createInstallArgs(InstallParams params) {
- if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
+ if (params.move != null) {
+ return new MoveInstallArgs(params);
+ } else if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
return new AsecInstallArgs(params);
} else {
return new FileInstallArgs(params);
@@ -9923,7 +9960,7 @@
* when cleaning up old installs, or used as a move source.
*/
private InstallArgs createInstallArgsForExisting(int installFlags, String codePath,
- String resourcePath, String nativeLibraryRoot, String[] instructionSets) {
+ String resourcePath, String[] instructionSets) {
final boolean isInAsec;
if (installOnExternalAsec(installFlags)) {
/* Apps on SD card are always in ASEC containers. */
@@ -9943,14 +9980,15 @@
return new AsecInstallArgs(codePath, instructionSets,
installOnExternalAsec(installFlags), installForwardLocked(installFlags));
} else {
- return new FileInstallArgs(codePath, resourcePath, nativeLibraryRoot,
- instructionSets);
+ return new FileInstallArgs(codePath, resourcePath, instructionSets);
}
}
static abstract class InstallArgs {
/** @see InstallParams#origin */
final OriginInfo origin;
+ /** @see InstallParams#move */
+ final MoveInfo move;
final IPackageInstallObserver2 observer;
// Always refers to PackageManager flags only
@@ -9966,10 +10004,12 @@
// if we move dex files under the common app path.
/* nullable */ String[] instructionSets;
- InstallArgs(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags,
- String installerPackageName, String volumeUuid, ManifestDigest manifestDigest,
- UserHandle user, String[] instructionSets, String abiOverride) {
+ InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
+ int installFlags, String installerPackageName, String volumeUuid,
+ ManifestDigest manifestDigest, UserHandle user, String[] instructionSets,
+ String abiOverride) {
this.origin = origin;
+ this.move = move;
this.installFlags = installFlags;
this.observer = observer;
this.installerPackageName = installerPackageName;
@@ -9994,12 +10034,10 @@
abstract String getCodePath();
/** @see PackageSettingBase#resourcePathString */
abstract String getResourcePath();
- abstract String getLegacyNativeLibraryPath();
// Need installer lock especially for dex file removal.
abstract void cleanUpResourcesLI();
abstract boolean doPostDeleteLI(boolean delete);
- abstract boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException;
/**
* Called before the source arguments are copied. This is used mostly
@@ -10060,7 +10098,6 @@
class FileInstallArgs extends InstallArgs {
private File codeFile;
private File resourceFile;
- private File legacyNativeLibraryPath;
// Example topology:
// /data/app/com.example/base.apk
@@ -10071,7 +10108,7 @@
/** New install */
FileInstallArgs(InstallParams params) {
- super(params.origin, params.observer, params.installFlags,
+ super(params.origin, params.move, params.observer, params.installFlags,
params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
params.getUser(), null /* instruction sets */, params.packageAbiOverride);
if (isFwdLocked()) {
@@ -10080,21 +10117,11 @@
}
/** Existing install */
- FileInstallArgs(String codePath, String resourcePath, String legacyNativeLibraryPath,
- String[] instructionSets) {
- super(OriginInfo.fromNothing(), null, 0, null, null, null, null, instructionSets, null);
+ FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
+ super(OriginInfo.fromNothing(), null, null, 0, null, null, null, null, instructionSets,
+ null);
this.codeFile = (codePath != null) ? new File(codePath) : null;
this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
- this.legacyNativeLibraryPath = (legacyNativeLibraryPath != null) ?
- new File(legacyNativeLibraryPath) : null;
- }
-
- boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
- final long sizeBytes = imcs.calculateInstalledSize(origin.file.getAbsolutePath(),
- isFwdLocked(), abiOverride);
-
- final StorageManager storage = StorageManager.from(mContext);
- return (sizeBytes <= storage.getStorageBytesUntilLow(Environment.getDataDirectory()));
}
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
@@ -10166,46 +10193,46 @@
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
return false;
- } else {
- final File targetDir = codeFile.getParentFile();
- final File beforeCodeFile = codeFile;
- final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
-
- Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
- try {
- Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
- } catch (ErrnoException e) {
- Slog.d(TAG, "Failed to rename", e);
- return false;
- }
-
- if (!SELinux.restoreconRecursive(afterCodeFile)) {
- Slog.d(TAG, "Failed to restorecon");
- return false;
- }
-
- // Reflect the rename internally
- codeFile = afterCodeFile;
- resourceFile = afterCodeFile;
-
- // Reflect the rename in scanned details
- pkg.codePath = afterCodeFile.getAbsolutePath();
- pkg.baseCodePath = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
- pkg.baseCodePath);
- pkg.splitCodePaths = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
- pkg.splitCodePaths);
-
- // Reflect the rename in app info
- pkg.applicationInfo.volumeUuid = pkg.volumeUuid;
- pkg.applicationInfo.setCodePath(pkg.codePath);
- pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
- pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
- pkg.applicationInfo.setResourcePath(pkg.codePath);
- pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath);
- pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
-
- return true;
}
+
+ final File targetDir = codeFile.getParentFile();
+ final File beforeCodeFile = codeFile;
+ final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
+
+ Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
+ try {
+ Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
+ } catch (ErrnoException e) {
+ Slog.d(TAG, "Failed to rename", e);
+ return false;
+ }
+
+ if (!SELinux.restoreconRecursive(afterCodeFile)) {
+ Slog.d(TAG, "Failed to restorecon");
+ return false;
+ }
+
+ // Reflect the rename internally
+ codeFile = afterCodeFile;
+ resourceFile = afterCodeFile;
+
+ // Reflect the rename in scanned details
+ pkg.codePath = afterCodeFile.getAbsolutePath();
+ pkg.baseCodePath = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
+ pkg.baseCodePath);
+ pkg.splitCodePaths = FileUtils.rewriteAfterRename(beforeCodeFile, afterCodeFile,
+ pkg.splitCodePaths);
+
+ // Reflect the rename in app info
+ pkg.applicationInfo.volumeUuid = pkg.volumeUuid;
+ pkg.applicationInfo.setCodePath(pkg.codePath);
+ pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
+ pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
+ pkg.applicationInfo.setResourcePath(pkg.codePath);
+ pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath);
+ pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
+
+ return true;
}
int doPostInstall(int status, int uid) {
@@ -10225,11 +10252,6 @@
return (resourceFile != null) ? resourceFile.getAbsolutePath() : null;
}
- @Override
- String getLegacyNativeLibraryPath() {
- return (legacyNativeLibraryPath != null) ? legacyNativeLibraryPath.getAbsolutePath() : null;
- }
-
private boolean cleanUp() {
if (codeFile == null || !codeFile.exists()) {
return false;
@@ -10245,13 +10267,6 @@
resourceFile.delete();
}
- if (legacyNativeLibraryPath != null && !FileUtils.contains(codeFile, legacyNativeLibraryPath)) {
- if (!FileUtils.deleteContents(legacyNativeLibraryPath)) {
- Slog.w(TAG, "Couldn't delete native library directory " + legacyNativeLibraryPath);
- }
- legacyNativeLibraryPath.delete();
- }
-
return true;
}
@@ -10315,11 +10330,10 @@
String cid;
String packagePath;
String resourcePath;
- String legacyNativeLibraryDir;
/** New install */
AsecInstallArgs(InstallParams params) {
- super(params.origin, params.observer, params.installFlags,
+ super(params.origin, params.move, params.observer, params.installFlags,
params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
params.getUser(), null /* instruction sets */, params.packageAbiOverride);
}
@@ -10327,7 +10341,7 @@
/** Existing install */
AsecInstallArgs(String fullCodePath, String[] instructionSets,
boolean isExternal, boolean isForwardLocked) {
- super(OriginInfo.fromNothing(), null, (isExternal ? INSTALL_EXTERNAL : 0)
+ super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
instructionSets, null);
// Hackily pretend we're still looking at a full code path
@@ -10344,7 +10358,7 @@
}
AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
- super(OriginInfo.fromNothing(), null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
+ super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
| (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
instructionSets, null);
this.cid = cid;
@@ -10355,21 +10369,6 @@
cid = mInstallerService.allocateExternalStageCidLegacy();
}
- boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
- final long sizeBytes = imcs.calculateInstalledSize(packagePath, isFwdLocked(),
- abiOverride);
-
- final File target;
- if (isExternalAsec()) {
- target = new UserEnvironment(UserHandle.USER_OWNER).getExternalStorageDirectory();
- } else {
- target = Environment.getDataDirectory();
- }
-
- final StorageManager storage = StorageManager.from(mContext);
- return (sizeBytes <= storage.getStorageBytesUntilLow(target));
- }
-
int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException {
if (origin.staged) {
Slog.d(TAG, origin.cid + " already staged; skipping copy");
@@ -10410,11 +10409,6 @@
return resourcePath;
}
- @Override
- String getLegacyNativeLibraryPath() {
- return legacyNativeLibraryDir;
- }
-
int doPreInstall(int status) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
// Destroy container
@@ -10513,8 +10507,6 @@
packagePath = mountFile.getAbsolutePath();
resourcePath = packagePath;
}
-
- legacyNativeLibraryDir = new File(mountFile, LIB_DIR_NAME).getAbsolutePath();
}
int doPostInstall(int status, int uid) {
@@ -10576,8 +10568,6 @@
removeDexFiles(allCodePaths, instructionSets);
}
-
-
String getPackageName() {
return getAsecPackageName(cid);
}
@@ -10626,6 +10616,108 @@
}
}
+ /**
+ * Logic to handle movement of existing installed applications.
+ */
+ class MoveInstallArgs extends InstallArgs {
+ private File codeFile;
+ private File resourceFile;
+
+ /** New install */
+ MoveInstallArgs(InstallParams params) {
+ super(params.origin, params.move, params.observer, params.installFlags,
+ params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+ params.getUser(), null /* instruction sets */, params.packageAbiOverride);
+ }
+
+ int copyApk(IMediaContainerService imcs, boolean temp) {
+ Slog.d(TAG, "Moving " + move.packageName + " from " + move.fromUuid + " to "
+ + move.toUuid);
+ synchronized (mInstaller) {
+ if (mInstaller.moveCompleteApp(move.fromUuid, move.toUuid, move.packageName,
+ move.dataAppName, move.appId, move.seinfo) != 0) {
+ return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ }
+ }
+
+ codeFile = new File(Environment.getDataAppDirectory(move.toUuid), move.dataAppName);
+ resourceFile = codeFile;
+ Slog.d(TAG, "codeFile after move is " + codeFile);
+
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ int doPreInstall(int status) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp();
+ }
+ return status;
+ }
+
+ boolean doRename(int status, PackageParser.Package pkg, String oldCodePath) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp();
+ return false;
+ }
+
+ // Reflect the move in app info
+ pkg.applicationInfo.volumeUuid = pkg.volumeUuid;
+ pkg.applicationInfo.setCodePath(pkg.codePath);
+ pkg.applicationInfo.setBaseCodePath(pkg.baseCodePath);
+ pkg.applicationInfo.setSplitCodePaths(pkg.splitCodePaths);
+ pkg.applicationInfo.setResourcePath(pkg.codePath);
+ pkg.applicationInfo.setBaseResourcePath(pkg.baseCodePath);
+ pkg.applicationInfo.setSplitResourcePaths(pkg.splitCodePaths);
+
+ return true;
+ }
+
+ int doPostInstall(int status, int uid) {
+ if (status != PackageManager.INSTALL_SUCCEEDED) {
+ cleanUp();
+ }
+ return status;
+ }
+
+ @Override
+ String getCodePath() {
+ return (codeFile != null) ? codeFile.getAbsolutePath() : null;
+ }
+
+ @Override
+ String getResourcePath() {
+ return (resourceFile != null) ? resourceFile.getAbsolutePath() : null;
+ }
+
+ private boolean cleanUp() {
+ if (codeFile == null || !codeFile.exists()) {
+ return false;
+ }
+
+ if (codeFile.isDirectory()) {
+ mInstaller.rmPackageDir(codeFile.getAbsolutePath());
+ } else {
+ codeFile.delete();
+ }
+
+ if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
+ resourceFile.delete();
+ }
+
+ return true;
+ }
+
+ void cleanUpResourcesLI() {
+ cleanUp();
+ }
+
+ boolean doPostDeleteLI(boolean delete) {
+ // XXX err, shouldn't we respect the delete flag?
+ cleanUpResourcesLI();
+ return true;
+ }
+ }
+
static String getAsecPackageName(String packageCid) {
int idx = packageCid.lastIndexOf("-");
if (idx == -1) {
@@ -11012,7 +11104,6 @@
res.removedInfo.args = createInstallArgsForExisting(0,
deletedPackage.applicationInfo.getCodePath(),
deletedPackage.applicationInfo.getResourcePath(),
- deletedPackage.applicationInfo.nativeLibraryRootDir,
getAppDexInstructionSets(deletedPackage.applicationInfo));
} else {
res.removedInfo.args = null;
@@ -11320,8 +11411,10 @@
return;
}
- // If app directory is not writable, dexopt will be called after the rename
- if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
+ if (args.move != null) {
+ // We did an in-place move, so dex is ready to roll
+ scanFlags |= SCAN_NO_DEX;
+ } else if (!forwardLocked && !pkg.applicationInfo.isExternalAsec()) {
// Enable SCAN_NO_DEX flag to skip dexopt at a later stage
scanFlags |= SCAN_NO_DEX;
// Run dexopt before old package gets removed, to minimize time when app is unavailable
@@ -11704,7 +11797,7 @@
return res ? PackageManager.DELETE_SUCCEEDED : PackageManager.DELETE_FAILED_INTERNAL_ERROR;
}
- static class PackageRemovedInfo {
+ class PackageRemovedInfo {
String removedPackage;
int uid = -1;
int removedAppId = -1;
@@ -11949,8 +12042,7 @@
// Delete application code and resources
if (deleteCodeAndResources && (outInfo != null)) {
outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
- ps.codePathString, ps.resourcePathString, ps.legacyNativeLibraryPathString,
- getAppDexInstructionSets(ps));
+ ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
}
return true;
@@ -13119,8 +13211,8 @@
enforceCrossUserPermission(uid, userId, true, true, "stop package");
// writer
synchronized (mPackages) {
- if (mSettings.setPackageStoppedStateLPw(packageName, stopped, allowedByPermission,
- uid, userId)) {
+ if (mSettings.setPackageStoppedStateLPw(this, packageName, stopped,
+ allowedByPermission, uid, userId)) {
scheduleWritePackageRestrictionsLocked(userId);
}
}
@@ -14180,17 +14272,16 @@
private void loadPrivatePackages(VolumeInfo vol) {
final ArrayList<ApplicationInfo> loaded = new ArrayList<>();
final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE;
+ synchronized (mInstallLock) {
synchronized (mPackages) {
final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
for (PackageSetting ps : packages) {
- synchronized (mInstallLock) {
- final PackageParser.Package pkg;
- try {
- pkg = scanPackageLI(ps.codePath, parseFlags, 0, 0, null);
- loaded.add(pkg.applicationInfo);
- } catch (PackageManagerException e) {
- Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
- }
+ final PackageParser.Package pkg;
+ try {
+ pkg = scanPackageLI(ps.codePath, parseFlags, 0, 0, null);
+ loaded.add(pkg.applicationInfo);
+ } catch (PackageManagerException e) {
+ Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
}
}
@@ -14198,6 +14289,7 @@
mSettings.writeLPr();
}
+ }
Slog.d(TAG, "Loaded packages " + loaded);
sendResourcesChangedBroadcast(true, false, loaded, null);
@@ -14205,24 +14297,25 @@
private void unloadPrivatePackages(VolumeInfo vol) {
final ArrayList<ApplicationInfo> unloaded = new ArrayList<>();
+ synchronized (mInstallLock) {
synchronized (mPackages) {
final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
for (PackageSetting ps : packages) {
if (ps.pkg == null) continue;
- synchronized (mInstallLock) {
- final ApplicationInfo info = ps.pkg.applicationInfo;
- final PackageRemovedInfo outInfo = new PackageRemovedInfo();
- if (deletePackageLI(ps.name, null, false, null, null,
- PackageManager.DELETE_KEEP_DATA, outInfo, false)) {
- unloaded.add(info);
- } else {
- Slog.w(TAG, "Failed to unload " + ps.codePath);
- }
+
+ final ApplicationInfo info = ps.pkg.applicationInfo;
+ final PackageRemovedInfo outInfo = new PackageRemovedInfo();
+ if (deletePackageLI(ps.name, null, false, null, null,
+ PackageManager.DELETE_KEEP_DATA, outInfo, false)) {
+ unloaded.add(info);
+ } else {
+ Slog.w(TAG, "Failed to unload " + ps.codePath);
}
}
mSettings.writeLPr();
}
+ }
Slog.d(TAG, "Unloaded packages " + unloaded);
sendResourcesChangedBroadcast(false, false, unloaded, null);
@@ -14255,6 +14348,7 @@
private void movePackageInternal(final String packageName, final String volumeUuid,
final int moveId) throws PackageManagerException {
final UserHandle user = new UserHandle(UserHandle.getCallingUserId());
+ final StorageManager storage = mContext.getSystemService(StorageManager.class);
final PackageManager pm = mContext.getPackageManager();
final boolean currentAsec;
@@ -14284,11 +14378,17 @@
"Package already moved to " + volumeUuid);
}
+ final File probe = new File(pkg.codePath);
+ final File probeOat = new File(probe, "oat");
+ if (!probe.isDirectory() || !probeOat.isDirectory()) {
+ throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+ "Move only supported for modern cluster style installs");
+ }
+
if (ps.frozen) {
throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
"Failed to move already frozen package");
}
-
ps.frozen = true;
currentAsec = pkg.applicationInfo.isForwardLocked()
@@ -14302,7 +14402,7 @@
label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
}
- // Now that we're guarded by frozen state, kill app during upgrade
+ // Now that we're guarded by frozen state, kill app during move
killApplication(packageName, appId, "move pkg");
final Bundle extras = new Bundle();
@@ -14311,16 +14411,18 @@
mMoveCallbacks.notifyCreated(moveId, extras);
int installFlags;
- final boolean moveData;
+ final boolean moveCompleteApp;
+ final File measurePath;
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, volumeUuid)) {
installFlags = INSTALL_INTERNAL;
- moveData = !currentAsec;
+ moveCompleteApp = !currentAsec;
+ measurePath = Environment.getDataAppDirectory(volumeUuid);
} else if (Objects.equals(StorageManager.UUID_PRIMARY_PHYSICAL, volumeUuid)) {
installFlags = INSTALL_EXTERNAL;
- moveData = false;
+ moveCompleteApp = false;
+ measurePath = storage.getPrimaryPhysicalVolume().getPath();
} else {
- final StorageManager storage = mContext.getSystemService(StorageManager.class);
final VolumeInfo volume = storage.findVolumeByUuid(volumeUuid);
if (volume == null || volume.getType() != VolumeInfo.TYPE_PRIVATE
|| !volume.isMountedWritable()) {
@@ -14332,26 +14434,38 @@
Preconditions.checkState(!currentAsec);
installFlags = INSTALL_INTERNAL;
- moveData = true;
+ moveCompleteApp = true;
+ measurePath = Environment.getDataAppDirectory(volumeUuid);
}
- Slog.d(TAG, "Moving " + packageName + " from " + currentVolumeUuid + " to " + volumeUuid);
- mMoveCallbacks.notifyStatusChanged(moveId, 10);
-
- if (moveData) {
- synchronized (mInstallLock) {
- // TODO: split this into separate copy and delete operations
- if (mInstaller.moveUserDataDirs(currentVolumeUuid, volumeUuid, packageName, appId,
- seinfo) != 0) {
- unfreezePackage(packageName);
- throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
- "Failed to move private data to " + volumeUuid);
- }
+ final PackageStats stats = new PackageStats(null, -1);
+ synchronized (mInstaller) {
+ if (!getPackageSizeInfoLI(packageName, -1, stats)) {
+ unfreezePackage(packageName);
+ throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+ "Failed to measure package size");
}
}
- mMoveCallbacks.notifyStatusChanged(moveId, 50);
+ Slog.d(TAG, "Measured code size " + stats.codeSize + ", data size " + stats.dataSize);
+ final long startFreeBytes = measurePath.getFreeSpace();
+ final long sizeBytes;
+ if (moveCompleteApp) {
+ sizeBytes = stats.codeSize + stats.dataSize;
+ } else {
+ sizeBytes = stats.codeSize;
+ }
+
+ if (sizeBytes > storage.getStorageBytesUntilLow(measurePath)) {
+ unfreezePackage(packageName);
+ throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
+ "Not enough free space to move");
+ }
+
+ mMoveCallbacks.notifyStatusChanged(moveId, 10);
+
+ final CountDownLatch installedLatch = new CountDownLatch(1);
final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) throws RemoteException {
@@ -14364,6 +14478,8 @@
Slog.d(TAG, "Install result for move: "
+ PackageManager.installStatusToString(returnCode, msg));
+ installedLatch.countDown();
+
// Regardless of success or failure of the move operation,
// always unfreeze the package
unfreezePackage(packageName);
@@ -14386,13 +14502,40 @@
}
};
- // Treat a move like reinstalling an existing app, which ensures that we
- // process everythign uniformly, like unpacking native libraries.
+ final MoveInfo move;
+ if (moveCompleteApp) {
+ // Kick off a thread to report progress estimates
+ new Thread() {
+ @Override
+ public void run() {
+ while (true) {
+ try {
+ if (installedLatch.await(1, TimeUnit.SECONDS)) {
+ break;
+ }
+ } catch (InterruptedException ignored) {
+ }
+
+ final long deltaFreeBytes = startFreeBytes - measurePath.getFreeSpace();
+ final int progress = 10 + (int) MathUtils.constrain(
+ ((deltaFreeBytes * 80) / sizeBytes), 0, 80);
+ mMoveCallbacks.notifyStatusChanged(moveId, progress);
+ }
+ }
+ }.start();
+
+ final String dataAppName = codeFile.getName();
+ move = new MoveInfo(moveId, currentVolumeUuid, volumeUuid, packageName,
+ dataAppName, appId, seinfo);
+ } else {
+ move = null;
+ }
+
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
final Message msg = mHandler.obtainMessage(INIT_COPY);
final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
- msg.obj = new InstallParams(origin, installObserver, installFlags,
+ msg.obj = new InstallParams(origin, move, installObserver, installFlags,
installerPackageName, volumeUuid, null, user, packageAbiOverride);
mHandler.sendMessage(msg);
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f9c248d..d3bfdeb 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -985,6 +985,13 @@
if (ivi == null) {
ivi = new IntentFilterVerificationInfo(packageName, domains);
ps.setIntentFilterVerificationInfo(ivi);
+ Slog.d(PackageManagerService.TAG,
+ "Creating new IntentFilterVerificationInfo for packageName: " + packageName);
+ } else {
+ ivi.setDomains(domains);
+ Slog.d(PackageManagerService.TAG,
+ "Setting domains to existing IntentFilterVerificationInfo for packageName: " +
+ packageName + " and with domains: " + ivi.getDomainsString());
}
return ivi;
}
@@ -1021,7 +1028,7 @@
// Then, if we set a ALWAYS status, then put NEVER status for Apps whose IntentFilter
// domains overlap the domains of the current package
- ArraySet<String> currentDomains = current.getIntentFilterVerificationInfo().getDomainsSet();
+ ArraySet<String> currentDomains = current.getIntentFilterVerificationInfo().getDomains();
if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
for (PackageSetting ps : mPackages.values()) {
if (ps == null || ps.pkg.packageName.equals(packageName)) continue;
@@ -1029,7 +1036,7 @@
if (ivi == null) {
continue;
}
- ArraySet<String> set = ivi.getDomainsSet();
+ ArraySet<String> set = ivi.getDomains();
set.retainAll(currentDomains);
if (set.size() > 0) {
ps.setDomainVerificationStatusForUser(
@@ -3603,8 +3610,8 @@
return pkg.getCurrentEnabledStateLPr(classNameStr, userId);
}
- boolean setPackageStoppedStateLPw(String packageName, boolean stopped,
- boolean allowedByPermission, int uid, int userId) {
+ boolean setPackageStoppedStateLPw(PackageManagerService yucky, String packageName,
+ boolean stopped, boolean allowedByPermission, int uid, int userId) {
int appId = UserHandle.getAppId(uid);
final PackageSetting pkgSetting = mPackages.get(packageName);
if (pkgSetting == null) {
@@ -3628,7 +3635,7 @@
// pkgSetting.pkg.mSetStopped = stopped;
if (pkgSetting.getNotLaunched(userId)) {
if (pkgSetting.installerPackageName != null) {
- PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
+ yucky.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH,
pkgSetting.name, null,
pkgSetting.installerPackageName, null, new int[] {userId});
}
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 3d8905d..8f4fb51 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -64,7 +64,8 @@
static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject,
jobject graphicBuffer, jobject bitmapHandle) {
- SkBitmap& bitmap = *GraphicsJNI::getSkBitmapDeprecated(env, bitmapHandle);
+ SkBitmap bitmap;
+ GraphicsJNI::getSkBitmap(env, bitmapHandle, &bitmap);
SkAutoLockPixels alp(bitmap);
// The goal of this method is to copy the bitmap into the GraphicBuffer
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index c50d63c..64514a9 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -25,7 +25,7 @@
namespace android {
-static void android_server_SystemServer_nativeInit(JNIEnv* /* env */, jobject /* clazz */) {
+static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {
char propBuf[PROPERTY_VALUE_MAX];
property_get("system_init.startsensorservice", propBuf, "1");
if (strcmp(propBuf, "1") == 0) {
@@ -39,7 +39,7 @@
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- { "nativeInit", "()V", (void*) android_server_SystemServer_nativeInit },
+ { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
};
int register_android_server_SystemServer(JNIEnv* env)
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index f801d2d..c886c4c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4065,11 +4065,12 @@
}
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
synchronized (this) {
- if (mDeviceOwner != null) {
- return mDeviceOwner.getDeviceOwnerName();
+ if (mDeviceOwner == null || !mDeviceOwner.hasDeviceOwner()) {
+ return null;
}
+ String deviceOwnerPackage = mDeviceOwner.getDeviceOwnerPackageName();
+ return getApplicationLabel(deviceOwnerPackage, UserHandle.USER_OWNER);
}
- return null;
}
// Returns the active device owner or null if there is no device owner.
@@ -4426,7 +4427,6 @@
if (profileOwner == null) {
return null;
}
-
DevicePolicyData policy = getUserData(userHandle);
final int n = policy.mAdminList.size();
for (int i = 0; i < n; i++) {
@@ -4444,13 +4444,37 @@
return null;
}
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
-
- synchronized (this) {
- if (mDeviceOwner != null) {
- return mDeviceOwner.getProfileOwnerName(userHandle);
- }
+ ComponentName profileOwner = getProfileOwner(userHandle);
+ if (profileOwner == null) {
+ return null;
}
- return null;
+ return getApplicationLabel(profileOwner.getPackageName(), userHandle);
+ }
+
+ /**
+ * Canonical name for a given package.
+ */
+ private String getApplicationLabel(String packageName, int userHandle) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ final Context userContext;
+ try {
+ UserHandle handle = new UserHandle(userHandle);
+ userContext = mContext.createPackageContextAsUser(packageName, 0, handle);
+ } catch (PackageManager.NameNotFoundException nnfe) {
+ Log.w(LOG_TAG, packageName + " is not installed for user " + userHandle, nnfe);
+ return null;
+ }
+ ApplicationInfo appInfo = userContext.getApplicationInfo();
+ CharSequence result = null;
+ if (appInfo != null) {
+ PackageManager pm = userContext.getPackageManager();
+ result = pm.getApplicationLabel(appInfo);
+ }
+ return result != null ? result.toString() : null;
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/**
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2922130..c1153b6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -156,9 +156,9 @@
private boolean mFirstBoot;
/**
- * Called to initialize native system services.
+ * Start the sensor service.
*/
- private static native void nativeInit();
+ private static native void startSensorService();
/**
* The main entry point from zygote.
@@ -233,7 +233,6 @@
// Initialize native services.
System.loadLibrary("android_servers");
- nativeInit();
// Check whether we failed to shut down last time we tried.
// This call may not return.
@@ -359,6 +358,10 @@
// Set up the Application instance for the system process and get started.
mActivityManagerService.setSystemProcess();
+
+ // The sensor service needs access to package manager service, app ops
+ // service, and permissions service, therefore we start it after them.
+ startSensorService();
}
/**
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index c2e61c6..117cbe4 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -28,6 +28,7 @@
import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
+import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -56,6 +57,7 @@
import android.util.Slog;
import android.util.SparseArray;
+import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.SystemConfig;
@@ -96,6 +98,7 @@
Handler mHandler;
AppOpsManager mAppOps;
UserManager mUserManager;
+ AppWidgetManager mAppWidgetManager;
private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>();
private File mUsageStatsDir;
@@ -158,6 +161,7 @@
if (phase == PHASE_SYSTEM_SERVICES_READY) {
// Observe changes to the threshold
new SettingsObserver(mHandler).registerObserver();
+ mAppWidgetManager = getContext().getSystemService(AppWidgetManager.class);
} else if (phase == PHASE_BOOT_COMPLETED) {
setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
}
@@ -500,6 +504,11 @@
return false;
}
+ if (mAppWidgetManager != null
+ && mAppWidgetManager.isBoundWidgetPackage(packageName, userId)) {
+ return false;
+ }
+
final long lastUsed = getLastPackageAccessTime(packageName, userId);
return hasPassedIdleDuration(lastUsed);
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 81c5e6a..56b2fa5 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -734,10 +734,10 @@
}
@Override
- public boolean activeServiceSupportsAssistGesture() {
+ public boolean activeServiceSupportsAssist() {
enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
synchronized (this) {
- return mImpl != null && mImpl.mInfo.getSupportsAssistGesture();
+ return mImpl != null && mImpl.mInfo.getSupportsAssist();
}
}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 9273939..fee6495 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -132,7 +132,7 @@
/**
* @hide
*/
- public static final int CAPABILITY_UNUSED = 0x00000010;
+ public static final int CAPABILITY_UNUSED_1 = 0x00000010;
/** Call supports responding via text option. */
public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
@@ -189,27 +189,6 @@
public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
/**
- * Whether the call is a generic conference, where we do not know the precise state of
- * participants in the conference (eg. on CDMA).
- */
- public static final int CAPABILITY_GENERIC_CONFERENCE = 0x00004000;
-
- /**
- * Call is using high definition audio.
- */
- public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00008000;
-
- /**
- * Call is using WIFI.
- */
- public static final int CAPABILITY_WIFI = 0x00010000;
-
- /**
- * Indicates that the current device callback number should be shown.
- */
- public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 0x00020000;
-
- /**
* Speed up audio setup for MT call.
* @hide
*/
@@ -228,7 +207,37 @@
public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
//******************************************************************************************
- // Next CAPABILITY value: 0x00200000
+ // Next CAPABILITY value: 0x00004000
+ //******************************************************************************************
+
+ /**
+ * Whether the call is currently a conference.
+ */
+ public static final int PROPERTY_CONFERENCE = 0x00000001;
+
+ /**
+ * Whether the call is a generic conference, where we do not know the precise state of
+ * participants in the conference (eg. on CDMA).
+ */
+ public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002;
+
+ /**
+ * Whether the call is made while the device is in emergency callback mode.
+ */
+ public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004;
+
+ /**
+ * Connection is using WIFI.
+ */
+ public static final int PROPERTY_WIFI = 0x00000008;
+
+ /**
+ * Call is using high definition audio.
+ */
+ public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
+
+ //******************************************************************************************
+ // Next PROPERTY value: 0x00000020
//******************************************************************************************
private final Uri mHandle;
@@ -314,18 +323,6 @@
if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
}
- if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) {
- builder.append(" CAPABILITY_HIGH_DEF_AUDIO");
- }
- if (can(capabilities, CAPABILITY_WIFI)) {
- builder.append(" CAPABILITY_WIFI");
- }
- if (can(capabilities, CAPABILITY_GENERIC_CONFERENCE)) {
- builder.append(" CAPABILITY_GENERIC_CONFERENCE");
- }
- if (can(capabilities, CAPABILITY_SHOW_CALLBACK_NUMBER)) {
- builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
- }
if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
}
@@ -340,6 +337,55 @@
}
/**
+ * Whether the supplied properties includes the specified property.
+ *
+ * @param properties A bit field of properties.
+ * @param property The property to check properties for.
+ * @return Whether the specified property is supported.
+ */
+ public static boolean hasProperty(int properties, int property) {
+ return (properties & property) != 0;
+ }
+
+ /**
+ * Whether the properties of this {@code Details} includes the specified property.
+ *
+ * @param property The property to check properties for.
+ * @return Whether the specified property is supported.
+ */
+ public boolean hasProperty(int property) {
+ return hasProperty(mCallProperties, property);
+ }
+
+ /**
+ * Render a set of property bits ({@code PROPERTY_*}) as a human readable string.
+ *
+ * @param properties A property bit field.
+ * @return A human readable string representation.
+ */
+ public static String propertiesToString(int properties) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("[Properties:");
+ if (hasProperty(properties, PROPERTY_CONFERENCE)) {
+ builder.append(" PROPERTY_CONFERENCE");
+ }
+ if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) {
+ builder.append(" PROPERTY_GENERIC_CONFERENCE");
+ }
+ if (hasProperty(properties, PROPERTY_WIFI)) {
+ builder.append(" PROPERTY_WIFI");
+ }
+ if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) {
+ builder.append(" PROPERTY_HIGH_DEF_AUDIO");
+ }
+ if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
+ builder.append(" EMERGENCY_CALLBACK_MODE");
+ }
+ builder.append("]");
+ return builder.toString();
+ }
+
+ /**
* @return The handle (e.g., phone number) to which the {@code Call} is currently
* connected.
*/
@@ -387,8 +433,8 @@
}
/**
- * @return A bitmask of the properties of the {@code Call}, as defined in
- * {@link CallProperties}.
+ * @return A bitmask of the properties of the {@code Call}, as defined by the various
+ * {@code PROPERTY_*} constants in this class.
*/
public int getCallProperties() {
return mCallProperties;
diff --git a/telecomm/java/android/telecom/CallProperties.java b/telecomm/java/android/telecom/CallProperties.java
deleted file mode 100644
index 1721a39..0000000
--- a/telecomm/java/android/telecom/CallProperties.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.telecom;
-
-/**
- * Defines properties of a phone call which may be affected by changes to the call.
- */
-public class CallProperties {
- /** Call is currently in a conference call. */
- public static final int CONFERENCE = 0x00000001;
-}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index cdecb33..303a492 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1104,6 +1104,58 @@
|| radioTechnology == RIL_RADIO_TECHNOLOGY_EHRPD;
}
+ /** @hide */
+ public static boolean hasCdma(int radioTechnologyBitmask) {
+ int cdmaBitmask = (RIL_RADIO_TECHNOLOGY_IS95A
+ | RIL_RADIO_TECHNOLOGY_IS95B
+ | RIL_RADIO_TECHNOLOGY_1xRTT
+ | RIL_RADIO_TECHNOLOGY_EVDO_0
+ | RIL_RADIO_TECHNOLOGY_EVDO_A
+ | RIL_RADIO_TECHNOLOGY_EVDO_B
+ | RIL_RADIO_TECHNOLOGY_EHRPD);
+
+ return ((radioTechnologyBitmask & cdmaBitmask) != 0);
+ }
+
+ /** @hide */
+ public static boolean bitmaskHasTech(int bearerBitmask, int radioTech) {
+ if (bearerBitmask == 0) {
+ return true;
+ } else if (radioTech >= 1) {
+ return ((bearerBitmask & (1 << (radioTech - 1))) != 0);
+ }
+ return false;
+ }
+
+ /** @hide */
+ public static int getBitmaskForTech(int radioTech) {
+ if (radioTech >= 1) {
+ return (1 << (radioTech - 1));
+ }
+ return 0;
+ }
+
+ /** @hide */
+ public static int getBitmaskFromString(String bearerList) {
+ String[] bearers = bearerList.split("\\|");
+ int bearerBitmask = 0;
+ for (String bearer : bearers) {
+ int bearerInt = 0;
+ try {
+ bearerInt = Integer.parseInt(bearer.trim());
+ } catch (NumberFormatException nfe) {
+ return 0;
+ }
+
+ if (bearerInt == 0) {
+ return 0;
+ }
+
+ bearerBitmask |= getBitmaskForTech(bearerInt);
+ }
+ return bearerBitmask;
+ }
+
/**
* Returns a merged ServiceState consisting of the base SS with voice settings from the
* voice SS. The voice SS is only used if it is IN_SERVICE (otherwise the base SS is returned).
diff --git a/tests/Assist/res/xml/interaction_service.xml b/tests/Assist/res/xml/interaction_service.xml
index 2fd50aa..f56156e 100644
--- a/tests/Assist/res/xml/interaction_service.xml
+++ b/tests/Assist/res/xml/interaction_service.xml
@@ -18,4 +18,4 @@
<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android"
android:sessionService="com.android.test.assist.AssistInteractionSessionService"
android:recognitionService="com.android.test.assist.AssistRecognitionService"
- android:supportsAssistGesture="true"/>
+ android:supportsAssist="true"/>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
index 5ba3ad9..be5d7f9 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ProjectionActivity.java
@@ -46,9 +46,9 @@
}
private void setProject(boolean value) {
- RenderNode displayList = getDisplayList();
- if (displayList != null) {
- displayList.setProjectBackwards(value);
+ RenderNode renderNode = updateDisplayListIfDirty();
+ if (renderNode != null) {
+ renderNode.setProjectBackwards(value);
}
// NOTE: we can't invalidate ProjectedView for the redraw because:
// 1) the view won't preserve displayList properties that it doesn't know about
diff --git a/tests/VoiceInteraction/res/xml/interaction_service.xml b/tests/VoiceInteraction/res/xml/interaction_service.xml
index 789493a..c015ad2 100644
--- a/tests/VoiceInteraction/res/xml/interaction_service.xml
+++ b/tests/VoiceInteraction/res/xml/interaction_service.xml
@@ -21,4 +21,4 @@
android:sessionService="com.android.test.voiceinteraction.MainInteractionSessionService"
android:recognitionService="com.android.test.voiceinteraction.MainRecognitionService"
android:settingsActivity="com.android.test.voiceinteraction.SettingsActivity"
- android:supportsAssistGesture="true" />
+ android:supportsAssist="true" />
diff --git a/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
index 30d204f..4098b98 100644
--- a/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java
@@ -57,6 +57,11 @@
public String[] getPackagesForUid(int uid) {
return new String[0];
}
+
+ @Override
+ public boolean isRuntimePermission(String permission) {
+ return false;
+ }
};
ServiceManagerNative.asInterface(BinderInternal.getContextObject())
.setPermissionController(pc);
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index 7f1e977..4072302 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -164,10 +164,6 @@
com.android.internal.R.styleable.Include_id, View.NO_ID);
final int visibility = a.getInt(
com.android.internal.R.styleable.Include_visibility, -1);
- final boolean hasWidth = a.hasValue(
- com.android.internal.R.styleable.Include_layout_width);
- final boolean hasHeight = a.hasValue(
- com.android.internal.R.styleable.Include_layout_height);
a.recycle();
// We try to load the layout params set in the <include /> tag. If
@@ -179,19 +175,17 @@
// successfully loaded layout params from the <include /> tag,
// false means we need to rely on the included layout params.
ViewGroup.LayoutParams params = null;
- if (hasWidth && hasHeight) {
- try {
- // ---- START CHANGES
- sIsInInclude = true;
- // ---- END CHANGES
+ try {
+ // ---- START CHANGES
+ sIsInInclude = true;
+ // ---- END CHANGES
- params = group.generateLayoutParams(attrs);
+ params = group.generateLayoutParams(attrs);
- } finally {
- // ---- START CHANGES
- sIsInInclude = false;
- // ---- END CHANGES
- }
+ } finally {
+ // ---- START CHANGES
+ sIsInInclude = false;
+ // ---- END CHANGES
}
if (params == null) {
params = group.generateLayoutParams(childAttrs);