Merge "Don’t relaunch activity in fullscreen stack when entering split screen mode" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 5e4b2d4..233fbd7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5241,6 +5241,7 @@
method public boolean getContentIntentAvailableOffline();
method public int getCustomContentHeight();
method public int getCustomSizePreset();
+ method public java.lang.String getDismissalId();
method public android.app.PendingIntent getDisplayIntent();
method public int getGravity();
method public boolean getHintAmbientBigPicture();
@@ -5258,6 +5259,7 @@
method public android.app.Notification.WearableExtender setContentIntentAvailableOffline(boolean);
method public android.app.Notification.WearableExtender setCustomContentHeight(int);
method public android.app.Notification.WearableExtender setCustomSizePreset(int);
+ method public android.app.Notification.WearableExtender setDismissalId(java.lang.String);
method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
method public android.app.Notification.WearableExtender setGravity(int);
method public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
@@ -20640,6 +20642,7 @@
field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+ field public static final int DolbyVisionProfileDvheDtb = 128; // 0x80
field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
diff --git a/api/system-current.txt b/api/system-current.txt
index bde3a8c..10d7159 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5386,6 +5386,7 @@
method public boolean getContentIntentAvailableOffline();
method public int getCustomContentHeight();
method public int getCustomSizePreset();
+ method public java.lang.String getDismissalId();
method public android.app.PendingIntent getDisplayIntent();
method public int getGravity();
method public boolean getHintAmbientBigPicture();
@@ -5403,6 +5404,7 @@
method public android.app.Notification.WearableExtender setContentIntentAvailableOffline(boolean);
method public android.app.Notification.WearableExtender setCustomContentHeight(int);
method public android.app.Notification.WearableExtender setCustomSizePreset(int);
+ method public android.app.Notification.WearableExtender setDismissalId(java.lang.String);
method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
method public android.app.Notification.WearableExtender setGravity(int);
method public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
@@ -22160,6 +22162,7 @@
field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+ field public static final int DolbyVisionProfileDvheDtb = 128; // 0x80
field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
diff --git a/api/test-current.txt b/api/test-current.txt
index 9141506..d66b5c7 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5241,6 +5241,7 @@
method public boolean getContentIntentAvailableOffline();
method public int getCustomContentHeight();
method public int getCustomSizePreset();
+ method public java.lang.String getDismissalId();
method public android.app.PendingIntent getDisplayIntent();
method public int getGravity();
method public boolean getHintAmbientBigPicture();
@@ -5258,6 +5259,7 @@
method public android.app.Notification.WearableExtender setContentIntentAvailableOffline(boolean);
method public android.app.Notification.WearableExtender setCustomContentHeight(int);
method public android.app.Notification.WearableExtender setCustomSizePreset(int);
+ method public android.app.Notification.WearableExtender setDismissalId(java.lang.String);
method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
method public android.app.Notification.WearableExtender setGravity(int);
method public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
@@ -20708,6 +20710,7 @@
field public static final int DolbyVisionProfileDvavPer = 1; // 0x1
field public static final int DolbyVisionProfileDvheDen = 8; // 0x8
field public static final int DolbyVisionProfileDvheDer = 4; // 0x4
+ field public static final int DolbyVisionProfileDvheDtb = 128; // 0x80
field public static final int DolbyVisionProfileDvheDth = 64; // 0x40
field public static final int DolbyVisionProfileDvheDtr = 16; // 0x10
field public static final int DolbyVisionProfileDvheStn = 32; // 0x20
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 20037ce..0c2e3c1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -5486,6 +5486,7 @@
private static final String KEY_CUSTOM_CONTENT_HEIGHT = "customContentHeight";
private static final String KEY_GRAVITY = "gravity";
private static final String KEY_HINT_SCREEN_TIMEOUT = "hintScreenTimeout";
+ private static final String KEY_DISMISSAL_ID = "dismissalId";
// Flags bitwise-ored to mFlags
private static final int FLAG_CONTENT_INTENT_AVAILABLE_OFFLINE = 0x1;
@@ -5514,6 +5515,7 @@
private int mCustomContentHeight;
private int mGravity = DEFAULT_GRAVITY;
private int mHintScreenTimeout;
+ private String mDismissalId;
/**
* Create a {@link android.app.Notification.WearableExtender} with default
@@ -5550,6 +5552,7 @@
mCustomContentHeight = wearableBundle.getInt(KEY_CUSTOM_CONTENT_HEIGHT);
mGravity = wearableBundle.getInt(KEY_GRAVITY, DEFAULT_GRAVITY);
mHintScreenTimeout = wearableBundle.getInt(KEY_HINT_SCREEN_TIMEOUT);
+ mDismissalId = wearableBundle.getString(KEY_DISMISSAL_ID);
}
}
@@ -5600,6 +5603,9 @@
if (mHintScreenTimeout != 0) {
wearableBundle.putInt(KEY_HINT_SCREEN_TIMEOUT, mHintScreenTimeout);
}
+ if (mDismissalId != null) {
+ wearableBundle.putString(KEY_DISMISSAL_ID, mDismissalId);
+ }
builder.getExtras().putBundle(EXTRA_WEARABLE_EXTENSIONS, wearableBundle);
return builder;
@@ -5620,6 +5626,7 @@
that.mCustomContentHeight = this.mCustomContentHeight;
that.mGravity = this.mGravity;
that.mHintScreenTimeout = this.mHintScreenTimeout;
+ that.mDismissalId = this.mDismissalId;
return that;
}
@@ -6107,6 +6114,29 @@
return (mFlags & FLAG_HINT_CONTENT_INTENT_LAUNCHES_ACTIVITY) != 0;
}
+ /**
+ * When you post a notification, if you set the dismissal id field, then when that
+ * notification is canceled, notifications on other wearables and the paired Android phone
+ * having that same dismissal id will also be canceled. Note that this only works if you
+ * have notification bridge mode set to NO_BRIDGING in your Wear app manifest. See
+ * <a href="{@docRoot}wear/notifications/index.html">Adding Wearable Features to
+ * Notifications</a> for more information on how to use the bridge mode feature.
+ * @param dismissalId the dismissal id of the notification.
+ * @return this object for method chaining
+ */
+ public WearableExtender setDismissalId(String dismissalId) {
+ mDismissalId = dismissalId;
+ return this;
+ }
+
+ /**
+ * Returns the dismissal id of the notification.
+ * @return the dismissal id of the notification or null if it has not been set.
+ */
+ public String getDismissalId() {
+ return mDismissalId;
+ }
+
private void setFlag(int mask, boolean value) {
if (value) {
mFlags |= mask;
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index ecfc527..c475575 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -16,6 +16,8 @@
package android.app.job;
+import static android.util.TimeUtils.formatDuration;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
@@ -24,7 +26,6 @@
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.util.Log;
-import static android.util.TimeUtils.formatDuration;
import java.util.ArrayList;
@@ -154,6 +155,20 @@
*/
public static final int PRIORITY_ADJ_ALWAYS_RUNNING = -80;
+ /**
+ * Indicates that the implementation of this job will be using
+ * {@link JobService#startForeground(int, android.app.Notification)} to run
+ * in the foreground.
+ * <p>
+ * When set, the internal scheduling of this job will ignore any background
+ * network restrictions for the requesting app. Note that this flag alone
+ * doesn't actually place your {@link JobService} in the foreground; you
+ * still need to post the notification yourself.
+ *
+ * @hide
+ */
+ public static final int FLAG_WILL_BE_FOREGROUND = 1 << 0;
+
private final int jobId;
private final PersistableBundle extras;
private final ComponentName service;
@@ -174,6 +189,7 @@
private final long initialBackoffMillis;
private final int backoffPolicy;
private final int priority;
+ private final int flags;
/**
* Unique job id associated with this class. This is assigned to your job by the scheduler.
@@ -201,6 +217,11 @@
return priority;
}
+ /** @hide */
+ public int getFlags() {
+ return flags;
+ }
+
/**
* Whether this job needs the device to be plugged in.
*/
@@ -356,6 +377,7 @@
hasEarlyConstraint = in.readInt() == 1;
hasLateConstraint = in.readInt() == 1;
priority = in.readInt();
+ flags = in.readInt();
}
private JobInfo(JobInfo.Builder b) {
@@ -381,6 +403,7 @@
hasEarlyConstraint = b.mHasEarlyConstraint;
hasLateConstraint = b.mHasLateConstraint;
priority = b.mPriority;
+ flags = b.mFlags;
}
@Override
@@ -410,6 +433,7 @@
out.writeInt(hasEarlyConstraint ? 1 : 0);
out.writeInt(hasLateConstraint ? 1 : 0);
out.writeInt(priority);
+ out.writeInt(this.flags);
}
public static final Creator<JobInfo> CREATOR = new Creator<JobInfo>() {
@@ -504,6 +528,7 @@
private PersistableBundle mExtras = PersistableBundle.EMPTY;
private ComponentName mJobService;
private int mPriority = PRIORITY_DEFAULT;
+ private int mFlags;
// Requirements.
private boolean mRequiresCharging;
private boolean mRequiresDeviceIdle;
@@ -539,14 +564,18 @@
mJobId = jobId;
}
- /**
- * @hide
- */
+ /** @hide */
public Builder setPriority(int priority) {
mPriority = priority;
return this;
}
+ /** @hide */
+ public Builder setFlags(int flags) {
+ mFlags = flags;
+ return this;
+ }
+
/**
* Set optional extras. This is persisted, so we only allow primitive types.
* @param extras Bundle containing extras you want the scheduler to hold on to for you.
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 167befc..bdea1e0 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -188,7 +188,7 @@
* See {@link android.R.attr#resizeableActivity}.
* @hide
*/
- public int resizeMode;
+ public int resizeMode = RESIZE_MODE_RESIZEABLE;
/**
* Name of the VrListenerService component to run for this activity.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 66c5000..6534f5b 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -159,6 +159,7 @@
private static final String TAG_SUPPORTS_INPUT = "supports-input";
private static final String TAG_EAT_COMMENT = "eat-comment";
private static final String TAG_PACKAGE = "package";
+ private static final String TAG_RESTRICT_UPDATE = "restrict-update";
// These are the tags supported by child packages
private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
@@ -1639,9 +1640,9 @@
/**
* This is the common parsing routing for handling parent and child
* packages in a base APK. The difference between parent and child
- * parsing is that some targs are not supported by child packages as
+ * parsing is that some tags are not supported by child packages as
* well as some manifest attributes are ignored. The implementation
- * assumes the calling code already handled the manifest tag if needed
+ * assumes the calling code has already handled the manifest tag if needed
* (this applies to the parent only).
*
* @param pkg The package which to populate
@@ -2089,6 +2090,29 @@
// If parsing a child failed the error is already set
return null;
}
+
+ } else if (tagName.equals(TAG_RESTRICT_UPDATE)) {
+ if ((flags & PARSE_IS_SYSTEM_DIR) != 0) {
+ sa = res.obtainAttributes(parser,
+ com.android.internal.R.styleable.AndroidManifestRestrictUpdate);
+ final String hash = sa.getNonConfigurationString(
+ com.android.internal.R.styleable.AndroidManifestRestrictUpdate_hash, 0);
+ sa.recycle();
+
+ pkg.restrictUpdateHash = null;
+ if (hash != null) {
+ final int hashLength = hash.length();
+ final byte[] hashBytes = new byte[hashLength / 2];
+ for (int i = 0; i < hashLength; i += 2){
+ hashBytes[i/2] = (byte) ((Character.digit(hash.charAt(i), 16) << 4)
+ + Character.digit(hash.charAt(i + 1), 16));
+ }
+ pkg.restrictUpdateHash = hashBytes;
+ }
+ }
+
+ XmlUtils.skipCurrentTag(parser);
+
} else if (RIGID_PARSER) {
outError[0] = "Bad element under <manifest>: "
+ parser.getName();
@@ -4822,6 +4846,8 @@
*/
public boolean use32bitAbi;
+ public byte[] restrictUpdateHash;
+
public Package(String packageName) {
this.packageName = packageName;
applicationInfo.packageName = packageName;
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index 194b9ee..aaf6c57 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -357,6 +357,7 @@
retVal += "\n\tPeakMips : " + mPeakMips;
retVal += ", StoppedPowerDraw : " + mStoppedPowerDrawMw + " mW";
retVal += ", PeakPowerDraw : " + mPeakPowerDrawMw + " mW";
+ retVal += ", MaxPacketLength : " + mMaxPacketLengthBytes + " Bytes";
retVal += "\n\tSupported sensors : " + Arrays.toString(mSupportedSensors);
retVal += "\n\tMemory Regions : " + Arrays.toString(mMemoryRegions);
@@ -375,6 +376,7 @@
mStoppedPowerDrawMw = in.readFloat();
mSleepPowerDrawMw = in.readFloat();
mPeakPowerDrawMw = in.readFloat();
+ mMaxPacketLengthBytes = in.readInt();
int numSupportedSensors = in.readInt();
mSupportedSensors = new int[numSupportedSensors];
@@ -398,6 +400,7 @@
out.writeFloat(mStoppedPowerDrawMw);
out.writeFloat(mSleepPowerDrawMw);
out.writeFloat(mPeakPowerDrawMw);
+ out.writeInt(mMaxPacketLengthBytes);
out.writeInt(mSupportedSensors.length);
out.writeIntArray(mSupportedSensors);
@@ -414,4 +417,4 @@
return new ContextHubInfo[size];
}
};
-}
\ No newline at end of file
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index faf5c64..933dddf 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -774,8 +774,13 @@
* @hide
*/
public Network getActiveNetworkForUid(int uid) {
+ return getActiveNetworkForUid(uid, false);
+ }
+
+ /** {@hide} */
+ public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) {
try {
- return mService.getActiveNetworkForUid(uid);
+ return mService.getActiveNetworkForUid(uid, ignoreBlocked);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -836,8 +841,13 @@
* {@hide}
*/
public NetworkInfo getActiveNetworkInfoForUid(int uid) {
+ return getActiveNetworkInfoForUid(uid, false);
+ }
+
+ /** {@hide} */
+ public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
try {
- return mService.getActiveNetworkInfoForUid(uid);
+ return mService.getActiveNetworkInfoForUid(uid, ignoreBlocked);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -880,8 +890,13 @@
* is not valid.
*/
public NetworkInfo getNetworkInfo(Network network) {
+ return getNetworkInfoForUid(network, Process.myUid(), false);
+ }
+
+ /** {@hide} */
+ public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) {
try {
- return mService.getNetworkInfoForNetwork(network);
+ return mService.getNetworkInfoForUid(network, uid, ignoreBlocked);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index c897c45..aec6b3e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -44,11 +44,11 @@
interface IConnectivityManager
{
Network getActiveNetwork();
- Network getActiveNetworkForUid(int uid);
+ Network getActiveNetworkForUid(int uid, boolean ignoreBlocked);
NetworkInfo getActiveNetworkInfo();
- NetworkInfo getActiveNetworkInfoForUid(int uid);
+ NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked);
NetworkInfo getNetworkInfo(int networkType);
- NetworkInfo getNetworkInfoForNetwork(in Network network);
+ NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean ignoreBlocked);
NetworkInfo[] getAllNetworkInfo();
Network getNetworkForType(int networkType);
Network[] getAllNetworks();
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 2b8b28d..224ff5b 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -38,6 +38,9 @@
boolean isUidForeground(int uid);
+ /** Higher priority listener before general event dispatch */
+ void setConnectivityListener(INetworkPolicyListener listener);
+
void registerListener(INetworkPolicyListener listener);
void unregisterListener(INetworkPolicyListener listener);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 2c63be2..959b309 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1157,6 +1157,8 @@
public short batteryTemperature;
public char batteryVoltage;
+
+ public int batteryChargeCoulombs;
// Constants from SCREEN_BRIGHTNESS_*
public static final int STATE_BRIGHTNESS_SHIFT = 0;
@@ -1181,6 +1183,8 @@
public static final int STATE_WIFI_SCAN_FLAG = 1<<27;
public static final int STATE_WIFI_RADIO_ACTIVE_FLAG = 1<<26;
public static final int STATE_MOBILE_RADIO_ACTIVE_FLAG = 1<<25;
+ // Do not use, this is used for coulomb delta count.
+ private static final int STATE_RESERVED_0 = 1<<24;
// These are on the lower bits used for the command; if they change
// we need to write another int of data.
public static final int STATE_SENSOR_ON_FLAG = 1<<23;
@@ -1352,6 +1356,7 @@
bat = (((int)batteryTemperature)&0xffff)
| ((((int)batteryVoltage)<<16)&0xffff0000);
dest.writeInt(bat);
+ dest.writeInt(batteryChargeCoulombs);
dest.writeInt(states);
dest.writeInt(states2);
if (wakelockTag != null) {
@@ -1380,6 +1385,7 @@
int bat2 = src.readInt();
batteryTemperature = (short)(bat2&0xffff);
batteryVoltage = (char)((bat2>>16)&0xffff);
+ batteryChargeCoulombs = src.readInt();
states = src.readInt();
states2 = src.readInt();
if ((bat&0x10000000) != 0) {
@@ -1419,6 +1425,7 @@
batteryPlugType = 0;
batteryTemperature = 0;
batteryVoltage = 0;
+ batteryChargeCoulombs = 0;
states = 0;
states2 = 0;
wakelockTag = null;
@@ -1446,6 +1453,7 @@
batteryPlugType = o.batteryPlugType;
batteryTemperature = o.batteryTemperature;
batteryVoltage = o.batteryVoltage;
+ batteryChargeCoulombs = o.batteryChargeCoulombs;
states = o.states;
states2 = o.states2;
if (o.wakelockTag != null) {
@@ -1477,6 +1485,7 @@
&& batteryPlugType == o.batteryPlugType
&& batteryTemperature == o.batteryTemperature
&& batteryVoltage == o.batteryVoltage
+ && batteryChargeCoulombs == o.batteryChargeCoulombs
&& states == o.states
&& states2 == o.states2
&& currentTime == o.currentTime;
@@ -4527,6 +4536,7 @@
int oldPlug = -1;
int oldTemp = -1;
int oldVolt = -1;
+ int oldCharge = -1;
long lastTime = -1;
void reset() {
@@ -4537,6 +4547,7 @@
oldPlug = -1;
oldTemp = -1;
oldVolt = -1;
+ oldCharge = -1;
}
public void printNextItem(PrintWriter pw, HistoryItem rec, long baseTime, boolean checkin,
@@ -4698,6 +4709,11 @@
pw.print(checkin ? ",Bv=" : " volt=");
pw.print(oldVolt);
}
+ if (oldCharge != rec.batteryChargeCoulombs) {
+ oldCharge = rec.batteryChargeCoulombs;
+ pw.print(checkin ? ",Bcc=" : " charge=");
+ pw.print(oldCharge);
+ }
printBitDescriptions(pw, oldState, rec.states, rec.wakelockTag,
HISTORY_STATE_DESCRIPTIONS, !checkin);
printBitDescriptions(pw, oldState2, rec.states2, null,
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 68b0a9f..b546da0 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -324,6 +324,11 @@
void removeIdleTimer(String iface);
/**
+ * Configure name servers, search paths, and resolver parameters for the given network.
+ */
+ void setDnsConfigurationForNetwork(int netId, in String[] servers, String domains);
+
+ /**
* Bind name servers to a network in the DNS resolver.
*/
void setDnsServersForNetwork(int netId, in String[] servers, String domains);
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index b25b33d..403e06c 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -434,6 +434,9 @@
String filename = packageFile.getCanonicalPath();
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
+ // If the package name ends with "_s.zip", it's a security update.
+ boolean securityUpdate = filename.endsWith("_s.zip");
+
// If the package is on the /data partition, the package needs to
// be processed (i.e. uncrypt'd). The caller specifies if that has
// been done in 'processed' parameter.
@@ -468,7 +471,12 @@
final String filenameArg = "--update_package=" + filename + "\n";
final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n";
- final String command = filenameArg + localeArg;
+ final String securityArg = "--security\n";
+
+ String command = filenameArg + localeArg;
+ if (securityUpdate) {
+ command += securityArg;
+ }
RecoverySystem rs = (RecoverySystem) context.getSystemService(
Context.RECOVERY_SERVICE);
@@ -501,6 +509,7 @@
public static void scheduleUpdateOnBoot(Context context, File packageFile)
throws IOException {
String filename = packageFile.getCanonicalPath();
+ boolean securityUpdate = filename.endsWith("_s.zip");
// If the package is on the /data partition, use the block map file as
// the package name instead.
@@ -510,7 +519,12 @@
final String filenameArg = "--update_package=" + filename + "\n";
final String localeArg = "--locale=" + Locale.getDefault().toString() + "\n";
- final String command = filenameArg + localeArg;
+ final String securityArg = "--security\n";
+
+ String command = filenameArg + localeArg;
+ if (securityUpdate) {
+ command += securityArg;
+ }
RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
if (!rs.setupBcb(command)) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b1bf355..700c2d2 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6869,14 +6869,6 @@
"hdmi_control_auto_device_off_enabled";
/**
- * Whether to use the DHCP client from Lollipop and earlier instead of the newer Android DHCP
- * client.
- * (0 = false, 1 = true)
- * @hide
- */
- public static final String LEGACY_DHCP_CLIENT = "legacy_dhcp_client";
-
- /**
* Whether TV will switch to MHL port when a mobile device is plugged in.
* (0 = false, 1 = true)
* @hide
@@ -6982,6 +6974,33 @@
public static final String STORAGE_BENCHMARK_INTERVAL = "storage_benchmark_interval";
/**
+ * Sample validity in seconds to configure for the system DNS resolver.
+ * {@hide}
+ */
+ public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
+ "dns_resolver_sample_validity_seconds";
+
+ /**
+ * Success threshold in percent for use with the system DNS resolver.
+ * {@hide}
+ */
+ public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
+ "dns_resolver_success_threshold_percent";
+
+ /**
+ * Minimum number of samples needed for statistics to be considered meaningful in the
+ * system DNS resolver.
+ * {@hide}
+ */
+ public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
+
+ /**
+ * Maximum number taken into account for statistics purposes in the system DNS resolver.
+ * {@hide}
+ */
+ public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
+
+ /**
* Whether to disable the automatic scheduling of system updates.
* 1 = system updates won't be automatically scheduled (will always
* present notification instead).
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index e708b0a..cf783d2 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -764,9 +764,9 @@
}
mSystemContext = context;
INotificationManager noMan = getNotificationInterface();
- noMan.registerListener(mWrapper, componentName, currentUser);
- mCurrentUser = currentUser;
mHandler = new MyHandler(context.getMainLooper());
+ mCurrentUser = currentUser;
+ noMan.registerListener(mWrapper, componentName, currentUser);
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a0384f2..edf05ba 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -389,6 +389,8 @@
/** Set to true once doDie() has been called. */
private boolean mRemoved;
+ private boolean mNeedsHwRendererSetup;
+
/**
* Consistency verifier for debugging purposes.
*/
@@ -915,6 +917,11 @@
mWindowAttributes.surfaceInsets.set(
oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
+ } else if (mWindowAttributes.surfaceInsets.left != oldInsetLeft
+ || mWindowAttributes.surfaceInsets.top != oldInsetTop
+ || mWindowAttributes.surfaceInsets.right != oldInsetRight
+ || mWindowAttributes.surfaceInsets.bottom != oldInsetBottom) {
+ mNeedsHwRendererSetup = true;
}
applyKeepScreenOnFlag(mWindowAttributes);
@@ -1959,9 +1966,11 @@
if (hardwareRenderer != null && hardwareRenderer.isEnabled()) {
if (hwInitialized
|| mWidth != hardwareRenderer.getWidth()
- || mHeight != hardwareRenderer.getHeight()) {
+ || mHeight != hardwareRenderer.getHeight()
+ || mNeedsHwRendererSetup) {
hardwareRenderer.setup(mWidth, mHeight, mAttachInfo,
mWindowAttributes.surfaceInsets);
+ mNeedsHwRendererSetup = false;
}
}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 4737e9b..2d3b6ab 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -284,6 +284,13 @@
* currently set for that origin. The host application should invoke the
* specified callback with the desired permission state. See
* {@link GeolocationPermissions} for details.
+ *
+ * <p>Note that for applications targeting Android N and later SDKs
+ * (API level > {@link android.os.Build.VERSION_CODES#M})
+ * this method is only called for requests originating from secure
+ * origins such as https. On non-secure origins geolocation requests
+ * are automatically denied.</p>
+ *
* @param origin The origin of the web content attempting to use the
* Geolocation API.
* @param callback The callback to use to set the permission state for the
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index ada7731..f54edf1 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -255,6 +255,16 @@
* is loading.
* </p>
*
+ * <h3>HTML5 Geolocation API support</h3>
+ *
+ * <p>For applications targeting Android N and later releases
+ * (API level > {@link android.os.Build.VERSION_CODES#M}) the geolocation api is only supported on
+ * secure origins such as https. For such applications requests to geolocation api on non-secure
+ * origins are automatically denied without invoking the corresponding
+ * {@link WebChromeClient#onGeolocationPermissionsShowPrompt(String, GeolocationPermissions.Callback)}
+ * method.
+ * </p>
+ *
* <h3>Layout size</h3>
* <p>
* It is recommended to set the WebView layout height to a fixed value or to
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index b6200a1..c21f1df 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -38,6 +38,7 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.widget.RadialTimePickerView.OnValueSelectedListener;
import com.android.internal.R;
import com.android.internal.widget.NumericTextView;
@@ -48,8 +49,7 @@
/**
* A delegate implementing the radial clock-based TimePicker.
*/
-class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate implements
- RadialTimePickerView.OnValueSelectedListener {
+class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
/**
* Delay in milliseconds before valid but potentially incomplete, for
* example "1" but not "12", keyboard edits are propagated from the
@@ -88,8 +88,8 @@
private boolean mIsEnabled = true;
private boolean mAllowAutoAdvance;
- private int mInitialHourOfDay;
- private int mInitialMinute;
+ private int mCurrentHour;
+ private int mCurrentMinute;
private boolean mIs24Hour;
private boolean mIsAmPmAtStart;
@@ -189,8 +189,7 @@
mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(R.id.radial_picker);
mRadialTimePickerView.applyAttributes(attrs, defStyleAttr, defStyleRes);
-
- setupListeners();
+ mRadialTimePickerView.setOnValueSelectedListener(mOnValueSelectedListener);
mAllowAutoAdvance = true;
@@ -324,28 +323,24 @@
}
private void initialize(int hourOfDay, int minute, boolean is24HourView, int index) {
- mInitialHourOfDay = hourOfDay;
- mInitialMinute = minute;
+ mCurrentHour = hourOfDay;
+ mCurrentMinute = minute;
mIs24Hour = is24HourView;
updateUI(index);
}
- private void setupListeners() {
- mRadialTimePickerView.setOnValueSelectedListener(this);
- }
-
private void updateUI(int index) {
updateHeaderAmPm();
- updateHeaderHour(mInitialHourOfDay, false);
+ updateHeaderHour(mCurrentHour, false);
updateHeaderSeparator();
- updateHeaderMinute(mInitialMinute, false);
+ updateHeaderMinute(mCurrentMinute, false);
updateRadialPicker(index);
mDelegator.invalidate();
}
private void updateRadialPicker(int index) {
- mRadialTimePickerView.initialize(mInitialHourOfDay, mInitialMinute, mIs24Hour);
+ mRadialTimePickerView.initialize(mCurrentHour, mCurrentMinute, mIs24Hour);
setCurrentItemShowing(index, false, true);
}
@@ -358,7 +353,7 @@
final boolean isAmPmAtStart = dateTimePattern.startsWith("a");
setAmPmAtStart(isAmPmAtStart);
- updateAmPmLabelStates(mInitialHourOfDay < 12 ? AM : PM);
+ updateAmPmLabelStates(mCurrentHour < 12 ? AM : PM);
}
}
@@ -388,15 +383,25 @@
*/
@Override
public void setHour(int hour) {
- if (mInitialHourOfDay != hour) {
- mInitialHourOfDay = hour;
- updateHeaderHour(hour, true);
- updateHeaderAmPm();
- mRadialTimePickerView.setCurrentHour(hour);
- mRadialTimePickerView.setAmOrPm(mInitialHourOfDay < 12 ? AM : PM);
- mDelegator.invalidate();
- onTimeChanged();
+ setHourInternal(hour, false, true);
+ }
+
+ private void setHourInternal(int hour, boolean isFromPicker, boolean announce) {
+ if (mCurrentHour == hour) {
+ return;
}
+
+ mCurrentHour = hour;
+ updateHeaderHour(hour, announce);
+ updateHeaderAmPm();
+
+ if (!isFromPicker) {
+ mRadialTimePickerView.setCurrentHour(hour);
+ mRadialTimePickerView.setAmOrPm(hour < 12 ? AM : PM);
+ }
+
+ mDelegator.invalidate();
+ onTimeChanged();
}
/**
@@ -421,13 +426,23 @@
*/
@Override
public void setMinute(int minute) {
- if (mInitialMinute != minute) {
- mInitialMinute = minute;
- updateHeaderMinute(minute, true);
- mRadialTimePickerView.setCurrentMinute(minute);
- mDelegator.invalidate();
- onTimeChanged();
+ setMinuteInternal(minute, false);
+ }
+
+ private void setMinuteInternal(int minute, boolean isFromPicker) {
+ if (mCurrentMinute == minute) {
+ return;
}
+
+ mCurrentMinute = minute;
+ updateHeaderMinute(minute, true);
+
+ if (!isFromPicker) {
+ mRadialTimePickerView.setCurrentMinute(minute);
+ }
+
+ mDelegator.invalidate();
+ onTimeChanged();
}
/**
@@ -448,7 +463,7 @@
public void setIs24Hour(boolean is24Hour) {
if (mIs24Hour != is24Hour) {
mIs24Hour = is24Hour;
- mInitialHourOfDay = getHour();
+ mCurrentHour = getHour();
updateHourFormat();
updateUI(mRadialTimePickerView.getCurrentItemShowing());
@@ -563,34 +578,6 @@
}
/**
- * Called by the picker for updating the header display.
- */
- @Override
- public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
- switch (pickerIndex) {
- case HOUR_INDEX:
- if (mAllowAutoAdvance && autoAdvance) {
- updateHeaderHour(newValue, false);
- setCurrentItemShowing(MINUTE_INDEX, true, false);
- mDelegator.announceForAccessibility(newValue + ". " + mSelectMinutes);
- } else {
- updateHeaderHour(newValue, true);
- }
- break;
- case MINUTE_INDEX:
- updateHeaderMinute(newValue, true);
- break;
- case AMPM_INDEX:
- updateAmPmLabelStates(newValue);
- break;
- }
-
- if (mOnTimeChangedListener != null) {
- mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
- }
- }
-
- /**
* Converts hour-of-day (0-23) time into a localized hour number.
* <p>
* The localized value may be in the range (0-23), (1-24), (0-11), or
@@ -702,11 +689,43 @@
private void setAmOrPm(int amOrPm) {
updateAmPmLabelStates(amOrPm);
- if (mRadialTimePickerView.setAmOrPm(amOrPm) && mOnTimeChangedListener != null) {
- mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
+ if (mRadialTimePickerView.setAmOrPm(amOrPm)) {
+ mCurrentHour = getHour();
+
+ if (mOnTimeChangedListener != null) {
+ mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
+ }
}
}
+ /** Listener for RadialTimePickerView interaction. */
+ private final OnValueSelectedListener mOnValueSelectedListener = new OnValueSelectedListener() {
+ @Override
+ public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) {
+ switch (pickerIndex) {
+ case HOUR_INDEX:
+ final boolean isTransition = mAllowAutoAdvance && autoAdvance;
+ setHourInternal(newValue, true, !isTransition);
+ if (isTransition) {
+ setCurrentItemShowing(MINUTE_INDEX, true, false);
+ mDelegator.announceForAccessibility(newValue + ". " + mSelectMinutes);
+ }
+ break;
+ case MINUTE_INDEX:
+ setMinuteInternal(newValue, true);
+ break;
+ case AMPM_INDEX:
+ updateAmPmLabelStates(newValue);
+ break;
+ }
+
+ if (mOnTimeChangedListener != null) {
+ mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
+ }
+ }
+ };
+
+ /** Listener for keyboard interaction. */
private final OnValueChangedListener mDigitEnteredListener = new OnValueChangedListener() {
@Override
public void onValueChanged(NumericTextView view, int value,
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index a2a135b..42b89d5 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -122,7 +122,8 @@
void noteNetworkInterfaceType(String iface, int type);
void noteNetworkStatsEnabled();
void noteDeviceIdleMode(int mode, String activeReason, int activeUid);
- void setBatteryState(int status, int health, int plugType, int level, int temp, int volt);
+ void setBatteryState(int status, int health, int plugType, int level, int temp, int volt,
+ int chargeCount);
long getAwakeTimeBattery();
long getAwakeTimePlugged();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 5358d78..654a4f1 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -108,7 +108,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 143 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 144 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -2089,27 +2089,111 @@
tag.poolIdx = index;
}
+ /*
+ The history delta format uses flags to denote further data in subsequent ints in the parcel.
+
+ There is always the first token, which may contain the delta time, or an indicator of
+ the length of the time (int or long) following this token.
+
+ First token: always present,
+ 31 23 15 7 0
+ █M|L|K|J|I|H|G|F█E|D|C|B|A|T|T|T█T|T|T|T|T|T|T|T█T|T|T|T|T|T|T|T█
+
+ T: the delta time if it is <= 0x7fffd. Otherwise 0x7fffe indicates an int immediately
+ follows containing the time, and 0x7ffff indicates a long immediately follows with the
+ delta time.
+ A: battery level changed and an int follows with battery data.
+ B: state changed and an int follows with state change data.
+ C: state2 has changed and an int follows with state2 change data.
+ D: wakelock/wakereason has changed and an wakelock/wakereason struct follows.
+ E: event data has changed and an event struct follows.
+ F: battery charge in coulombs has changed and an int with the charge follows.
+ G: state flag denoting that the mobile radio was active.
+ H: state flag denoting that the wifi radio was active.
+ I: state flag denoting that a wifi scan occurred.
+ J: state flag denoting that a wifi full lock was held.
+ K: state flag denoting that the gps was on.
+ L: state flag denoting that a wakelock was held.
+ M: state flag denoting that the cpu was running.
+
+ Time int/long: if T in the first token is 0x7ffff or 0x7fffe, then an int or long follows
+ with the time delta.
+
+ Battery level int: if A in the first token is set,
+ 31 23 15 7 0
+ █L|L|L|L|L|L|L|T█T|T|T|T|T|T|T|T█T|V|V|V|V|V|V|V█V|V|V|V|V|V|V|D█
+
+ D: indicates that extra history details follow.
+ V: the battery voltage.
+ T: the battery temperature.
+ L: the battery level (out of 100).
+
+ State change int: if B in the first token is set,
+ 31 23 15 7 0
+ █S|S|S|H|H|H|P|P█F|E|D|C|B| | |A█ | | | | | | | █ | | | | | | | █
+
+ A: wifi multicast was on.
+ B: battery was plugged in.
+ C: screen was on.
+ D: phone was scanning for signal.
+ E: audio was on.
+ F: a sensor was active.
+
+ State2 change int: if C in the first token is set,
+ 31 23 15 7 0
+ █M|L|K|J|I|H|H|G█F|E|D|C| | | | █ | | | | | | | █ |B|B|B|A|A|A|A█
+
+ A: 4 bits indicating the wifi supplicant state: {@link BatteryStats#WIFI_SUPPL_STATE_NAMES}.
+ B: 3 bits indicating the wifi signal strength: 0, 1, 2, 3, 4.
+ C: a bluetooth scan was active.
+ D: the camera was active.
+ E: bluetooth was on.
+ F: a phone call was active.
+ G: the device was charging.
+ H: 2 bits indicating the device-idle (doze) state: off, light, full
+ I: the flashlight was on.
+ J: wifi was on.
+ K: wifi was running.
+ L: video was playing.
+ M: power save mode was on.
+
+ Wakelock/wakereason struct: if D in the first token is set,
+ TODO(adamlesinski): describe wakelock/wakereason struct.
+
+ Event struct: if E in the first token is set,
+ TODO(adamlesinski): describe the event struct.
+
+ History step details struct: if D in the battery level int is set,
+ TODO(adamlesinski): describe the history step details struct.
+
+ Battery charge int: if F in the first token is set, an int representing the battery charge
+ in coulombs follows.
+ */
+
// Part of initial delta int that specifies the time delta.
static final int DELTA_TIME_MASK = 0x7ffff;
static final int DELTA_TIME_LONG = 0x7ffff; // The delta is a following long
static final int DELTA_TIME_INT = 0x7fffe; // The delta is a following int
static final int DELTA_TIME_ABS = 0x7fffd; // Following is an entire abs update.
// Flag in delta int: a new battery level int follows.
- static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
+ static final int DELTA_BATTERY_LEVEL_FLAG = 0x00080000;
// Flag in delta int: a new full state and battery status int follows.
- static final int DELTA_STATE_FLAG = 0x00100000;
+ static final int DELTA_STATE_FLAG = 0x00100000;
// Flag in delta int: a new full state2 int follows.
- static final int DELTA_STATE2_FLAG = 0x00200000;
+ static final int DELTA_STATE2_FLAG = 0x00200000;
// Flag in delta int: contains a wakelock or wakeReason tag.
- static final int DELTA_WAKELOCK_FLAG = 0x00400000;
+ static final int DELTA_WAKELOCK_FLAG = 0x00400000;
// Flag in delta int: contains an event description.
- static final int DELTA_EVENT_FLAG = 0x00800000;
+ static final int DELTA_EVENT_FLAG = 0x00800000;
+ // Flag in delta int: contains a coulomb charge count.
+ static final int DELTA_BATTERY_CHARGE_COULOMBS_FLAG = 0x01000000;
// These upper bits are the frequently changing state bits.
- static final int DELTA_STATE_MASK = 0xff000000;
+ static final int DELTA_STATE_MASK = 0xfe000000;
// These are the pieces of battery state that are packed in to the upper bits of
// the state int that have been packed in to the first delta int. They must fit
- // in DELTA_STATE_MASK.
+ // in STATE_BATTERY_MASK.
+ static final int STATE_BATTERY_MASK = 0xff000000;
static final int STATE_BATTERY_STATUS_MASK = 0x00000007;
static final int STATE_BATTERY_STATUS_SHIFT = 29;
static final int STATE_BATTERY_HEALTH_MASK = 0x00000007;
@@ -2165,6 +2249,12 @@
if (cur.eventCode != HistoryItem.EVENT_NONE) {
firstToken |= DELTA_EVENT_FLAG;
}
+
+ final boolean batteryChargeCoulombsChanged = cur.batteryChargeCoulombs
+ != last.batteryChargeCoulombs;
+ if (batteryChargeCoulombsChanged) {
+ firstToken |= DELTA_BATTERY_CHARGE_COULOMBS_FLAG;
+ }
dest.writeInt(firstToken);
if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken)
+ " deltaTime=" + deltaTime);
@@ -2247,6 +2337,12 @@
mLastHistoryStepDetails = null;
}
mLastHistoryStepLevel = cur.batteryLevel;
+
+ if (batteryChargeCoulombsChanged) {
+ if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryChargeCoulombs="
+ + cur.batteryChargeCoulombs);
+ dest.writeInt(cur.batteryChargeCoulombs);
+ }
}
private int buildBatteryLevelInt(HistoryItem h) {
@@ -2273,7 +2369,7 @@
return ((h.batteryStatus&STATE_BATTERY_STATUS_MASK)<<STATE_BATTERY_STATUS_SHIFT)
| ((h.batteryHealth&STATE_BATTERY_HEALTH_MASK)<<STATE_BATTERY_HEALTH_SHIFT)
| ((plugType&STATE_BATTERY_PLUG_MASK)<<STATE_BATTERY_PLUG_SHIFT)
- | (h.states&(~DELTA_STATE_MASK));
+ | (h.states&(~STATE_BATTERY_MASK));
}
private void computeHistoryStepDetails(final HistoryStepDetails out,
@@ -2412,7 +2508,7 @@
if ((firstToken&DELTA_STATE_FLAG) != 0) {
int stateInt = src.readInt();
- cur.states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~DELTA_STATE_MASK));
+ cur.states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~STATE_BATTERY_MASK));
cur.batteryStatus = (byte)((stateInt>>STATE_BATTERY_STATUS_SHIFT)
& STATE_BATTERY_STATUS_MASK);
cur.batteryHealth = (byte)((stateInt>>STATE_BATTERY_HEALTH_SHIFT)
@@ -2438,7 +2534,7 @@
+ " batteryPlugType=" + cur.batteryPlugType
+ " states=0x" + Integer.toHexString(cur.states));
} else {
- cur.states = (firstToken&DELTA_STATE_MASK) | (cur.states&(~DELTA_STATE_MASK));
+ cur.states = (firstToken&DELTA_STATE_MASK) | (cur.states&(~STATE_BATTERY_MASK));
}
if ((firstToken&DELTA_STATE2_FLAG) != 0) {
@@ -2493,6 +2589,10 @@
} else {
cur.stepDetails = null;
}
+
+ if ((firstToken&DELTA_BATTERY_CHARGE_COULOMBS_FLAG) != 0) {
+ cur.batteryChargeCoulombs = src.readInt();
+ }
}
@Override
@@ -5611,12 +5711,12 @@
mWifiControllerActivity.reset(false);
}
- if (mBsi.mBluetoothActivity != null) {
- mBsi.mBluetoothActivity.reset(false);
+ if (mBluetoothControllerActivity != null) {
+ mBluetoothControllerActivity.reset(false);
}
- if (mBsi.mModemActivity != null) {
- mBsi.mModemActivity.reset(false);
+ if (mModemControllerActivity != null) {
+ mModemControllerActivity.reset(false);
}
mUserCpuTime.reset(false);
@@ -9210,7 +9310,7 @@
public static final int BATTERY_PLUGGED_NONE = 0;
public void setBatteryStateLocked(int status, int health, int plugType, int level,
- int temp, int volt) {
+ int temp, int volt, int chargeCount) {
final boolean onBattery = plugType == BATTERY_PLUGGED_NONE;
final long uptime = mClocks.uptimeMillis();
final long elapsedRealtime = mClocks.elapsedRealtime();
@@ -9254,6 +9354,7 @@
if (mDischargePlugLevel < 0) {
mDischargePlugLevel = level;
}
+
if (onBattery != mOnBattery) {
mHistoryCur.batteryLevel = (byte)level;
mHistoryCur.batteryStatus = (byte)status;
@@ -9261,6 +9362,7 @@
mHistoryCur.batteryPlugType = (byte)plugType;
mHistoryCur.batteryTemperature = (short)temp;
mHistoryCur.batteryVoltage = (char)volt;
+ mHistoryCur.batteryChargeCoulombs = chargeCount;
setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
} else {
boolean changed = false;
@@ -9294,6 +9396,11 @@
mHistoryCur.batteryVoltage = (char)volt;
changed = true;
}
+ if (chargeCount >= (mHistoryCur.batteryChargeCoulombs+10)
+ || chargeCount <= (mHistoryCur.batteryChargeCoulombs-10)) {
+ mHistoryCur.batteryChargeCoulombs = chargeCount;
+ changed = true;
+ }
long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
| (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
| (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 91f003d..9459257 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -77,6 +77,7 @@
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr,
camera_frame_metadata_t *metadata);
virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
+ virtual void postRecordingFrameHandleTimestamp(nsecs_t timestamp, native_handle_t* handle);
void postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata);
void addCallbackBuffer(JNIEnv *env, jbyteArray cbb, int msgType);
void setCallbackMode(JNIEnv *env, bool installed, bool manualMode);
@@ -349,6 +350,11 @@
postData(msgType, dataPtr, NULL);
}
+void JNICameraContext::postRecordingFrameHandleTimestamp(nsecs_t, native_handle_t*) {
+ // This is not needed at app layer. This should not be called because JNICameraContext cannot
+ // start video recording.
+}
+
void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_metadata_t *metadata)
{
jobjectArray obj = NULL;
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index 5c961d9..98d6b24 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -44,7 +44,6 @@
static constexpr int HEADER_FIELD_HUB_HANDLE=2;
static constexpr int HEADER_FIELD_APP_INSTANCE=3;
-
namespace android {
namespace {
@@ -164,9 +163,20 @@
return db.hubInfo.hubs[hubHandle].hub_id;
}
+static int get_app_instance_for_app_id(uint64_t app_id) {
+ auto end = db.appInstances.end();
+ for (auto current = db.appInstances.begin(); current != end; ++current) {
+ if (current->second.appInfo.app_name.id == app_id) {
+ return current->first;
+ }
+ }
+ ALOGD("Cannot find app for app instance %" PRIu64 ".", app_id);
+ return -1;
+}
+
static int set_dest_app(hub_message_t *msg, int id) {
if (!db.appInstances.count(id)) {
- ALOGD("%s: Cannod find app for app instance %d", __FUNCTION__, id);
+ ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
return -1;
}
@@ -301,7 +311,7 @@
}
}
-static int onMessageReceipt(int *header, int headerLen, char *msg, int msgLen) {
+static int onMessageReceipt(uint32_t *header, size_t headerLen, char *msg, size_t msgLen) {
JNIEnv *env;
if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
@@ -396,14 +406,9 @@
int context_hub_callback(uint32_t hubId,
const struct hub_message_t *msg,
void *cookie) {
- int msgHeader[MSG_HEADER_SIZE];
-
if (!msg) {
return -1;
}
-
- msgHeader[HEADER_FIELD_MSG_TYPE] = msg->message_type;
-
if (!sanity_check_cookie(cookie, hubId)) {
ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing",
hubId, cookie);
@@ -411,17 +416,22 @@
return -1;
}
- msgHeader[HEADER_FIELD_HUB_HANDLE] = *(uint32_t*)cookie;
+ uint32_t messageType = msg->message_type;
+ uint32_t hubHandle = *(uint32_t*) cookie;
- if (msgHeader[HEADER_FIELD_MSG_TYPE] < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE &&
- msgHeader[HEADER_FIELD_MSG_TYPE] != 0 ) {
- handle_os_message(msgHeader[HEADER_FIELD_MSG_TYPE],
- msgHeader[HEADER_FIELD_HUB_HANDLE],
- (char *)msg->message,
- msg->message_len);
+ if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
+ handle_os_message(messageType, hubHandle, (char*) msg->message, msg->message_len);
} else {
- onMessageReceipt(msgHeader, sizeof(msgHeader),
- (char *)msg->message, msg->message_len);
+ int appHandle = get_app_instance_for_app_id(msg->app_name.id);
+ if (appHandle < 0) {
+ ALOGE("Filtering out message due to invalid App Instance.");
+ } else {
+ uint32_t msgHeader[MSG_HEADER_SIZE] = {};
+ msgHeader[HEADER_FIELD_MSG_TYPE] = messageType;
+ msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle;
+ msgHeader[HEADER_FIELD_APP_INSTANCE] = appHandle;
+ onMessageReceipt(msgHeader, MSG_HEADER_SIZE, (char*) msg->message, msg->message_len);
+ }
}
return 0;
diff --git a/core/res/res/layout-sw600dp/date_picker_dialog.xml b/core/res/res/layout-sw600dp/date_picker_dialog.xml
index f18485f..5e3ca14 100644
--- a/core/res/res/layout-sw600dp/date_picker_dialog.xml
+++ b/core/res/res/layout-sw600dp/date_picker_dialog.xml
@@ -21,4 +21,5 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:spinnersShown="true"
- android:calendarViewShown="true" />
+ android:calendarViewShown="true"
+ android:datePickerMode="@integer/date_picker_mode" />
diff --git a/core/res/res/layout/date_picker_dialog.xml b/core/res/res/layout/date_picker_dialog.xml
index 64ac1b9..8f36e95 100644
--- a/core/res/res/layout/date_picker_dialog.xml
+++ b/core/res/res/layout/date_picker_dialog.xml
@@ -21,4 +21,5 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:spinnersShown="true"
- android:calendarViewShown="false" />
+ android:calendarViewShown="false"
+ android:datePickerMode="@integer/date_picker_mode" />
diff --git a/core/res/res/layout/time_picker_dialog.xml b/core/res/res/layout/time_picker_dialog.xml
index 30fe910..d1f3902 100644
--- a/core/res/res/layout/time_picker_dialog.xml
+++ b/core/res/res/layout/time_picker_dialog.xml
@@ -21,4 +21,5 @@
android:id="@+id/timePicker"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:timePickerMode="@integer/time_picker_mode" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 3fd75f7..191afe5 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2291,4 +2291,14 @@
<attr name="minimalHeight" format="dimension" />
</declare-styleable>
+ <!-- <code>restrict-update</code> tag restricts system apps from being updated unless the
+ SHA-512 hash equals the specified value.
+ @hide -->
+ <declare-styleable name="AndroidManifestRestrictUpdate" parent="AndroidManifest">
+ <!-- The SHA-512 hash of the only APK that can be used to update a package.
+ <p>NOTE: This is only applicable to system packages.
+ @hide -->
+ <attr name="hash" format="string" />
+ </declare-styleable>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 11df8e5..c91e09f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2715,6 +2715,7 @@
<public type="attr" name="contentInsetEndWithActions" />
<public type="attr" name="numberPickerStyle" />
<public type="attr" name="enableVrMode" />
+ <public type="attr" name="hash" />
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
<public type="style" name="Widget.Material.SeekBar.Discrete" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fb7a19f9..dffab2c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -626,7 +626,7 @@
<!-- Title for the capability of an accessibility service to request touch exploration. -->
<string name="capability_title_canRequestTouchExploration">Turn on Explore by Touch</string>
<!-- Description for the capability of an accessibility service to request touch exploration. -->
- <string name="capability_desc_canRequestTouchExploration">Touched items will be spoken aloud
+ <string name="capability_desc_canRequestTouchExploration">Tapped items will be spoken aloud
and the screen can be explored using gestures.</string>
<!-- Title for the capability of an accessibility service to request enhanced web accessibility. -->
@@ -1708,7 +1708,7 @@
<string name="keyguard_password_enter_pin_prompt">New PIN code</string>
<!-- Displayed as hint in passwordEntry EditText on PasswordUnlockScreen [CHAR LIMIT=30]-->
- <string name="keyguard_password_entry_touch_hint"><font size="17">Touch to type password</font></string>
+ <string name="keyguard_password_entry_touch_hint"><font size="17">Tap to type password</font></string>
<!-- Instructions telling the user to enter their text password to unlock the keyguard.
Displayed in one line in a large font. -->
@@ -2577,7 +2577,7 @@
is running</string>
<!-- [CHAR LIMIT=NONE] Stub notification text for an app running a service that has provided
a bad bad notification for itself. -->
- <string name="app_running_notification_text">Touch for more information
+ <string name="app_running_notification_text">Tap for more information
or to stop the app.</string>
<!-- Preference framework strings. -->
@@ -2761,7 +2761,7 @@
<string name="heavy_weight_notification"><xliff:g id="app">%1$s</xliff:g> running</string>
<!-- Notification details to tell the user that a heavy-weight application is running. -->
- <string name="heavy_weight_notification_detail">Touch to switch to app</string>
+ <string name="heavy_weight_notification_detail">Tap to switch to app</string>
<!-- Title of dialog prompting whether user wants to switch between heavy-weight apps. -->
<string name="heavy_weight_switcher_title">Switch apps?</string>
@@ -2782,7 +2782,7 @@
<!-- Notification details to tell the user that a process has exceeded its memory limit. -->
<string name="dump_heap_notification_detail">Heap dump has been collected;
- touch to share</string>
+ tap to share</string>
<!-- Title of dialog prompting the user to share a heap dump. -->
<string name="dump_heap_title">Share heap dump?</string>
@@ -2865,7 +2865,7 @@
<string name="wifi_no_internet">Wi-Fi has no Internet access</string>
<!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
- <string name="wifi_no_internet_detailed">Touch for options</string>
+ <string name="wifi_no_internet_detailed">Tap for options</string>
<!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems. This is the notification's title / ticker. -->
<string name="wifi_watchdog_network_disabled">Couldn\'t connect to Wi-Fi</string>
@@ -2887,7 +2887,7 @@
<string name="wifi_p2p_turnon_message">Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot.</string>
<string name="wifi_p2p_failed_message">Couldn\'t start Wi-Fi Direct.</string>
<string name="wifi_p2p_enabled_notification_title">Wi-Fi Direct is on</string>
- <string name="wifi_p2p_enabled_notification_message">Touch for settings</string>
+ <string name="wifi_p2p_enabled_notification_message">Tap for settings</string>
<string name="accept">Accept</string>
<string name="decline">Decline</string>
@@ -2995,12 +2995,12 @@
<!-- USB_PREFERENCES: Notification for when a USB accessory is attached. This is the title -->
<string name="usb_accessory_notification_title">Connected to a USB accessory</string>
<!-- See USB_PREFERENCES. This is the message. -->
- <string name="usb_notification_message">Touch for more options.</string>
+ <string name="usb_notification_message">Tap for more options.</string>
<!-- Title of notification shown when ADB is actively connected to the phone. -->
<string name="adb_active_notification_title">USB debugging connected</string>
<!-- Message of notification shown when ADB is actively connected to the phone. -->
- <string name="adb_active_notification_message">Touch to disable USB debugging.</string>
+ <string name="adb_active_notification_message">Tap to disable USB debugging.</string>
<!-- Title of notification shown to indicate that bug report is being collected. -->
<string name="taking_remote_bugreport_notification_title">Taking bug report\u2026</string>
@@ -3057,12 +3057,12 @@
<!-- Notification title when external media is unmountable (corrupt) [CHAR LIMIT=30] -->
<string name="ext_media_unmountable_notification_title">Corrupted <xliff:g id="name" example="SD card">%s</xliff:g></string>
<!-- Notification body when external media is unmountable (corrupt) [CHAR LIMIT=NONE] -->
- <string name="ext_media_unmountable_notification_message"><xliff:g id="name" example="SD card">%s</xliff:g> is corrupt. Touch to fix.</string>
+ <string name="ext_media_unmountable_notification_message"><xliff:g id="name" example="SD card">%s</xliff:g> is corrupt. Tap to fix.</string>
<!-- Notification title when external media is unsupported [CHAR LIMIT=30] -->
<string name="ext_media_unsupported_notification_title">Unsupported <xliff:g id="name" example="SD card">%s</xliff:g></string>
<!-- Notification body when external media is unsupported [CHAR LIMIT=NONE] -->
- <string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Touch to set up in a supported format.</string>
+ <string name="ext_media_unsupported_notification_message">This device doesn\u2019t support this <xliff:g id="name" example="SD card">%s</xliff:g>. Tap to set up in a supported format.</string>
<!-- Notification title when external media is unsafely removed [CHAR LIMIT=30] -->
<string name="ext_media_badremoval_notification_title"><xliff:g id="name" example="SD card">%s</xliff:g> unexpectedly removed</string>
@@ -3148,7 +3148,7 @@
<string name="permdesc_requestInstallPackages">Allows an application to request installation of packages.</string>
<!-- Shown in the tutorial for tap twice for zoom control. -->
- <string name="tutorial_double_tap_to_zoom_message_short">Touch twice for zoom control</string>
+ <string name="tutorial_double_tap_to_zoom_message_short">Tap twice for zoom control</string>
<!-- Shown in gadget hosts (e.g. the home screen) when there was an error inflating
@@ -3235,9 +3235,9 @@
<!-- The title of the notification when VPN is active with an application name. -->
<string name="vpn_title_long">VPN is activated by <xliff:g id="app" example="FooVPN client">%s</xliff:g></string>
<!-- The text of the notification when VPN is active. -->
- <string name="vpn_text">Touch to manage the network.</string>
+ <string name="vpn_text">Tap to manage the network.</string>
<!-- The text of the notification when VPN is active with a session name. -->
- <string name="vpn_text_long">Connected to <xliff:g id="session" example="office">%s</xliff:g>. Touch to manage the network.</string>
+ <string name="vpn_text_long">Connected to <xliff:g id="session" example="office">%s</xliff:g>. Tap to manage the network.</string>
<!-- Notification title when connecting to lockdown VPN. -->
<string name="vpn_lockdown_connecting">Always-on VPN connecting\u2026</string>
@@ -3246,7 +3246,7 @@
<!-- Notification title when error connecting to lockdown VPN. -->
<string name="vpn_lockdown_error">Always-on VPN error</string>
<!-- Notification body that indicates user can touch to configure lockdown VPN connection. -->
- <string name="vpn_lockdown_config">Touch to configure</string>
+ <string name="vpn_lockdown_config">Tap to configure</string>
<!-- Localized strings for WebView -->
<!-- Label for button in a WebView that will open a chooser to choose a file to upload -->
@@ -3261,12 +3261,12 @@
<!-- Strings for car mode notification -->
<!-- Shown when car mode is enabled -->
<string name="car_mode_disable_notification_title">Car mode enabled</string>
- <string name="car_mode_disable_notification_message">Touch to exit car mode.</string>
+ <string name="car_mode_disable_notification_message">Tap to exit car mode.</string>
<!-- Strings for tethered notification -->
<!-- Shown when the device is tethered -->
<string name="tethered_notification_title">Tethering or hotspot active</string>
- <string name="tethered_notification_message">Touch to set up.</string>
+ <string name="tethered_notification_message">Tap to set up.</string>
<!-- Strings for possible PreferenceActivity Back/Next buttons -->
<string name="back_button_label">Back</string>
@@ -3352,7 +3352,7 @@
<!-- Description of the button to decrease the NumberPicker value. [CHAR LIMIT=NONE] -->
<string name="number_picker_decrement_button">Decrease</string>
<!-- Description of the tap and hold action to get into scroll mode in NumberPicker. [CHAR LIMIT=NONE] -->
- <string name="number_picker_increment_scroll_mode"><xliff:g id="value" example="3">%s</xliff:g> touch and hold.</string>
+ <string name="number_picker_increment_scroll_mode"><xliff:g id="value" example="3">%s</xliff:g> touch & hold.</string>
<!-- Description of the scrolling action in NumberPicker. [CHAR LIMIT=NONE] -->
<string name="number_picker_increment_scroll_action">Slide up to increase and down to decrease.</string>
@@ -3470,7 +3470,7 @@
<!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
<string name="data_usage_warning_title">Data usage warning</string>
<!-- Notification body when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
- <string name="data_usage_warning_body">Touch to view usage and settings.</string>
+ <string name="data_usage_warning_body">Tap to view usage and settings.</string>
<!-- Notification title when 2G-3G data usage has exceeded limit threshold, and has been disabled. [CHAR LIMIT=32] -->
<string name="data_usage_3g_limit_title">2G-3G data limit reached</string>
@@ -3497,7 +3497,7 @@
<!-- Notification title when background data usage is limited. [CHAR LIMIT=32] -->
<string name="data_usage_restricted_title">Background data restricted</string>
<!-- Notification body when background data usage is limited. [CHAR LIMIT=32] -->
- <string name="data_usage_restricted_body">Touch to remove restriction.</string>
+ <string name="data_usage_restricted_body">Tap to remove restriction.</string>
<!-- SSL Certificate dialogs -->
<!-- Title for an SSL Certificate dialog -->
@@ -4080,9 +4080,9 @@
<string name="date_picker_day_typeface">sans-serif-medium</string>
<!-- Notify use that they are in Lock-to-app -->
- <string name="lock_to_app_toast">To unpin this screen, touch and hold Back.</string>
+ <string name="lock_to_app_toast">To unpin this screen, touch & hold Back.</string>
<!-- Notify use that they are in Lock-to-app in accessibility mode -->
- <string name="lock_to_app_toast_accessible">To unpin this screen, touch and hold Overview.</string>
+ <string name="lock_to_app_toast_accessible">To unpin this screen, touch & hold Overview.</string>
<!-- Notify user that they are locked in lock-to-app mode -->
<string name="lock_to_app_toast_locked">App is pinned: Unpinning isn\'t allowed on this device.</string>
<!-- Starting lock-to-app indication. -->
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 8a33406..6752e3c 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -660,7 +660,7 @@
</style>
<style name="Widget.Material.TimePicker">
- <item name="timePickerMode">@integer/time_picker_mode</item>
+ <item name="timePickerMode">clock</item>
<item name="legacyLayout">@layout/time_picker_legacy_material</item>
<!-- Attributes for new-style TimePicker. -->
<item name="internalLayout">@layout/time_picker_material</item>
@@ -674,7 +674,7 @@
</style>
<style name="Widget.Material.DatePicker">
- <item name="datePickerMode">@integer/date_picker_mode</item>
+ <item name="datePickerMode">calendar</item>
<item name="legacyLayout">@layout/date_picker_legacy_holo</item>
<item name="calendarViewShown">true</item>
<!-- Attributes for new-style DatePicker. -->
diff --git a/core/res/res/values/themes_holo.xml b/core/res/res/values/themes_holo.xml
index 34c89fc..677051a 100644
--- a/core/res/res/values/themes_holo.xml
+++ b/core/res/res/values/themes_holo.xml
@@ -466,6 +466,9 @@
<item name="editTextColor">?attr/textColorPrimary</item>
<item name="editTextBackground">@drawable/edit_text_holo_light</item>
+ <item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item</item>
+ <item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container</item>
+ <item name="textEditSuggestionHighlightStyle">@style/TextAppearance.Holo.SuggestionHighlight</item>
<item name="candidatesTextStyleSpans">@string/candidates_style</item>
diff --git a/docs/html/preview/behavior-changes.jd b/docs/html/preview/behavior-changes.jd
index 0cf5bc9..7c8bfe8 100644
--- a/docs/html/preview/behavior-changes.jd
+++ b/docs/html/preview/behavior-changes.jd
@@ -215,11 +215,17 @@
<ul>
<li>
- Private files’ file permissions can no longer be relaxed by the owner, and
- an attempt to do so using
+ Private files’ file permissions should no longer be relaxed by the owner,
+ and an attempt to do so using
{@link android.content.Context#MODE_WORLD_READABLE} and/or
{@link android.content.Context#MODE_WORLD_WRITEABLE}, will trigger a
{@link java.lang.SecurityException}.
+ <p class="note">
+ <strong>Note:</strong> As of yet, this restriction is not fully enforced.
+ Apps may still modify permissions to their private directory using
+ native APIs or the {@link java.io.File File} API. However, we strongly
+ discourage relaxing the permissions to the private directory.
+ </p>
</li>
<li>
Passing <code>file://</code> URIs outside the package domain may leave the
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 94b7e55..1e7761b 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -55,7 +55,7 @@
<!-- start studio download modal -->
-<div data-modal="studio_tos" class="dac-modal" id="langform">
+<div data-modal="studio_tos" class="dac-modal" id="studio_tos">
<div class="dac-modal-container">
<div class="dac-modal-window">
<header class="dac-modal-header">
@@ -534,4 +534,3 @@
</div>
</section>
-
diff --git a/graphics/java/android/view/PixelCopy.java b/graphics/java/android/view/PixelCopy.java
index 95c930c..29bf963 100644
--- a/graphics/java/android/view/PixelCopy.java
+++ b/graphics/java/android/view/PixelCopy.java
@@ -123,6 +123,9 @@
public static void request(@NonNull Surface source, @NonNull Bitmap dest,
@NonNull OnPixelCopyFinishedListener listener, @NonNull Handler listenerThread) {
validateBitmapDest(dest);
+ if (!source.isValid()) {
+ throw new IllegalArgumentException("Surface isn't valid, source.isValid() == false");
+ }
// TODO: Make this actually async and fast and cool and stuff
int result = ThreadedRenderer.copySurfaceInto(source, dest);
listenerThread.post(new Runnable() {
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index fdbe76a..0a8e3f3 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -471,18 +471,19 @@
return *this;
}
-GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture) {
+GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
mOutGlop->fill.texture = { &texture,
GL_TEXTURE_EXTERNAL_OES, GL_LINEAR, GL_CLAMP_TO_EDGE,
- nullptr };
+ &textureTransform };
setFill(SK_ColorWHITE, 1.0f, SkXfermode::kSrc_Mode, Blend::ModeOrderSwap::NoSwap,
nullptr, nullptr);
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+ mDescription.hasTextureTransform = true;
return *this;
}
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index b6c186d..a9dd56f 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -73,7 +73,7 @@
// TODO: Texture should probably know and own its target.
// setFillLayer() forces it to GL_TEXTURE which isn't always correct.
// Similarly setFillLayer normally forces its own wrap & filter mode
- GlopBuilder& setFillExternalTexture(Texture& texture);
+ GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform);
GlopBuilder& setTransform(const Snapshot& snapshot, const int transformFlags) {
return setTransform(*snapshot.transform, transformFlags);
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index 36007cd..9cde5d6 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -236,6 +236,8 @@
static const Matrix4& identity();
+ void invalidateType() { mType = kTypeUnknown; }
+
private:
mutable uint8_t mType;
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 49596e1..55f823d 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -101,7 +101,10 @@
// Setup the source
sp<GraphicBuffer> sourceBuffer;
sp<Fence> sourceFence;
- status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence);
+ Matrix4 texTransform;
+ status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence,
+ texTransform.data);
+ texTransform.invalidateType();
if (err != NO_ERROR) {
ALOGW("Failed to get last queued buffer, error = %d", err);
return CopyResult::UnknownError;
@@ -163,8 +166,8 @@
Glop glop;
GlopBuilder(renderState, caches, &glop)
.setRoundRectClipState(nullptr)
- .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
- .setFillExternalTexture(sourceTexture)
+ .setMeshTexturedUnitQuad(nullptr)
+ .setFillExternalTexture(sourceTexture, texTransform)
.setTransform(Matrix4::identity(), TransformFlags::None)
.setModelViewMapUnitToRect(destRect)
.build();
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index a8c2652..b9ed269 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1247,7 +1247,8 @@
private Range<Double> estimateFrameRatesFor(int width, int height) {
Size size = findClosestSize(width, height);
Range<Long> range = mMeasuredFrameRates.get(size);
- Double ratio = (double)(size.getWidth() * size.getHeight()) / (width * height);
+ Double ratio = getBlockCount(size.getWidth(), size.getHeight())
+ / (double)Math.max(getBlockCount(width, height), 1);
return Range.create(range.getLower() * ratio, range.getUpper() * ratio);
}
@@ -2744,6 +2745,7 @@
public static final int DolbyVisionProfileDvheDtr = 0x10;
public static final int DolbyVisionProfileDvheStn = 0x20;
public static final int DolbyVisionProfileDvheDth = 0x40;
+ public static final int DolbyVisionProfileDvheDtb = 0x80;
// from OMX_VIDEO_DOLBYVISIONLEVELTYPE
public static final int DolbyVisionLevelHd24 = 0x1;
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 346f083..93c595f 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -46,7 +46,8 @@
* <tr><td>{@link #KEY_HEIGHT}</td><td>Integer</td><td></td></tr>
* <tr><td>{@link #KEY_COLOR_FORMAT}</td><td>Integer</td><td>set by the user
* for encoders, readable in the output format of decoders</b></td></tr>
- * <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td><b>encoder-only</b></td></tr>
+ * <tr><td>{@link #KEY_FRAME_RATE}</td><td>Integer or Float</td><td>required for <b>encoders</b>,
+ * optional for <b>decoders</b></td></tr>
* <tr><td>{@link #KEY_CAPTURE_RATE}</td><td>Integer</td><td></td></tr>
* <tr><td>{@link #KEY_I_FRAME_INTERVAL}</td><td>Integer</td><td><b>encoder-only</b></td></tr>
* <tr><td>{@link #KEY_INTRA_REFRESH_PERIOD}</td><td>Integer</td><td><b>encoder-only</b>, optional</td></tr>
@@ -197,7 +198,19 @@
/**
* A key describing the frame rate of a video format in frames/sec.
- * The associated value is an integer or a float.
+ * The associated value is normally an integer when the value is used by the platform,
+ * but video codecs also accept float configuration values.
+ * Specifically, {@link MediaExtractor#getTrackFormat MediaExtractor} provides an integer
+ * value corresponding to the frame rate information of the track if specified and non-zero.
+ * Otherwise, this key is not present. {@link MediaCodec#configure MediaCodec} accepts both
+ * float and integer values. This represents the desired operating frame rate if the
+ * {@link #KEY_OPERATING_RATE} is not present and {@link #KEY_PRIORITY} is {@code 0}
+ * (realtime). For video encoders this value corresponds to the intended frame rate,
+ * although encoders are expected
+ * to support variable frame rate based on {@link MediaCodec.BufferInfo#presentationTimeUs
+ * buffer timestamp}. This key is not used in the {@code MediaCodec}
+ * {@link MediaCodec#getInputFormat input}/{@link MediaCodec#getOutputFormat output} formats,
+ * nor by {@link MediaMuxer#addTrack MediaMuxer}.
*/
public static final String KEY_FRAME_RATE = "frame-rate";
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index ed6fdb7..2da4d6a 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -57,7 +57,7 @@
<activity
android:name=".ui.PrintActivity"
- android:configChanges="screenSize|smallestScreenSize|orientation|locale|keyboard|keyboardHidden|fontScale|uiMode|layoutDirection"
+ android:configChanges="mnc|mnc|touchscreen|navigation|screenLayout|screenSize|smallestScreenSize|orientation|locale|keyboard|keyboardHidden|fontScale|uiMode|layoutDirection|density"
android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE"
android:theme="@style/Theme.PrintActivity">
<intent-filter>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
index bb35917..999d82d 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java
@@ -510,7 +510,12 @@
public void destroy() {
if (mBoundToService) {
mBoundToService = false;
- mContext.unbindService(AsyncRenderer.this);
+ try {
+ mContext.unbindService(AsyncRenderer.this);
+ } catch (IllegalArgumentException e) {
+ // Service might have been forcefully unbound in onDestroy()
+ Log.e(LOG_TAG, "Cannot unbind service", e);
+ }
}
mPageContentCache.invalidate();
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index c411186..cc0b4ca 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -268,7 +268,7 @@
new Runnable() {
@Override
public void run() {
- if (isFinishing()) {
+ if (isFinishing() || isDestroyed()) {
// onPause might have not been able to cancel the job, see PrintActivity#onPause
// To be sure, cancel the job again. Double canceling does no harm.
mSpoolerProvider.getSpooler().setPrintJobState(mPrintJob.getId(),
@@ -288,12 +288,8 @@
// the first batch of results which will be delivered
// after reading historical data. This should be pretty
// fast, so just wait before showing the UI.
- mPrinterRegistry = new PrinterRegistry(PrintActivity.this,
- new Runnable() {
- @Override
- public void run() {
- onPrinterRegistryReady(documentAdapter);
- }
+ mPrinterRegistry = new PrinterRegistry(PrintActivity.this, () -> {
+ (new Handler(getMainLooper())).post(() -> onPrinterRegistryReady(documentAdapter));
}, LOADER_ID_PRINT_REGISTRY, LOADER_ID_PRINT_REGISTRY_INT);
}
@@ -324,7 +320,8 @@
// If we are finishing or we are in a state that we do not need any
// data from the printing app, then no need to finish.
- if (isFinishing() || (isFinalState(mState) && !mPrintedDocument.isUpdating())) {
+ if (isFinishing() || isDestroyed() ||
+ (isFinalState(mState) && !mPrintedDocument.isUpdating())) {
return;
}
setState(STATE_PRINT_CANCELED);
@@ -622,6 +619,17 @@
}
@Override
+ protected void onDestroy() {
+ if (mPrintedDocument != null) {
+ mPrintedDocument.cancel(true);
+ }
+
+ doFinish();
+
+ super.onDestroy();
+ }
+
+ @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case ACTIVITY_REQUEST_CREATE_FILE: {
@@ -964,7 +972,7 @@
}
private void ensureProgressUiShown() {
- if (isFinishing()) {
+ if (isFinishing() || isDestroyed()) {
return;
}
if (mUiState != UI_STATE_PROGRESS) {
@@ -976,7 +984,7 @@
}
private void ensurePreviewUiShown() {
- if (isFinishing()) {
+ if (isFinishing() || isDestroyed()) {
return;
}
if (mUiState != UI_STATE_PREVIEW) {
@@ -987,7 +995,7 @@
}
private void ensureErrorUiShown(CharSequence message, int action) {
- if (isFinishing()) {
+ if (isFinishing() || isDestroyed()) {
return;
}
if (mUiState != UI_STATE_ERROR) {
@@ -1267,6 +1275,7 @@
mPageRangeTitle = (TextView) findViewById(R.id.page_range_title);
mPageRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
mPageRangeEditText.setVisibility(View.INVISIBLE);
+ mPageRangeTitle.setVisibility(View.INVISIBLE);
mPageRangeEditText.setOnFocusChangeListener(mSelectAllOnFocusListener);
mPageRangeEditText.addTextChangedListener(new RangeTextWatcher());
@@ -1353,7 +1362,7 @@
@Override
public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
- if (!isFinishing()) {
+ if (!(isFinishing() || isDestroyed())) {
onLoadFinished(loader, null);
}
}
@@ -2036,7 +2045,9 @@
mSpoolerProvider.destroy();
}
- setState(mProgressMessageController.cancel());
+ if (mProgressMessageController != null) {
+ setState(mProgressMessageController.cancel());
+ }
if (mState != STATE_INITIALIZING) {
mPrintedDocument.finish();
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 74c98e4..efa34ff 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -421,8 +421,6 @@
<string name="wifi_aggressive_handover">Aggressive Wi\u2011Fi to Cellular handover</string>
<!-- Setting Checkbox title whether to enable WiFi Scanning in the presence of traffic. [CHAR LIMIT=80] -->
<string name="wifi_allow_scan_with_traffic">Always allow Wi\u2011Fi Roam Scans</string>
- <!-- Setting Checkbox title whether to enable WiFi Scanning in the presence of traffic. [CHAR LIMIT=80] -->
- <string name="legacy_dhcp_client">Use legacy DHCP client</string>
<!-- Setting Checkbox title whether to always keep cellular data active. [CHAR LIMIT=80] -->
<string name="mobile_data_always_on">Cellular data always active</string>
<!-- Setting Checkbox title for disabling Bluetooth absolute volume -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index bcbc6ac..bf75046 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -52,7 +52,7 @@
protected static final boolean DEBUG_TIMING = false;
private static final String TAG = "SettingsDrawerActivity";
- static final String EXTRA_SHOW_MENU = "show_drawer_menu";
+ public static final String EXTRA_SHOW_MENU = "show_drawer_menu";
private static List<DashboardCategory> sDashboardCategories;
private static HashMap<Pair<String, String>, Tile> sTileCache;
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index f0ae1c9..be05a3a 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -18,6 +18,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
+ android:clipToPadding="false"
android:id="@+id/volume_dialog_row"
android:paddingEnd="@dimen/volume_button_size" >
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 716185f..b2aa966 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -106,6 +106,7 @@
public void setHost(QSTileHost host) {
mHost = host;
mPhoneStatusBar = host.getPhoneStatusBar();
+ mTileAdapter.setHost(host);
}
public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 41b49d8..ec0eefb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -81,6 +81,7 @@
private Holder mCurrentDrag;
private boolean mAccessibilityMoving;
private int mAccessibilityFromIndex;
+ private QSTileHost mHost;
public TileAdapter(Context context) {
mContext = context;
@@ -88,6 +89,10 @@
mItemTouchHelper = new ItemTouchHelper(mCallbacks);
}
+ public void setHost(QSTileHost host) {
+ mHost = host;
+ }
+
@Override
public long getItemId(int position) {
return mTiles.get(position) != null ? mAllTiles.indexOf(mTiles.get(position))
@@ -108,7 +113,7 @@
newSpecs.add(mTiles.get(i).spec);
}
host.changeTiles(mCurrentSpecs, newSpecs);
- setTileSpecs(newSpecs);
+ mCurrentSpecs = newSpecs;
}
public void setTileSpecs(List<String> currentSpecs) {
@@ -285,6 +290,7 @@
move(mAccessibilityFromIndex, position, v);
notifyItemChanged(mAccessibilityFromIndex);
notifyItemMoved(mAccessibilityFromIndex, position);
+ saveSpecs(mHost);
}
private void showAccessibilityDialog(final int position, final View v) {
@@ -373,6 +379,7 @@
fromLabel, (to + 1));
}
v.announceForAccessibility(announcement);
+ saveSpecs(mHost);
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 54dd015..23a3ca1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -40,9 +40,11 @@
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
import com.android.systemui.statusbar.phone.QSTileHost;
+import libcore.util.Objects;
-public class CustomTile extends QSTile<QSTile.State> {
+public class CustomTile extends QSTile<QSTile.State> implements TileChangeListener {
public static final String PREFIX = "custom(";
private static final boolean DEBUG = false;
@@ -58,7 +60,7 @@
private final IQSTileService mService;
private final TileServiceManager mServiceManager;
private final int mUser;
- private final android.graphics.drawable.Icon mDefaultIcon;
+ private android.graphics.drawable.Icon mDefaultIcon;
private boolean mListening;
private boolean mBound;
@@ -71,21 +73,10 @@
mComponent = ComponentName.unflattenFromString(action);
mServiceManager = host.getTileServices().getTileWrapper(this);
mService = mServiceManager.getTileService();
+ mServiceManager.setTileChangeListener(this);
mTile = new Tile(mComponent);
mUser = ActivityManager.getCurrentUser();
- android.graphics.drawable.Icon defaultIcon;
- try {
- PackageManager pm = mContext.getPackageManager();
- ServiceInfo info = pm.getServiceInfo(mComponent,
- PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
- defaultIcon = info.icon != 0 ? android.graphics.drawable.Icon
- .createWithResource(mComponent.getPackageName(), info.icon) : null;
- mTile.setIcon(defaultIcon);
- mTile.setLabel(info.loadLabel(pm));
- } catch (Exception e) {
- defaultIcon = null;
- }
- mDefaultIcon = defaultIcon;
+ setTileIcon();
try {
mService.setQSTile(mTile);
} catch (RemoteException e) {
@@ -93,6 +84,57 @@
}
}
+ private void setTileIcon() {
+ try {
+ PackageManager pm = mContext.getPackageManager();
+ ServiceInfo info = pm.getServiceInfo(mComponent,
+ PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+ // Update the icon if its not set or is the default icon.
+ boolean updateIcon = mTile.getIcon() == null
+ || iconEquals(mTile.getIcon(), mDefaultIcon);
+ mDefaultIcon = info.icon != 0 ? android.graphics.drawable.Icon
+ .createWithResource(mComponent.getPackageName(), info.icon) : null;
+ if (updateIcon) {
+ mTile.setIcon(mDefaultIcon);
+ }
+ // Update the label if there is no label.
+ if (mTile.getLabel() == null) {
+ mTile.setLabel(info.loadLabel(pm));
+ }
+ } catch (Exception e) {
+ mDefaultIcon = null;
+ }
+ }
+
+ /**
+ * Compare two icons, only works for resources.
+ */
+ private boolean iconEquals(android.graphics.drawable.Icon icon1,
+ android.graphics.drawable.Icon icon2) {
+ if (icon1 == icon2) {
+ return true;
+ }
+ if (icon1 == null || icon2 == null) {
+ return false;
+ }
+ if (icon1.getType() != android.graphics.drawable.Icon.TYPE_RESOURCE
+ || icon2.getType() != android.graphics.drawable.Icon.TYPE_RESOURCE) {
+ return false;
+ }
+ if (icon1.getResId() != icon2.getResId()) {
+ return false;
+ }
+ if (!Objects.equal(icon1.getResPackage(), icon2.getResPackage())) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void onTileChanged(ComponentName tile) {
+ setTileIcon();
+ }
+
@Override
public boolean isAvailable() {
return mDefaultIcon != null;
@@ -136,6 +178,8 @@
mListening = listening;
try {
if (listening) {
+ setTileIcon();
+ refreshState();
if (!mServiceManager.isActiveTile()) {
mServiceManager.setBindRequested(true);
mService.onStartListening();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 5903218..212f179 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -80,6 +80,7 @@
boolean mReceiverRegistered;
private IQSService mService;
private boolean mUnbindImmediate;
+ private TileChangeListener mChangeListener;
public TileLifecycleManager(Handler handler, Context context, Intent intent, UserHandle user) {
mContext = context;
@@ -168,7 +169,7 @@
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.d(TAG, "onServiceDisconnected " + name);
- mWrapper = null;
+ handleDeath();
}
private void handlePendingMessages() {
@@ -279,6 +280,10 @@
mReceiverRegistered = false;
}
+ public void setTileChangeListener(TileChangeListener changeListener) {
+ mChangeListener = changeListener;
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "onReceive: " + intent);
@@ -289,6 +294,9 @@
return;
}
}
+ if (Intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction()) && mChangeListener != null) {
+ mChangeListener.onTileChanged(mIntent.getComponent());
+ }
stopPackageListening();
if (mBound) {
// Trying to bind again will check the state of the package before bothering to bind.
@@ -401,4 +409,8 @@
if (DEBUG) Log.d(TAG, "binderDeath");
handleDeath();
}
+
+ public interface TileChangeListener {
+ void onTileChanged(ComponentName tile);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
index f34df75..82a5622 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -27,6 +27,7 @@
import android.service.quicksettings.IQSTileService;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
+import com.android.systemui.qs.external.TileLifecycleManager.TileChangeListener;
import libcore.util.Objects;
/**
@@ -81,6 +82,10 @@
new UserHandle(ActivityManager.getCurrentUser()), filter, null, mHandler);
}
+ public void setTileChangeListener(TileChangeListener changeListener) {
+ mStateManager.setTileChangeListener(changeListener);
+ }
+
public boolean isActiveTile() {
return mStateManager.isActiveTile();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 6d76763e..ce0163e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -327,7 +327,14 @@
public static String contentDescForNotification(Context c, Notification n) {
Notification.Builder builder = Notification.Builder.recoverBuilder(c, n);
String appName = builder.loadHeaderAppName();
+
+ CharSequence title = n.extras.getString(Notification.EXTRA_TITLE);
CharSequence ticker = n.tickerText;
- return c.getString(R.string.accessibility_desc_notification_icon, appName, ticker);
+
+ CharSequence desc = !TextUtils.isEmpty(ticker) ? ticker
+ : !TextUtils.isEmpty(title) ? title : "";
+
+ return c.getString(R.string.accessibility_desc_notification_icon, appName, desc);
}
+
}
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 f7ecd61..6fc32de 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -409,6 +409,9 @@
if (mKeyguardBottomArea != null) {
mKeyguardBottomArea.setUserSetupComplete(mUserSetup);
}
+ if (mNetworkController != null) {
+ mNetworkController.setUserSetupComplete(mUserSetup);
+ }
}
if (mIconPolicy != null) {
mIconPolicy.setCurrentUserSetup(mUserSetup);
@@ -838,6 +841,7 @@
}
});
mNetworkController = new NetworkControllerImpl(mContext, mHandlerThread.getLooper());
+ mNetworkController.setUserSetupComplete(mUserSetup);
mHotspotController = new HotspotControllerImpl(mContext);
mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper());
mSecurityController = new SecurityControllerImpl(mContext);
@@ -1437,7 +1441,11 @@
public void removeNotification(String key, RankingMap ranking) {
boolean deferRemoval = false;
if (mHeadsUpManager.isHeadsUp(key)) {
- deferRemoval = !mHeadsUpManager.removeNotification(key);
+ // A cancel() in repsonse to a remote input shouldn't be delayed, as it makes the
+ // sending look longer than it takes.
+ boolean ignoreEarliestRemovalTime = mRemoteInputController.isSpinning(key)
+ && !FORCE_REMOTE_INPUT_HISTORY;
+ deferRemoval = !mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime);
}
if (key.equals(mMediaNotificationKey)) {
clearCurrentMediaNotification();
@@ -2364,7 +2372,7 @@
if (wasHeadsUp) {
if (!shouldPeek) {
// We don't want this to be interrupting anymore, lets remove it
- mHeadsUpManager.removeNotification(key);
+ mHeadsUpManager.removeNotification(key, false /* ignoreEarliestRemovalTime */);
} else {
mHeadsUpManager.updateNotification(entry, alertAgain);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 52fb470..d3ae549 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -264,9 +264,9 @@
* @return true if the notification was removed and false if it still needs to be kept around
* for a bit since it wasn't shown long enough
*/
- public boolean removeNotification(String key) {
+ public boolean removeNotification(String key, boolean ignoreEarliestRemovalTime) {
if (DEBUG) Log.v(TAG, "remove");
- if (wasShownLongEnough(key)) {
+ if (wasShownLongEnough(key) || ignoreEarliestRemovalTime) {
releaseImmediately(key);
return true;
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 80dcfb6..83e25eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -114,6 +114,11 @@
notifyListenersIfNecessary();
}
+ public void setUserSetupComplete(boolean userSetup) {
+ mCurrentState.userSetup = userSetup;
+ notifyListenersIfNecessary();
+ }
+
@Override
public void updateConnectivity(BitSet connectedTransports, BitSet validatedTransports) {
boolean isValidated = validatedTransports.get(mTransportType);
@@ -204,11 +209,13 @@
String contentDescription = getStringIfExists(getContentDescription());
String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
+ final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
+ && mCurrentState.userSetup;
- // Show icon in QS when we are connected or need to show roaming.
+ // Show icon in QS when we are connected or need to show roaming or data is disabled.
boolean showDataIcon = mCurrentState.dataConnected
|| mCurrentState.iconGroup == TelephonyIcons.ROAMING
- || mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
+ || dataDisabled;
IconState statusIcon = new IconState(mCurrentState.enabled && !mCurrentState.airplaneMode,
getCurrentIconId(), contentDescription);
@@ -230,7 +237,7 @@
&& mCurrentState.activityOut;
showDataIcon &= mCurrentState.isDefault
|| mCurrentState.iconGroup == TelephonyIcons.ROAMING
- || mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
+ || dataDisabled;
int typeIcon = showDataIcon ? icons.mDataType : 0;
callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
@@ -511,6 +518,7 @@
boolean airplaneMode;
boolean carrierNetworkChangeMode;
boolean isDefault;
+ boolean userSetup;
@Override
public void copyFrom(State s) {
@@ -524,6 +532,7 @@
isEmergency = state.isEmergency;
airplaneMode = state.airplaneMode;
carrierNetworkChangeMode = state.carrierNetworkChangeMode;
+ userSetup = state.userSetup;
}
@Override
@@ -537,7 +546,9 @@
builder.append("isDefault=").append(isDefault).append(',');
builder.append("isEmergency=").append(isEmergency).append(',');
builder.append("airplaneMode=").append(airplaneMode).append(',');
- builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode);
+ builder.append("carrierNetworkChangeMode=").append(carrierNetworkChangeMode)
+ .append(',');
+ builder.append("userSetup=").append(userSetup);
}
@Override
@@ -550,6 +561,7 @@
&& ((MobileState) o).isEmergency == isEmergency
&& ((MobileState) o).airplaneMode == airplaneMode
&& ((MobileState) o).carrierNetworkChangeMode == carrierNetworkChangeMode
+ && ((MobileState) o).userSetup == userSetup
&& ((MobileState) o).isDefault == isDefault;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 40dacd3..a633241 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -130,6 +130,7 @@
@VisibleForTesting
ServiceState mLastServiceState;
+ private boolean mUserSetup;
/**
* Construct this controller object and register for updates.
@@ -490,6 +491,7 @@
MobileSignalController controller = new MobileSignalController(mContext, mConfig,
mHasMobileDataFeature, mPhone, mCallbackHandler,
this, subscriptions.get(i), mSubDefaults, mReceiverHandler.getLooper());
+ controller.setUserSetupComplete(mUserSetup);
mMobileSignalControllers.put(subId, controller);
if (subscriptions.get(i).getSimSlotIndex() == 0) {
mDefaultSignalController = controller;
@@ -516,6 +518,23 @@
updateAirplaneMode(true /* force */);
}
+ public void setUserSetupComplete(final boolean userSetup) {
+ mReceiverHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ handleSetUserSetupComplete(userSetup);
+ }
+ });
+ }
+
+ @VisibleForTesting
+ void handleSetUserSetupComplete(boolean userSetup) {
+ mUserSetup = userSetup;
+ for (MobileSignalController controller : mMobileSignalControllers.values()) {
+ controller.setUserSetupComplete(mUserSetup);
+ }
+ }
+
@VisibleForTesting
boolean hasCorrectMobileControllers(List<SubscriptionInfo> allSubscriptions) {
if (allSubscriptions.size() != mMobileSignalControllers.size()) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index f3033cd..a855aed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -91,8 +91,6 @@
mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
-
- // Check if this was the result of hitting the enter key
final boolean isSoftImeEvent = event == null
&& (actionId == EditorInfo.IME_ACTION_DONE
|| actionId == EditorInfo.IME_ACTION_NEXT
@@ -102,7 +100,10 @@
&& event.getAction() == KeyEvent.ACTION_DOWN;
if (isSoftImeEvent || isKeyboardEnterKey) {
- sendRemoteInput();
+ if (mEditText.length() > 0) {
+ sendRemoteInput();
+ }
+ // Consume action to prevent IME from closing.
return true;
}
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 2c53e29..36dd727 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -654,8 +654,9 @@
intent.putExtra(PackageManager.EXTRA_MOVE_ID, move.moveId);
final VolumeInfo vol = mStorageManager.findVolumeByQualifiedUuid(move.volumeUuid);
- intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
-
+ if (vol != null) {
+ intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
+ }
return PendingIntent.getActivityAsUser(mContext, move.moveId, intent,
PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 60d33fa..38cac1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -111,6 +111,7 @@
when(mMockTm.getDataEnabled(mSubId)).thenReturn(true);
setDefaultSubId(mSubId);
setSubscriptions(mSubId);
+ mNetworkController.handleSetUserSetupComplete(true);
mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
mPhoneStateListener = mMobileSignalController.mPhoneStateListener;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index d5eca95..542c390 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -1,9 +1,9 @@
package com.android.systemui.statusbar.policy;
+import android.net.NetworkCapabilities;
import android.os.Looper;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
-
import com.android.settingslib.net.DataUsageController;
import org.mockito.Mockito;
@@ -99,6 +99,29 @@
TelephonyIcons.QS_DATA_4G);
}
+ public void testDataDisabledIcon() {
+ setupNetworkController();
+ Mockito.when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
+ setupDefaultSignal();
+ updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
+ setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
+
+ verifyDataIndicators(TelephonyIcons.ICON_DATA_DISABLED,
+ TelephonyIcons.QS_ICON_DATA_DISABLED);
+ }
+
+ public void testDataDisabledIcon_UserNotSetup() {
+ setupNetworkController();
+ Mockito.when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
+ setupDefaultSignal();
+ updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
+ setConnectivity(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
+ mNetworkController.handleSetUserSetupComplete(false);
+
+ // Don't show the X until the device is setup.
+ verifyDataIndicators(0, 0);
+ }
+
public void test4gDataIconConfigChange() {
setupDefaultSignal();
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
@@ -145,7 +168,6 @@
verifyLastMobileDataIndicators(true, DEFAULT_SIGNAL_STRENGTH, DEFAULT_ICON);
verifyLastQsMobileDataIndicators(true, DEFAULT_QS_SIGNAL_STRENGTH,
DEFAULT_QS_ICON, in, out);
-
}
private void verifyDataIndicators(int dataIcon, int qsDataIcon) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 7b9d4456..c62689c 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -656,11 +656,15 @@
}
private void ensureGroupStateLoadedLocked(int userId) {
- if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
+ ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ true );
+ }
+
+ private void ensureGroupStateLoadedLocked(int userId, boolean enforceUserUnlockingOrUnlocked) {
+ if (enforceUserUnlockingOrUnlocked && !mUserManager.isUserUnlockingOrUnlocked(userId)) {
throw new IllegalStateException(
"User " + userId + " must be unlocked for widgets to be available");
}
- if (isProfileWithLockedParent(userId)) {
+ if (enforceUserUnlockingOrUnlocked && isProfileWithLockedParent(userId)) {
throw new IllegalStateException(
"Profile " + userId + " must have unlocked parent");
}
@@ -3945,7 +3949,9 @@
@Override
public void run() {
synchronized (mLock) {
- ensureGroupStateLoadedLocked(mUserId);
+ // No need to enforce unlocked state when there is no caller. User can be in the
+ // stopping state or removed by the time the message is processed
+ ensureGroupStateLoadedLocked(mUserId, false /* enforceUserUnlockingOrUnlocked */ );
saveStateLocked(mUserId);
}
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 95f9e2d..1b63cd4 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -3706,7 +3706,7 @@
result = BackupTransport.TRANSPORT_OK;
}
} catch (IOException e) {
- Slog.e(TAG, "Error backing up " + mPkg.packageName, e);
+ Slog.e(TAG, "Error backing up " + mPkg.packageName + ": " + e.getMessage());
result = BackupTransport.AGENT_ERROR;
} finally {
try {
@@ -4466,7 +4466,6 @@
}
}
-
// If we've lost our running criteria, tell the transport to cancel
// and roll back this (partial) backup payload; otherwise tell it
// that we've reached the clean finish state.
@@ -4484,14 +4483,16 @@
}
}
- // TRANSPORT_ERROR here means that we've hit an error that the runner
- // doesn't know about, so it's still moving data but we're pulling the
+ // A transport-originated error here means that we've hit an error that the
+ // runner doesn't know about, so it's still moving data but we're pulling the
// rug out from under it. Don't ask for its result: we already know better
// and we'll hang if we block waiting for it, since it relies on us to
// read back the data it's writing into the engine. Just proceed with
// a graceful failure. The runner/engine mechanism will tear itself
- // down cleanly when we close the pipes from this end.
- if (backupPackageStatus != BackupTransport.TRANSPORT_ERROR) {
+ // down cleanly when we close the pipes from this end. Transport-level
+ // errors take precedence over agent/app-specific errors for purposes of
+ // determining our course of action.
+ if (backupPackageStatus == BackupTransport.TRANSPORT_OK) {
// We still could fail in backup runner thread, getting result from there.
int backupRunnerResult = backupRunner.getBackupResultBlocking();
if (backupRunnerResult != BackupTransport.TRANSPORT_OK) {
@@ -4499,10 +4500,14 @@
// not TRANSPORT_ERROR here, overwrite it.
backupPackageStatus = backupRunnerResult;
}
+ } else {
+ if (MORE_DEBUG) {
+ Slog.i(TAG, "Transport-level failure; cancelling agent work");
+ }
}
if (MORE_DEBUG) {
- Slog.i(TAG, "Done trying to send backup data: result="
+ Slog.i(TAG, "Done delivering backup data: result="
+ backupPackageStatus);
}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 8753992..6b51721 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -358,7 +358,7 @@
try {
mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
- mBatteryProps.batteryVoltage);
+ mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter);
} catch (RemoteException e) {
// Should never happen.
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d85827e..00dcdea 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -29,8 +29,12 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
+import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
+import static android.net.NetworkPolicyManager.RULE_UNKNOWN;
+
import android.annotation.Nullable;
import android.app.BroadcastOptions;
import android.app.Notification;
@@ -96,8 +100,10 @@
import android.security.KeyStore;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.LocalLog;
import android.util.LocalLog.ReadOnlyLocalLog;
+import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -121,9 +127,9 @@
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.DataConnectionStats;
import com.android.server.connectivity.KeepaliveTracker;
-import com.android.server.connectivity.NetworkDiagnostics;
import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
+import com.android.server.connectivity.NetworkDiagnostics;
import com.android.server.connectivity.NetworkMonitor;
import com.android.server.connectivity.PacManager;
import com.android.server.connectivity.PermissionMonitor;
@@ -131,8 +137,8 @@
import com.android.server.connectivity.Vpn;
import com.android.server.net.BaseNetworkObserver;
import com.android.server.net.LockdownVpnTracker;
+
import com.google.android.collect.Lists;
-import com.google.android.collect.Sets;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -152,11 +158,11 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.SortedSet;
-import java.util.TreeSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.SortedSet;
+import java.util.TreeSet;
/**
* @hide
@@ -202,9 +208,14 @@
/** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
private Object mRulesLock = new Object();
/** Currently active network rules by UID. */
+ @GuardedBy("mRulesLock")
private SparseIntArray mUidRules = new SparseIntArray();
/** Set of ifaces that are costly. */
- private HashSet<String> mMeteredIfaces = Sets.newHashSet();
+ @GuardedBy("mRulesLock")
+ private ArraySet<String> mMeteredIfaces = new ArraySet<>();
+ /** Flag indicating if background data is restricted. */
+ @GuardedBy("mRulesLock")
+ private boolean mRestrictBackground;
final private Context mContext;
private int mNetworkPreference;
@@ -651,7 +662,8 @@
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
try {
- mPolicyManager.registerListener(mPolicyListener);
+ mPolicyManager.setConnectivityListener(mPolicyListener);
+ mRestrictBackground = mPolicyManager.getRestrictBackground();
} catch (RemoteException e) {
// ouch, no rules updates means some processes may never get network
loge("unable to register INetworkPolicyListener" + e.toString());
@@ -819,7 +831,7 @@
throw new IllegalStateException("No free netIds");
}
- private NetworkState getFilteredNetworkState(int networkType, int uid) {
+ private NetworkState getFilteredNetworkState(int networkType, int uid, boolean ignoreBlocked) {
if (mLegacyTypeTracker.isTypeSupported(networkType)) {
final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
final NetworkState state;
@@ -834,7 +846,7 @@
state = new NetworkState(info, new LinkProperties(), new NetworkCapabilities(),
null, null, null);
}
- filterNetworkStateForUid(state, uid);
+ filterNetworkStateForUid(state, uid, ignoreBlocked);
return state;
} else {
return NetworkState.EMPTY;
@@ -890,22 +902,36 @@
/**
* Check if UID should be blocked from using the network with the given LinkProperties.
*/
- private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid) {
- final boolean networkCostly;
+ private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid,
+ boolean ignoreBlocked) {
+ // Networks aren't blocked when ignoring blocked status
+ if (ignoreBlocked) return false;
+ // Networks are never blocked for system services
+ if (uid < Process.FIRST_APPLICATION_UID) return false;
+
+ final boolean networkMetered;
final int uidRules;
final String iface = (lp == null ? "" : lp.getInterfaceName());
synchronized (mRulesLock) {
- networkCostly = mMeteredIfaces.contains(iface);
- uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
+ networkMetered = mMeteredIfaces.contains(iface);
+ uidRules = mUidRules.get(uid, RULE_UNKNOWN);
}
- if (uidRules == RULE_REJECT_ALL) {
- return true;
- } else if ((uidRules == RULE_REJECT_METERED) && networkCostly) {
- return true;
- } else {
- return false;
+ switch (uidRules) {
+ case RULE_ALLOW_ALL:
+ case RULE_ALLOW_METERED:
+ case RULE_TEMPORARY_ALLOW_METERED:
+ return false;
+ case RULE_REJECT_METERED:
+ return networkMetered;
+ case RULE_REJECT_ALL:
+ return true;
+ case RULE_UNKNOWN:
+ default:
+ // When background data is restricted device-wide, the default
+ // behavior for apps should be like RULE_REJECT_METERED
+ return mRestrictBackground ? networkMetered : false;
}
}
@@ -930,10 +956,10 @@
* on {@link #isNetworkWithLinkPropertiesBlocked}, or
* {@link NetworkInfo#isMetered()} based on network policies.
*/
- private void filterNetworkStateForUid(NetworkState state, int uid) {
+ private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) {
if (state == null || state.networkInfo == null || state.linkProperties == null) return;
- if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid)) {
+ if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, ignoreBlocked)) {
state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
}
if (mLockdownTracker != null) {
@@ -962,7 +988,7 @@
enforceAccessPermission();
final int uid = Binder.getCallingUid();
final NetworkState state = getUnfilteredActiveNetworkState(uid);
- filterNetworkStateForUid(state, uid);
+ filterNetworkStateForUid(state, uid, false);
maybeLogBlockedNetworkInfo(state.networkInfo, uid);
return state.networkInfo;
}
@@ -970,16 +996,16 @@
@Override
public Network getActiveNetwork() {
enforceAccessPermission();
- return getActiveNetworkForUidInternal(Binder.getCallingUid());
+ return getActiveNetworkForUidInternal(Binder.getCallingUid(), false);
}
@Override
- public Network getActiveNetworkForUid(int uid) {
+ public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) {
enforceConnectivityInternalPermission();
- return getActiveNetworkForUidInternal(uid);
+ return getActiveNetworkForUidInternal(uid, ignoreBlocked);
}
- private Network getActiveNetworkForUidInternal(final int uid) {
+ private Network getActiveNetworkForUidInternal(final int uid, boolean ignoreBlocked) {
final int user = UserHandle.getUserId(uid);
int vpnNetId = NETID_UNSET;
synchronized (mVpns) {
@@ -994,7 +1020,10 @@
if (nai != null) return nai.network;
}
nai = getDefaultNetwork();
- if (nai != null && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid)) nai = null;
+ if (nai != null
+ && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, ignoreBlocked)) {
+ nai = null;
+ }
return nai != null ? nai.network : null;
}
@@ -1006,10 +1035,10 @@
}
@Override
- public NetworkInfo getActiveNetworkInfoForUid(int uid) {
+ public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
enforceConnectivityInternalPermission();
final NetworkState state = getUnfilteredActiveNetworkState(uid);
- filterNetworkStateForUid(state, uid);
+ filterNetworkStateForUid(state, uid, ignoreBlocked);
return state.networkInfo;
}
@@ -1023,22 +1052,21 @@
// getUnfilteredActiveNetworkState.
final NetworkState state = getUnfilteredActiveNetworkState(uid);
if (state.networkInfo != null && state.networkInfo.getType() == networkType) {
- filterNetworkStateForUid(state, uid);
+ filterNetworkStateForUid(state, uid, false);
return state.networkInfo;
}
}
- final NetworkState state = getFilteredNetworkState(networkType, uid);
+ final NetworkState state = getFilteredNetworkState(networkType, uid, false);
return state.networkInfo;
}
@Override
- public NetworkInfo getNetworkInfoForNetwork(Network network) {
+ public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) {
enforceAccessPermission();
- final int uid = Binder.getCallingUid();
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
if (nai != null) {
final NetworkState state = nai.getNetworkState();
- filterNetworkStateForUid(state, uid);
+ filterNetworkStateForUid(state, uid, ignoreBlocked);
return state.networkInfo;
} else {
return null;
@@ -1063,8 +1091,8 @@
public Network getNetworkForType(int networkType) {
enforceAccessPermission();
final int uid = Binder.getCallingUid();
- NetworkState state = getFilteredNetworkState(networkType, uid);
- if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid)) {
+ NetworkState state = getFilteredNetworkState(networkType, uid, false);
+ if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, false)) {
return state.network;
}
return null;
@@ -1381,6 +1409,11 @@
if (LOGD_RULES) {
log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
}
+
+ synchronized (mRulesLock) {
+ mRestrictBackground = restrictBackground;
+ }
+
if (restrictBackground) {
log("onRestrictBackgroundChanged(true): disabling tethering");
mTethering.untetherAll();
@@ -1824,6 +1857,10 @@
pw.decreaseIndent();
pw.println();
+ pw.print("Restrict background: ");
+ pw.println(mRestrictBackground);
+ pw.println();
+
pw.println("Network Requests:");
pw.increaseIndent();
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
@@ -2765,7 +2802,7 @@
// which isn't meant to work on uncreated networks.
if (!nai.created) return;
- if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid)) return;
+ if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, false)) return;
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid);
}
@@ -4280,10 +4317,10 @@
Collection<InetAddress> dnses = newLp.getDnsServers();
if (DBG) log("Setting DNS servers for network " + netId + " to " + dnses);
try {
- mNetd.setDnsServersForNetwork(
+ mNetd.setDnsConfigurationForNetwork(
netId, NetworkUtils.makeStrings(dnses), newLp.getDomains());
} catch (Exception e) {
- loge("Exception in setDnsServersForNetwork: " + e);
+ loge("Exception in setDnsConfigurationForNetwork: " + e);
}
final NetworkAgentInfo defaultNai = getDefaultNetwork();
if (defaultNai != null && defaultNai.network.netId == netId) {
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index c912b11..cbf7e80 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -1281,8 +1281,14 @@
// service can't connect to vold, it restarts, and then the new instance
// does successfully connect.
final IMountService service = getMountService();
- String password = service.getPassword();
- service.clearPassword();
+ String password;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ password = service.getPassword();
+ service.clearPassword();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
if (password == null) {
return false;
}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index b0581aa..7253870 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -2648,6 +2648,8 @@
*/
@Override
public int getPasswordType() {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ "no permission to access the crypt keeper");
waitForReady();
@@ -2672,6 +2674,8 @@
*/
@Override
public void setField(String field, String contents) throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ "no permission to access the crypt keeper");
waitForReady();
@@ -2690,6 +2694,8 @@
*/
@Override
public String getField(String field) throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ "no permission to access the crypt keeper");
waitForReady();
@@ -2714,6 +2720,8 @@
*/
@Override
public boolean isConvertibleToFBE() throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ "no permission to access the crypt keeper");
waitForReady();
@@ -2728,8 +2736,9 @@
@Override
public String getPassword() throws RemoteException {
- mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE,
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
"only keyguard can retrieve password");
+
if (!isReady()) {
return new String();
}
@@ -2752,6 +2761,9 @@
@Override
public void clearPassword() throws RemoteException {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.STORAGE_INTERNAL,
+ "only keyguard can clear password");
+
if (!isReady()) {
return;
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 9fc17a2..2418160 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -47,6 +47,7 @@
import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
import android.annotation.NonNull;
import android.app.ActivityManagerNative;
+import android.content.ContentResolver;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetd;
@@ -76,6 +77,7 @@
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
@@ -175,6 +177,12 @@
public static final int StrictCleartext = 617;
}
+ /* Defaults for resolver parameters. */
+ public static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
+ public static final int DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25;
+ public static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
+ public static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
+
/**
* String indicating a softap command.
*/
@@ -1927,6 +1935,51 @@
}
@Override
+ public void setDnsConfigurationForNetwork(int netId, String[] servers, String domains) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+
+ ContentResolver resolver = mContext.getContentResolver();
+
+ int sampleValidity = Settings.Global.getInt(resolver,
+ Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
+ DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
+ if (sampleValidity < 0 || sampleValidity > 65535) {
+ Slog.w(TAG, "Invalid sampleValidity=" + sampleValidity + ", using default=" +
+ DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
+ sampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
+ }
+
+ int successThreshold = Settings.Global.getInt(resolver,
+ Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
+ DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
+ if (successThreshold < 0 || successThreshold > 100) {
+ Slog.w(TAG, "Invalid successThreshold=" + successThreshold + ", using default=" +
+ DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
+ successThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
+ }
+
+ int minSamples = Settings.Global.getInt(resolver,
+ Settings.Global.DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
+ int maxSamples = Settings.Global.getInt(resolver,
+ Settings.Global.DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
+ if (minSamples < 0 || minSamples > maxSamples || maxSamples > 64) {
+ Slog.w(TAG, "Invalid sample count (min, max)=(" + minSamples + ", " + maxSamples +
+ "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
+ DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
+ minSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
+ maxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
+ }
+
+ final String[] domainStrs = domains == null ? new String[0] : domains.split(" ");
+ final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples };
+ try {
+ mNetdService.setResolverConfiguration(netId, servers, domainStrs, params);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
public void setDnsServersForNetwork(int netId, String[] servers, String domains) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
@@ -2048,13 +2101,13 @@
}
}
- private void closeSocketsForFirewallChain(int chain, String chainName) {
+ private void closeSocketsForFirewallChainLocked(int chain, String chainName) {
// UID ranges to close sockets on.
UidRange[] ranges;
// UID ranges whose sockets we won't touch.
int[] exemptUids;
- SparseIntArray rules = getUidFirewallRules(chain);
+ final SparseIntArray rules = getUidFirewallRules(chain);
int numUids = 0;
if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
@@ -2119,7 +2172,7 @@
mFirewallChainStates.put(chain, enable);
final String operation = enable ? "enable_chain" : "disable_chain";
- String chainName;
+ final String chainName;
switch(chain) {
case FIREWALL_CHAIN_STANDBY:
chainName = FIREWALL_CHAIN_NAME_STANDBY;
@@ -2146,7 +2199,7 @@
// whitelist and blacklist chains allow RSTs through.
if (enable) {
if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
- closeSocketsForFirewallChain(chain, chainName);
+ closeSocketsForFirewallChainLocked(chain, chainName);
}
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 96214d6..98b3b08 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -409,7 +409,6 @@
*/
public void validateAccounts(int userId) {
final UserAccounts accounts = getUserAccounts(userId);
-
// Invalidate user-specific cache to make sure we catch any
// removed authenticators.
validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
@@ -426,15 +425,13 @@
+ " isCeDatabaseAttached=" + accounts.openHelper.isCeDatabaseAttached()
+ " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
}
+
if (invalidateAuthenticatorCache) {
mAuthenticatorCache.invalidateCache(accounts.userId);
}
- final HashMap<String, Integer> knownAuth = new HashMap<>();
- for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service :
- mAuthenticatorCache.getAllServices(accounts.userId)) {
- knownAuth.put(service.type.type, service.uid);
- }
+ final HashMap<String, Integer> knownAuth = getAuthenticatorTypeAndUIDForUser(
+ mAuthenticatorCache, accounts.userId);
synchronized (accounts.cacheLock) {
final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
@@ -452,6 +449,7 @@
// Create a list of authenticator type whose previous uid no longer exists
HashSet<String> obsoleteAuthType = Sets.newHashSet();
try {
+ SparseBooleanArray knownUids = null;
while (metaCursor.moveToNext()) {
String type = TextUtils.split(metaCursor.getString(0), META_KEY_DELIMITER)[1];
String uid = metaCursor.getString(1);
@@ -466,23 +464,48 @@
// Remove it from the knownAuth list if it's unchanged.
knownAuth.remove(type);
} else {
- // Only add it to the list if it no longer exists or uid different
- obsoleteAuthType.add(type);
- // And delete it from the TABLE_META
- db.delete(
- TABLE_META,
- META_KEY + "=? AND " + META_VALUE + "=?",
- new String[] {
- META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type,
- uid}
- );
+ /*
+ * The authenticator is presently not cached and should only be triggered
+ * when we think an authenticator has been removed (or is being updated).
+ * But we still want to check if any data with the associated uid is
+ * around. This is an (imperfect) signal that the package may be updating.
+ *
+ * A side effect of this is that an authenticator sharing a uid with
+ * multiple apps won't get its credentials wiped as long as some app with
+ * that uid is still on the device. But I suspect that this is a rare case.
+ * And it isn't clear to me how an attacker could really exploit that
+ * feature.
+ *
+ * The upshot is that we don't have to worry about accounts getting
+ * uninstalled while the authenticator's package is being updated.
+ *
+ */
+ if (knownUids == null) {
+ knownUids = getUidsOfInstalledOrUpdatedPackagesAsUser(accounts.userId);
+ }
+ if (!knownUids.get(Integer.parseInt(uid))) {
+ // The authenticator is not presently available to the cache. And the
+ // package no longer has a data directory (so we surmise it isn't updating).
+ // So purge its data from the account databases.
+ obsoleteAuthType.add(type);
+ // And delete it from the TABLE_META
+ db.delete(
+ TABLE_META,
+ META_KEY + "=? AND " + META_VALUE + "=?",
+ new String[] {
+ META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type,
+ uid}
+ );
+ }
}
}
} finally {
metaCursor.close();
}
- // Add the newly registered authenticator to TABLE_META
+ // Add the newly registered authenticator to TABLE_META. If old authenticators have
+ // been renabled (after being updated for example), then we just overwrite the old
+ // values.
Iterator<Entry<String, Integer>> iterator = knownAuth.entrySet().iterator();
while (iterator.hasNext()) {
Entry<String, Integer> entry = iterator.next();
@@ -490,7 +513,7 @@
values.put(META_KEY,
META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + entry.getKey());
values.put(META_VALUE, entry.getValue());
- db.insert(TABLE_META, null, values);
+ db.insertWithOnConflict(TABLE_META, null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
Cursor cursor = db.query(TABLE_ACCOUNTS,
@@ -544,10 +567,32 @@
}
}
+ private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
+ // Get the UIDs of all apps that might have data on the device. We want
+ // to preserve user data if the app might otherwise be storing data.
+ List<PackageInfo> pkgsWithData =
+ mPackageManager.getInstalledPackagesAsUser(
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+ SparseBooleanArray knownUids = new SparseBooleanArray(pkgsWithData.size());
+ for (PackageInfo pkgInfo : pkgsWithData) {
+ if (pkgInfo.applicationInfo != null
+ && (pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
+ knownUids.put(pkgInfo.applicationInfo.uid, true);
+ }
+ }
+ return knownUids;
+ }
+
private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
Context context,
int userId) {
AccountAuthenticatorCache authCache = new AccountAuthenticatorCache(context);
+ return getAuthenticatorTypeAndUIDForUser(authCache, userId);
+ }
+
+ private static HashMap<String, Integer> getAuthenticatorTypeAndUIDForUser(
+ IAccountAuthenticatorCache authCache,
+ int userId) {
HashMap<String, Integer> knownAuth = new HashMap<>();
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service : authCache
.getAllServices(userId)) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 2386a36..fa69b4a 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -592,7 +592,7 @@
ActivityRecord _resultTo, String _resultWho, int _reqCode,
boolean _componentSpecified, boolean _rootVoiceInteraction,
ActivityStackSupervisor supervisor,
- ActivityContainer container, ActivityOptions options) {
+ ActivityContainer container, ActivityOptions options, ActivityRecord sourceRecord) {
service = _service;
appToken = new Token(this, service);
info = aInfo;
@@ -705,21 +705,7 @@
noDisplay = ent != null && ent.array.getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
- if ((!_componentSpecified || _launchedFromUid == Process.myUid()
- || _launchedFromUid == 0) &&
- Intent.ACTION_MAIN.equals(_intent.getAction()) &&
- _intent.hasCategory(Intent.CATEGORY_HOME) &&
- _intent.getCategories().size() == 1 &&
- _intent.getData() == null &&
- _intent.getType() == null &&
- !isResolverActivity()) {
- // This sure looks like a home activity!
- mActivityType = HOME_ACTIVITY_TYPE;
- } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
- mActivityType = RECENTS_ACTIVITY_TYPE;
- } else {
- mActivityType = APPLICATION_ACTIVITY_TYPE;
- }
+ setActivityType(_componentSpecified, _launchedFromUid, _intent, sourceRecord);
immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
@@ -740,6 +726,36 @@
}
}
+ private boolean isHomeIntent(Intent intent) {
+ return Intent.ACTION_MAIN.equals(intent.getAction())
+ && intent.hasCategory(Intent.CATEGORY_HOME)
+ && intent.getCategories().size() == 1
+ && intent.getData() == null
+ && intent.getType() == null;
+ }
+
+ private boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
+ if (uid == Process.myUid() || uid == 0) {
+ // System process can launch home activity.
+ return true;
+ }
+ // Resolver activity can launch home activity.
+ return sourceRecord != null && sourceRecord.isResolverActivity();
+ }
+
+ private void setActivityType(boolean componentSpecified,
+ int launchedFromUid, Intent intent, ActivityRecord sourceRecord) {
+ if ((!componentSpecified || canLaunchHomeActivity(launchedFromUid, sourceRecord))
+ && isHomeIntent(intent) && !isResolverActivity()) {
+ // This sure looks like a home activity!
+ mActivityType = HOME_ACTIVITY_TYPE;
+ } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
+ mActivityType = RECENTS_ACTIVITY_TYPE;
+ } else {
+ mActivityType = APPLICATION_ACTIVITY_TYPE;
+ }
+ }
+
void setTask(TaskRecord newTask, TaskRecord taskToAffiliateWith) {
if (task != null && task.removeActivity(this) && task != newTask && task.stack != null) {
task.stack.removeTask(task, "setTask");
@@ -1473,7 +1489,7 @@
}
final ActivityRecord r = new ActivityRecord(service, /*caller*/null, launchedFromUid,
launchedFromPackage, intent, resolvedType, aInfo, service.getConfiguration(),
- null, null, 0, componentSpecified, false, stackSupervisor, null, null);
+ null, null, 0, componentSpecified, false, stackSupervisor, null, null, null);
r.persistentState = persistentState;
r.taskDescription = taskDescription;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 33b87b6..c15effb 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -492,7 +492,7 @@
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
- options);
+ options, sourceRecord);
if (outActivity != null) {
outActivity[0] = r;
}
@@ -1597,9 +1597,6 @@
private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
mOptions);
- if (mDoResume) {
- mTargetStack.moveToFront("startingNewTask");
- }
if (mReuseTask == null) {
final TaskRecord task = mTargetStack.createTaskRecord(
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index e9ed34b..3ed9969 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -304,6 +304,15 @@
* @param crashInfo describing the failure
*/
void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ crashApplicationInner(r, crashInfo);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
long timeMillis = System.currentTimeMillis();
String shortMsg = crashInfo.exceptionClassName;
String longMsg = crashInfo.exceptionMessage;
@@ -317,49 +326,20 @@
AppErrorResult result = new AppErrorResult();
TaskRecord task;
synchronized (mService) {
- if (mService.mController != null) {
- try {
- String name = r != null ? r.processName : null;
- int pid = r != null ? r.pid : Binder.getCallingPid();
- int uid = r != null ? r.info.uid : Binder.getCallingUid();
- if (!mService.mController.appCrashed(name, pid,
- shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
- if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
- && "Native crash".equals(crashInfo.exceptionClassName)) {
- Slog.w(TAG, "Skip killing native crashed app " + name
- + "(" + pid + ") during testing");
- } else {
- Slog.w(TAG, "Force-killing crashed app " + name
- + " at watcher's request");
- if (r != null) {
- r.kill("crash", true);
- } else {
- // Huh.
- Process.killProcess(pid);
- ActivityManagerService.killProcessGroup(uid, pid);
- }
- }
- return;
- }
- } catch (RemoteException e) {
- mService.mController = null;
- Watchdog.getInstance().setActivityController(null);
- }
+ /**
+ * If crash is handled by instance of {@link android.app.IActivityController},
+ * finish now and don't show the app error dialog.
+ */
+ if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,
+ timeMillis)) {
+ return;
}
- final long origId = Binder.clearCallingIdentity();
-
- // If this process is running instrumentation, finish it.
+ /**
+ * If this process was running instrumentation, finish now - it will be handled in
+ * {@link ActivityManagerService#handleAppDiedLocked}.
+ */
if (r != null && r.instrumentationClass != null) {
- Slog.w(TAG, "Error in app " + r.processName
- + " running instrumentation " + r.instrumentationClass + ":");
- if (shortMsg != null) Slog.w(TAG, " " + shortMsg);
- if (longMsg != null) Slog.w(TAG, " " + longMsg);
- Bundle info = new Bundle();
- info.putString("shortMsg", shortMsg);
- info.putString("longMsg", longMsg);
- mService.finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
- Binder.restoreCallingIdentity(origId);
return;
}
@@ -375,7 +355,6 @@
// If we can't identify the process or it's already exceeded its crash quota,
// quit right away without showing a crash dialog.
if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {
- Binder.restoreCallingIdentity(origId);
return;
}
@@ -385,97 +364,90 @@
task = data.task;
msg.obj = data;
mService.mUiHandler.sendMessage(msg);
-
- Binder.restoreCallingIdentity(origId);
}
int res = result.get();
Intent appErrorIntent = null;
- final long ident = Binder.clearCallingIdentity();
- try {
- MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
- if (res == AppErrorDialog.TIMEOUT) {
- res = AppErrorDialog.FORCE_QUIT;
- }
- if (res == AppErrorDialog.RESET) {
- String[] packageList = r.getPackageList();
- if (packageList != null) {
- PackageManager pm = mContext.getPackageManager();
- final Semaphore s = new Semaphore(0);
- for (int i = 0; i < packageList.length; i++) {
- if (i < packageList.length - 1) {
- pm.deleteApplicationCacheFiles(packageList[i], null);
- } else {
- pm.deleteApplicationCacheFiles(packageList[i],
- new IPackageDataObserver.Stub() {
- @Override
- public void onRemoveCompleted(String packageName,
- boolean succeeded) {
- s.release();
- }
- });
+ MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);
+ if (res == AppErrorDialog.TIMEOUT) {
+ res = AppErrorDialog.FORCE_QUIT;
+ }
+ if (res == AppErrorDialog.RESET) {
+ String[] packageList = r.getPackageList();
+ if (packageList != null) {
+ PackageManager pm = mContext.getPackageManager();
+ final Semaphore s = new Semaphore(0);
+ for (int i = 0; i < packageList.length; i++) {
+ if (i < packageList.length - 1) {
+ pm.deleteApplicationCacheFiles(packageList[i], null);
+ } else {
+ pm.deleteApplicationCacheFiles(packageList[i],
+ new IPackageDataObserver.Stub() {
+ @Override
+ public void onRemoveCompleted(String packageName,
+ boolean succeeded) {
+ s.release();
+ }
+ });
- // Wait until cache has been cleared before we restart.
- try {
- s.acquire();
- } catch (InterruptedException e) {
- }
- }
- }
- }
- // If there was nothing to reset, just restart;
- res = AppErrorDialog.RESTART;
- }
- synchronized (mService) {
- if (res == AppErrorDialog.MUTE) {
- stopReportingCrashesLocked(r);
- }
- if (res == AppErrorDialog.RESTART) {
- mService.removeProcessLocked(r, false, true, "crash");
- if (task != null) {
+ // Wait until cache has been cleared before we restart.
try {
- mService.startActivityFromRecents(task.taskId,
- ActivityOptions.makeBasic().toBundle());
- } catch (IllegalArgumentException e) {
- // Hmm, that didn't work, app might have crashed before creating a
- // recents entry. Let's see if we have a safe-to-restart intent.
- if (task.intent.getCategories().contains(
- Intent.CATEGORY_LAUNCHER)) {
- mService.startActivityInPackage(task.mCallingUid,
- task.mCallingPackage, task.intent,
- null, null, null, 0, 0,
- ActivityOptions.makeBasic().toBundle(),
- task.userId, null, null);
- }
+ s.acquire();
+ } catch (InterruptedException e) {
}
}
}
- if (res == AppErrorDialog.FORCE_QUIT) {
- long orig = Binder.clearCallingIdentity();
- try {
- // Kill it with fire!
- mService.mStackSupervisor.handleAppCrashLocked(r);
- if (!r.persistent) {
- mService.removeProcessLocked(r, false, false, "crash");
- mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
- }
- } finally {
- Binder.restoreCallingIdentity(orig);
- }
- }
- if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
- appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
- }
- if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
- // XXX Can't keep track of crash time for isolated processes,
- // since they don't have a persistent identity.
- mProcessCrashTimes.put(r.info.processName, r.uid,
- SystemClock.uptimeMillis());
- }
}
- } finally {
- Binder.restoreCallingIdentity(ident);
+ // If there was nothing to reset, just restart;
+ res = AppErrorDialog.RESTART;
+ }
+ synchronized (mService) {
+ if (res == AppErrorDialog.MUTE) {
+ stopReportingCrashesLocked(r);
+ }
+ if (res == AppErrorDialog.RESTART) {
+ mService.removeProcessLocked(r, false, true, "crash");
+ if (task != null) {
+ try {
+ mService.startActivityFromRecents(task.taskId,
+ ActivityOptions.makeBasic().toBundle());
+ } catch (IllegalArgumentException e) {
+ // Hmm, that didn't work, app might have crashed before creating a
+ // recents entry. Let's see if we have a safe-to-restart intent.
+ if (task.intent.getCategories().contains(
+ Intent.CATEGORY_LAUNCHER)) {
+ mService.startActivityInPackage(task.mCallingUid,
+ task.mCallingPackage, task.intent,
+ null, null, null, 0, 0,
+ ActivityOptions.makeBasic().toBundle(),
+ task.userId, null, null);
+ }
+ }
+ }
+ }
+ if (res == AppErrorDialog.FORCE_QUIT) {
+ long orig = Binder.clearCallingIdentity();
+ try {
+ // Kill it with fire!
+ mService.mStackSupervisor.handleAppCrashLocked(r);
+ if (!r.persistent) {
+ mService.removeProcessLocked(r, false, false, "crash");
+ mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(orig);
+ }
+ }
+ if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
+ appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
+ }
+ if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
+ // XXX Can't keep track of crash time for isolated processes,
+ // since they don't have a persistent identity.
+ mProcessCrashTimes.put(r.info.processName, r.uid,
+ SystemClock.uptimeMillis());
+ }
}
if (appErrorIntent != null) {
@@ -487,6 +459,47 @@
}
}
+ private boolean handleAppCrashInActivityController(ProcessRecord r,
+ ApplicationErrorReport.CrashInfo crashInfo,
+ String shortMsg, String longMsg,
+ String stackTrace, long timeMillis) {
+ if (mService.mController == null) {
+ return false;
+ }
+
+ try {
+ String name = r != null ? r.processName : null;
+ int pid = r != null ? r.pid : Binder.getCallingPid();
+ int uid = r != null ? r.info.uid : Binder.getCallingUid();
+ if (!mService.mController.appCrashed(name, pid,
+ shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
+ if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
+ && "Native crash".equals(crashInfo.exceptionClassName)) {
+ Slog.w(TAG, "Skip killing native crashed app " + name
+ + "(" + pid + ") during testing");
+ } else {
+ Slog.w(TAG, "Force-killing crashed app " + name
+ + " at watcher's request");
+ if (r != null) {
+ if (!makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, null))
+ {
+ r.kill("crash", true);
+ }
+ } else {
+ // Huh.
+ Process.killProcess(pid);
+ ActivityManagerService.killProcessGroup(uid, pid);
+ }
+ }
+ return true;
+ }
+ } catch (RemoteException e) {
+ mService.mController = null;
+ Watchdog.getInstance().setActivityController(null);
+ }
+ return false;
+ }
+
private boolean makeAppCrashingLocked(ProcessRecord app,
String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
app.crashing = true;
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index c6786de..d34ec86 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -974,7 +974,7 @@
@Override
public void setBatteryState(final int status, final int health, final int plugType,
- final int level, final int temp, final int volt) {
+ final int level, final int temp, final int volt, final int chargeCount) {
enforceCallingPermission();
// BatteryService calls us here and we may update external state. It would be wrong
@@ -987,7 +987,8 @@
if (mStats.isOnBattery() == onBattery) {
// The battery state has not changed, so we don't need to sync external
// stats immediately.
- mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
+ mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
+ chargeCount);
return;
}
}
@@ -996,7 +997,8 @@
// immediately here, we may not collect the relevant data later.
updateExternalStatsSync("battery-state", BatteryStatsImpl.ExternalStatsSync.UPDATE_ALL);
synchronized (mStats) {
- mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt);
+ mStats.setBatteryStateLocked(status, health, plugType, level, temp, volt,
+ chargeCount);
}
}
});
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
index 5096b35..6d1c531 100644
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -144,8 +144,13 @@
boolean dumpSerializedSize = false;
boolean dumpEvents = false;
+ boolean dumpDebugInfo = false;
for (String arg : args) {
switch (arg) {
+ case "--debug":
+ dumpDebugInfo = true;
+ break;
+
case "--events":
dumpEvents = true;
break;
@@ -155,6 +160,7 @@
break;
case "--all":
+ dumpDebugInfo = true;
dumpEvents = true;
dumpSerializedSize = true;
break;
@@ -163,6 +169,7 @@
synchronized (mEvents) {
pw.println("Number of events: " + mEvents.size());
+ pw.println("Counter: " + mEventCounter);
if (mEvents.size() > 0) {
pw.println("Time span: " +
DateUtils.formatElapsedTime(
@@ -171,16 +178,12 @@
}
if (dumpSerializedSize) {
- long dataSize = 0;
Parcel p = Parcel.obtain();
for (ConnectivityMetricsEvent e : mEvents) {
- dataSize += 16; // timestamp and 2 stamps
-
- p.writeParcelable(e.data, 0);
+ p.writeParcelable(e, 0);
}
- dataSize += p.dataSize();
+ pw.println("Serialized data size: " + p.dataSize());
p.recycle();
- pw.println("Serialized data size: " + dataSize);
}
if (dumpEvents) {
@@ -192,6 +195,21 @@
}
}
+ if (dumpDebugInfo) {
+ synchronized (mThrottlingCounters) {
+ pw.println();
+ for (int i = 0; i < ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS; i++) {
+ if (mThrottlingCounters[i] > 0) {
+ pw.println("Throttling Counter #" + i + ": " + mThrottlingCounters[i]);
+ }
+ }
+ pw.println("Throttling Time Remaining: " +
+ DateUtils.formatElapsedTime(
+ (mThrottlingIntervalBoundaryMillis - System.currentTimeMillis())
+ / 1000));
+ }
+ }
+
synchronized (mPendingIntents) {
if (!mPendingIntents.isEmpty()) {
pw.println();
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 5ad988a..1f7d312 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -333,6 +333,7 @@
out.attribute(null, "sourceUserId", String.valueOf(jobStatus.getSourceUserId()));
out.attribute(null, "uid", Integer.toString(jobStatus.getUid()));
out.attribute(null, "priority", String.valueOf(jobStatus.getPriority()));
+ out.attribute(null, "flags", String.valueOf(jobStatus.getFlags()));
}
private void writeBundleToXml(PersistableBundle extras, XmlSerializer out)
@@ -543,6 +544,10 @@
if (val != null) {
jobBuilder.setPriority(Integer.parseInt(val));
}
+ val = parser.getAttributeValue(null, "flags");
+ if (val != null) {
+ jobBuilder.setFlags(Integer.parseInt(val));
+ }
val = parser.getAttributeValue(null, "sourceUserId");
sourceUserId = val == null ? -1 : Integer.parseInt(val);
} catch (NumberFormatException e) {
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 88cf322..f5aac08 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -16,6 +16,7 @@
package com.android.server.job.controllers;
+import android.app.job.JobInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -97,7 +98,9 @@
}
private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
- final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobStatus.getSourceUid());
+ final boolean ignoreBlocked = (jobStatus.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
+ final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobStatus.getSourceUid(),
+ ignoreBlocked);
final boolean connected = (info != null) && info.isConnected();
final boolean unmetered = connected && !info.isMetered();
final boolean notRoaming = connected && !info.isRoaming();
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 590d075..19bede9 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -297,6 +297,10 @@
return job.getPriority();
}
+ public int getFlags() {
+ return job.getFlags();
+ }
+
public boolean hasConnectivityConstraint() {
return (requiredConstraints&CONSTRAINT_CONNECTIVITY) != 0;
}
@@ -416,12 +420,12 @@
// satisfied).
// AppNotIdle implicit constraint must be satisfied
// DeviceNotDozing implicit constraint must be satisfied
- return (isConstraintsSatisfied()
- || (!job.isPeriodic()
- && hasDeadlineConstraint() && (satisfiedConstraints&CONSTRAINT_DEADLINE) != 0)
- )
- && (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0
- && (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0;
+ final boolean deadlineSatisfied = (!job.isPeriodic() && hasDeadlineConstraint()
+ && (satisfiedConstraints & CONSTRAINT_DEADLINE) != 0);
+ final boolean notIdle = (satisfiedConstraints & CONSTRAINT_APP_NOT_IDLE) != 0;
+ final boolean notDozing = (satisfiedConstraints & CONSTRAINT_DEVICE_NOT_DOZING) != 0
+ || (job.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) != 0;
+ return (isConstraintsSatisfied() || deadlineSatisfied) && notIdle && notDozing;
}
static final int CONSTRAINTS_OF_INTEREST =
@@ -561,6 +565,10 @@
if (job.getPriority() != 0) {
pw.print(prefix); pw.print(" Priority: "); pw.println(job.getPriority());
}
+ if (job.getFlags() != 0) {
+ pw.print(prefix); pw.print(" Flags: ");
+ pw.println(Integer.toHexString(job.getFlags()));
+ }
pw.print(prefix); pw.print(" Requires: charging=");
pw.print(job.isRequireCharging()); pw.print(" deviceIdle=");
pw.println(job.isRequireDeviceIdle());
@@ -613,6 +621,9 @@
pw.print(prefix); pw.print("Satisfied constraints:");
dumpConstraints(pw, satisfiedConstraints);
pw.println();
+ pw.print(prefix); pw.print("Unsatisfied constraints:");
+ dumpConstraints(pw, (requiredConstraints & ~satisfiedConstraints));
+ pw.println();
}
if (changedAuthorities != null) {
pw.print(prefix); pw.println("Changed authorities:");
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 30aab8c..50d9368 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -48,7 +48,6 @@
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
@@ -349,6 +348,9 @@
/** Foreground at UID granularity. */
final SparseIntArray mUidState = new SparseIntArray();
+ /** Higher priority listener before general event dispatch */
+ private INetworkPolicyListener mConnectivityListener;
+
private final RemoteCallbackList<INetworkPolicyListener>
mListeners = new RemoteCallbackList<>();
@@ -1391,6 +1393,7 @@
final String tag = in.getName();
if (type == START_TAG) {
if (TAG_POLICY_LIST.equals(tag)) {
+ final boolean oldValue = mRestrictBackground;
version = readIntAttribute(in, ATTR_VERSION);
if (version >= VERSION_ADDED_RESTRICT_BACKGROUND) {
mRestrictBackground = readBooleanAttribute(
@@ -1398,6 +1401,12 @@
} else {
mRestrictBackground = false;
}
+ if (mRestrictBackground != oldValue) {
+ // Some early services may have read the default value,
+ // so notify them that it's changed
+ mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED,
+ mRestrictBackground ? 1 : 0, 0).sendToTarget();
+ }
} else if (TAG_NETWORK_POLICY.equals(tag)) {
final int networkTemplate = readIntAttribute(in, ATTR_NETWORK_TEMPLATE);
@@ -1766,20 +1775,25 @@
}
@Override
+ public void setConnectivityListener(INetworkPolicyListener listener) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ if (mConnectivityListener != null) {
+ throw new IllegalStateException("Connectivity listener already registered");
+ }
+ mConnectivityListener = listener;
+ }
+
+ @Override
public void registerListener(INetworkPolicyListener listener) {
// TODO: create permission for observing network policy
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
mListeners.register(listener);
-
- // TODO: consider dispatching existing rules to new listeners
}
@Override
public void unregisterListener(INetworkPolicyListener listener) {
// TODO: create permission for observing network policy
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
mListeners.unregister(listener);
}
@@ -2754,8 +2768,8 @@
final boolean isBlacklisted = (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
final boolean isWhitelisted = mRestrictBackgroundWhitelistUids.get(uid);
- int newRule = RULE_ALLOW_ALL;
- final int oldRule = mUidRules.get(uid);
+ int newRule = RULE_UNKNOWN;
+ final int oldRule = mUidRules.get(uid, RULE_UNKNOWN);
// First step: define the new rule based on user restrictions and foreground state.
if (isForeground) {
@@ -2777,8 +2791,7 @@
+ ", oldRule: " + ruleToString(oldRule));
}
-
- if (newRule == RULE_ALLOW_ALL) {
+ if (newRule == RULE_UNKNOWN) {
mUidRules.delete(uid);
} else {
mUidRules.put(uid, newRule);
@@ -2858,6 +2871,45 @@
}
}
+ private void dispatchUidRulesChanged(INetworkPolicyListener listener, int uid, int uidRules) {
+ if (listener != null) {
+ try {
+ listener.onUidRulesChanged(uid, uidRules);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ private void dispatchMeteredIfacesChanged(INetworkPolicyListener listener,
+ String[] meteredIfaces) {
+ if (listener != null) {
+ try {
+ listener.onMeteredIfacesChanged(meteredIfaces);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ private void dispatchRestrictBackgroundChanged(INetworkPolicyListener listener,
+ boolean restrictBackground) {
+ if (listener != null) {
+ try {
+ listener.onRestrictBackgroundChanged(restrictBackground);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ private void dispatchRestrictBackgroundWhitelistChanged(INetworkPolicyListener listener,
+ int uid, boolean whitelisted) {
+ if (listener != null) {
+ try {
+ listener.onRestrictBackgroundWhitelistChanged(uid, whitelisted);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
private Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
@@ -2865,30 +2917,22 @@
case MSG_RULES_CHANGED: {
final int uid = msg.arg1;
final int uidRules = msg.arg2;
+ dispatchUidRulesChanged(mConnectivityListener, uid, uidRules);
final int length = mListeners.beginBroadcast();
for (int i = 0; i < length; i++) {
final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
- if (listener != null) {
- try {
- listener.onUidRulesChanged(uid, uidRules);
- } catch (RemoteException e) {
- }
- }
+ dispatchUidRulesChanged(listener, uid, uidRules);
}
mListeners.finishBroadcast();
return true;
}
case MSG_METERED_IFACES_CHANGED: {
final String[] meteredIfaces = (String[]) msg.obj;
+ dispatchMeteredIfacesChanged(mConnectivityListener, meteredIfaces);
final int length = mListeners.beginBroadcast();
for (int i = 0; i < length; i++) {
final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
- if (listener != null) {
- try {
- listener.onMeteredIfacesChanged(meteredIfaces);
- } catch (RemoteException e) {
- }
- }
+ dispatchMeteredIfacesChanged(listener, meteredIfaces);
}
mListeners.finishBroadcast();
return true;
@@ -2915,15 +2959,11 @@
}
case MSG_RESTRICT_BACKGROUND_CHANGED: {
final boolean restrictBackground = msg.arg1 != 0;
+ dispatchRestrictBackgroundChanged(mConnectivityListener, restrictBackground);
final int length = mListeners.beginBroadcast();
for (int i = 0; i < length; i++) {
final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
- if (listener != null) {
- try {
- listener.onRestrictBackgroundChanged(restrictBackground);
- } catch (RemoteException e) {
- }
- }
+ dispatchRestrictBackgroundChanged(listener, restrictBackground);
}
mListeners.finishBroadcast();
final Intent intent =
@@ -2947,18 +2987,16 @@
final boolean changed = msg.arg2 == 1;
final Boolean whitelisted = (Boolean) msg.obj;
+ // First notify internal listeners...
if (whitelisted != null) {
+ final boolean whitelistedBool = whitelisted.booleanValue();
+ dispatchRestrictBackgroundWhitelistChanged(mConnectivityListener, uid,
+ whitelistedBool);
final int length = mListeners.beginBroadcast();
for (int i = 0; i < length; i++) {
- // First notify internal listeners...
final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
- if (listener != null) {
- try {
- listener.onRestrictBackgroundWhitelistChanged(uid,
- whitelisted.booleanValue());
- } catch (RemoteException e) {
- }
- }
+ dispatchRestrictBackgroundWhitelistChanged(listener, uid,
+ whitelistedBool);
}
mListeners.finishBroadcast();
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ba651fc..61e36d9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -266,6 +266,7 @@
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
@@ -274,6 +275,7 @@
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
+import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
@@ -437,6 +439,8 @@
*/
private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
+ static final String PLATFORM_PACKAGE_NAME = "android";
+
static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
@@ -9725,7 +9729,9 @@
switch (grant) {
case GRANT_INSTALL: {
// Revoke this as runtime permission to handle the case of
- // a runtime permission being downgraded to an install one. Also in permission review mode we keep dangerous permissions for legacy apps
+ // a runtime permission being downgraded to an install one.
+ // Also in permission review mode we keep dangerous permissions
+ // for legacy apps
for (int userId : UserManagerService.getInstance().getUserIds()) {
if (origPermissions.getRuntimePermissionState(
bp.name, userId) != null) {
@@ -9773,10 +9779,21 @@
&& !appSupportsRuntimePermissions) {
// For legacy apps that need a permission review, every new
// runtime permission is granted but it is pending a review.
- if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
- permissionsState.grantRuntimePermission(bp, userId);
- flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
- // We changed the permission and flags, hence have to write.
+ // We also need to review only platform defined runtime
+ // permissions as these are the only ones the platform knows
+ // how to disable the API to simulate revocation as legacy
+ // apps don't expect to run with revoked permissions.
+ if (PLATFORM_PACKAGE_NAME.equals(bp.sourcePackage)) {
+ if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) {
+ flags |= FLAG_PERMISSION_REVIEW_REQUIRED;
+ // We changed the flags, hence have to write.
+ changedRuntimePermissionUserIds = ArrayUtils.appendInt(
+ changedRuntimePermissionUserIds, userId);
+ }
+ }
+ if (permissionsState.grantRuntimePermission(bp, userId)
+ != PermissionsState.PERMISSION_OPERATION_FAILURE) {
+ // We changed the permission, hence have to write.
changedRuntimePermissionUserIds = ArrayUtils.appendInt(
changedRuntimePermissionUserIds, userId);
}
@@ -13817,6 +13834,13 @@
return false;
}
+ private static void updateDigest(MessageDigest digest, File file) throws IOException {
+ try (DigestInputStream digestStream =
+ new DigestInputStream(new FileInputStream(file), digest)) {
+ while (digestStream.read() != -1) {} // nothing to do; just plow through the file
+ }
+ }
+
private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags,
UserHandle user, String installerPackageName, PackageInstalledInfo res) {
final boolean isEphemeral = (policyFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0;
@@ -13871,6 +13895,32 @@
}
}
+ // don't allow a system upgrade unless the upgrade hash matches
+ if (oldPackage.restrictUpdateHash != null && oldPackage.isSystemApp()) {
+ byte[] digestBytes = null;
+ try {
+ final MessageDigest digest = MessageDigest.getInstance("SHA-512");
+ updateDigest(digest, new File(pkg.baseCodePath));
+ if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
+ for (String path : pkg.splitCodePaths) {
+ updateDigest(digest, new File(path));
+ }
+ }
+ digestBytes = digest.digest();
+ } catch (NoSuchAlgorithmException | IOException e) {
+ res.setError(INSTALL_FAILED_INVALID_APK,
+ "Could not compute hash: " + pkgName);
+ return;
+ }
+ if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
+ res.setError(INSTALL_FAILED_INVALID_APK,
+ "New package fails restrict-update check: " + pkgName);
+ return;
+ }
+ // retain upgrade restriction
+ pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
+ }
+
// Check for shared user id changes
String invalidPackageName =
getParentOrChildPackageChangedSharedUser(oldPackage, pkg);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index af7e66d..4c7f9eb 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -73,6 +73,8 @@
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
import android.service.wallpaper.WallpaperService;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseArray;
@@ -224,6 +226,17 @@
+ " whichPending=0x" + Integer.toHexString(wallpaper.whichPending)
+ " written=" + written);
}
+
+ if (moved && lockWallpaperChanged) {
+ // We just migrated sys -> lock to preserve imagery for an impending
+ // new system-only wallpaper. Tell keyguard about it but that's it.
+ if (DEBUG) {
+ Slog.i(TAG, "Sys -> lock MOVED_TO");
+ }
+ notifyLockWallpaperChanged();
+ return;
+ }
+
synchronized (mLock) {
if (sysWallpaperChanged || lockWallpaperChanged) {
notifyCallbacksLocked(wallpaper);
@@ -276,14 +289,7 @@
mLockWallpaperMap.remove(wallpaper.userId);
}
// and in any case, tell keyguard about it
- final IWallpaperManagerCallback cb = mKeyguardListener;
- if (cb != null) {
- try {
- cb.onWallpaperChanged();
- } catch (RemoteException e) {
- // Oh well it went away; no big deal
- }
- }
+ notifyLockWallpaperChanged();
}
saveSettingsLocked(wallpaper.userId);
}
@@ -293,6 +299,17 @@
}
}
+ void notifyLockWallpaperChanged() {
+ final IWallpaperManagerCallback cb = mKeyguardListener;
+ if (cb != null) {
+ try {
+ cb.onWallpaperChanged();
+ } catch (RemoteException e) {
+ // Oh well it went away; no big deal
+ }
+ }
+ }
+
/**
* Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
* for display.
@@ -1334,6 +1351,17 @@
if (DEBUG) Slog.v(TAG, "setWallpaper which=0x" + Integer.toHexString(which));
WallpaperData wallpaper;
+ /* If we're setting system but not lock, and lock is currently sharing the system
+ * wallpaper, we need to migrate that image over to being lock-only before
+ * the caller here writes new bitmap data.
+ */
+ if (which == FLAG_SYSTEM && mLockWallpaperMap.get(userId) == null) {
+ if (DEBUG) {
+ Slog.i(TAG, "Migrating system->lock to preserve");
+ }
+ migrateSystemToLockWallpaperLocked(userId);
+ }
+
wallpaper = getWallpaperSafeLocked(userId, which);
final long ident = Binder.clearCallingIdentity();
try {
@@ -1354,6 +1382,38 @@
}
}
+ private void migrateSystemToLockWallpaperLocked(int userId) {
+ WallpaperData sysWP = mWallpaperMap.get(userId);
+ if (sysWP == null) {
+ if (DEBUG) {
+ Slog.i(TAG, "No system wallpaper? Not tracking for lock-only");
+ }
+ return;
+ }
+
+ // We know a-priori that there is no lock-only wallpaper currently
+ WallpaperData lockWP = new WallpaperData(userId,
+ WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
+ lockWP.wallpaperId = sysWP.wallpaperId;
+ lockWP.cropHint.set(sysWP.cropHint);
+ lockWP.width = sysWP.width;
+ lockWP.height = sysWP.height;
+ lockWP.allowBackup = false;
+
+ // Migrate the bitmap files outright; no need to copy
+ try {
+ Os.rename(sysWP.wallpaperFile.getAbsolutePath(), lockWP.wallpaperFile.getAbsolutePath());
+ Os.rename(sysWP.cropFile.getAbsolutePath(), lockWP.cropFile.getAbsolutePath());
+ } catch (ErrnoException e) {
+ Slog.e(TAG, "Can't migrate system wallpaper: " + e.getMessage());
+ lockWP.wallpaperFile.delete();
+ lockWP.cropFile.delete();
+ return;
+ }
+
+ mLockWallpaperMap.put(userId, lockWP);
+ }
+
ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper,
Bundle extras) {
if (name == null) name = "";
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 1493bc7..a0784b5 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1441,6 +1441,18 @@
return;
}
+ // Do not change surface properties of opening apps if we are waiting for the
+ // transition to be ready. transitionGoodToGo could be not ready even after all
+ // opening apps are drawn. It's only waiting on isFetchingAppTransitionsSpecs()
+ // to get the animation spec. (For example, go into Recents and immediately open
+ // the same app again before the app's surface is destroyed or saved, the surface
+ // is always ready in the whole process.) If we go ahead here, the opening app
+ // will be shown with the full size before the correct animation spec arrives.
+ if (mService.mAppTransition.isTransitionSet() && isDummyAnimation() &&
+ mService.mOpeningApps.contains(w.mAppToken)) {
+ return;
+ }
+
boolean displayed = false;
computeShownFrameLocked();
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index f2c995b..1feb816 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -836,6 +836,8 @@
BackgroundThread.getHandler().post(new Runnable() {
@Override
public void run() {
+ if (!mUserManager.isUserUnlockingOrUnlocked(userId)) return;
+
UserState userState;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(userId, true);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 612e5e8..f58de26 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -501,7 +501,10 @@
if (status != STATUS_OK) {
Slog.w(TAG, "Error stopping keyphrase model: " + model.getHandle());
}
- model.clearState();
+ model.setStopped();
+ model.setRequested(false);
+ model.clearCallback();
+ model.setRecognitionConfig(null);
}
}
internalClearGlobalStateLocked();
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index b9e9ac8..3785cdc 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -383,6 +383,15 @@
</activity>
<activity
+ android:name="VideoViewCaptureActivity"
+ android:label="SurfaceView/GetBitmap with Video source">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.hwui.TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="GLTextureViewActivity"
android:label="TextureView/OpenGL">
<intent-filter>
diff --git a/tests/HwAccelerationTest/res/raw/colorgrid_video.mp4 b/tests/HwAccelerationTest/res/raw/colorgrid_video.mp4
new file mode 100644
index 0000000..1be8bee
--- /dev/null
+++ b/tests/HwAccelerationTest/res/raw/colorgrid_video.mp4
Binary files differ
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java
index f658b7c..6fe2cb4 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GetBitmapSurfaceViewActivity.java
@@ -23,6 +23,7 @@
import android.os.Environment;
import android.view.Gravity;
import android.view.PixelCopy;
+import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
@@ -87,9 +88,42 @@
android.util.Log.e("TextureView", "Cannot set preview texture target!", t);
}
+ setCameraDisplayOrientation(this, 0, mCamera);
mCamera.startPreview();
}
+ public static void setCameraDisplayOrientation(Activity activity,
+ int cameraId, android.hardware.Camera camera) {
+ android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
+ android.hardware.Camera.getCameraInfo(cameraId, info);
+ int rotation = activity.getWindowManager().getDefaultDisplay()
+ .getRotation();
+ int degrees = 0;
+ switch (rotation) {
+ case Surface.ROTATION_0:
+ degrees = 0;
+ break;
+ case Surface.ROTATION_90:
+ degrees = 90;
+ break;
+ case Surface.ROTATION_180:
+ degrees = 180;
+ break;
+ case Surface.ROTATION_270:
+ degrees = 270;
+ break;
+ }
+
+ int result;
+ if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+ result = (info.orientation + degrees) % 360;
+ result = (360 - result) % 360; // compensate the mirror
+ } else { // back-facing
+ result = (info.orientation - degrees + 360) % 360;
+ }
+ camera.setDisplayOrientation(result);
+ }
+
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/VideoViewCaptureActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/VideoViewCaptureActivity.java
new file mode 100644
index 0000000..b87be80
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/VideoViewCaptureActivity.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.view.PixelCopy;
+import android.view.View;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.Toast;
+import android.widget.VideoView;
+
+import java.io.FileOutputStream;
+
+public class VideoViewCaptureActivity extends Activity {
+ private VideoView mVideoView;
+ private int mVideoWidth, mVideoHeight;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mVideoView = new VideoView(this);
+ mVideoView.setOnPreparedListener(mp -> {
+ mp.setLooping(true);
+ mVideoWidth = mp.getVideoWidth();
+ mVideoHeight = mp.getVideoHeight();
+ mVideoView.start();
+ });
+
+ Uri uri = Uri.parse("android.resource://com.android.test.hwui/" + R.raw.colorgrid_video);
+ mVideoView.setVideoURI(uri);
+
+ Button button = new Button(this);
+ button.setText("Copy bitmap to /sdcard/surfaceview.png");
+ button.setOnClickListener((View v) -> {
+ final Bitmap b = Bitmap.createBitmap(
+ mVideoWidth, mVideoHeight,
+ Bitmap.Config.ARGB_8888);
+ PixelCopy.request(mVideoView, b,
+ (int result) -> {
+ if (result != PixelCopy.SUCCESS) {
+ Toast.makeText(VideoViewCaptureActivity.this,
+ "Failed to copy", Toast.LENGTH_SHORT).show();
+ return;
+ }
+ try {
+ try (FileOutputStream out = new FileOutputStream(
+ Environment.getExternalStorageDirectory() + "/surfaceview.png");) {
+ b.compress(Bitmap.CompressFormat.PNG, 100, out);
+ }
+ } catch (Exception e) {
+ // Ignore
+ }
+ }, mVideoView.getHandler());
+ });
+
+ FrameLayout content = new FrameLayout(this);
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.addView(button, LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ layout.addView(mVideoView, LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.MATCH_PARENT);
+
+ content.addView(layout, new FrameLayout.LayoutParams(
+ FrameLayout.LayoutParams.MATCH_PARENT,
+ FrameLayout.LayoutParams.MATCH_PARENT));
+ setContentView(content);
+ }
+}
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index 81ab3cc..fe7c3b9 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -330,7 +330,7 @@
0x2764, # HEAVY BLACK HEART
}
assert missing_text_chars == set(), (
- 'Text style version of some emoji characters are missing.')
+ 'Text style version of some emoji characters are missing: ' + repr(missing_text_chars))
# Setting reverse to true returns a dictionary that maps the values to sets of
@@ -411,6 +411,20 @@
_emoji_zwj_sequences = parse_unicode_datafile(
path.join(ucd_path, 'emoji-zwj-sequences.txt'))
+ # filter modern pentathlon, as it seems likely to be removed from final spec
+ def is_excluded(n):
+ return n == 0x1f93b
+
+ def contains_excluded(t):
+ if type(t) == int:
+ return is_excluded(t)
+ return any(is_excluded(cp) for cp in t)
+
+ # filter modern pentathlon, as it seems likely to be removed from final spec
+ _emoji_properties['Emoji'] = set(
+ t for t in _emoji_properties['Emoji'] if not contains_excluded(t))
+ _emoji_sequences = dict(
+ (t, v) for (t, v) in _emoji_sequences.items() if not contains_excluded(t))
def flag_sequence(territory_code):
return tuple(0x1F1E6 + ord(ch) - ord('A') for ch in territory_code)
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index 663e1e2..f87f6c5 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -16,8 +16,6 @@
LOCAL_PATH := $(my-dir)
include $(CLEAR_VARS)
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
-
#
# Define rules to build temp_layoutlib.jar, which contains a subset of
# the classes in framework.jar. The layoutlib_create tool is used to
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index 16e5913..3dd8002 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -18,7 +18,6 @@
LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_JAVA_RESOURCE_DIRS := resources
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
LOCAL_JAVA_LIBRARIES := \
layoutlib_api-prebuilt \
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 80e230c..f87269b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -861,7 +861,9 @@
resValue = mRenderResources.resolveResValue(resValue);
if (defaultPropMap != null) {
- defaultPropMap.put(attrName,
+ defaultPropMap.put(
+ frameworkAttr ? SdkConstants.PREFIX_ANDROID + attrName :
+ attrName,
new Property(preResolve, resValue.getValue()));
}
@@ -932,7 +934,8 @@
@Nullable StyleResourceValue style, int[] attrs) throws Resources.NotFoundException {
List<Pair<String, Boolean>> attributes = searchAttrs(attrs);
- BridgeTypedArray ta = Resources_Delegate.newTypeArray(mSystemResources, attrs.length, false);
+ BridgeTypedArray ta =
+ Resources_Delegate.newTypeArray(mSystemResources, attrs.length, false);
PropertiesMap defaultPropMap = new PropertiesMap();
// for each attribute, get its name so that we can search it in the style
@@ -943,11 +946,11 @@
// look for the value in the given style
ResourceValue resValue;
String attrName = attribute.getFirst();
+ boolean frameworkAttr = attribute.getSecond();
if (style != null) {
- resValue = mRenderResources.findItemInStyle(style, attrName,
- attribute.getSecond());
+ resValue = mRenderResources.findItemInStyle(style, attrName, frameworkAttr);
} else {
- resValue = mRenderResources.findItemInTheme(attrName, attribute.getSecond());
+ resValue = mRenderResources.findItemInTheme(attrName, frameworkAttr);
}
if (resValue != null) {
@@ -955,8 +958,10 @@
String preResolve = resValue.getValue();
// resolve it to make sure there are no references left.
resValue = mRenderResources.resolveResValue(resValue);
- ta.bridgeSetValue(i, attrName, attribute.getSecond(), resValue);
- defaultPropMap.put(attrName, new Property(preResolve, resValue.getValue()));
+ ta.bridgeSetValue(i, attrName, frameworkAttr, resValue);
+ defaultPropMap.put(
+ frameworkAttr ? SdkConstants.ANDROID_PREFIX + attrName : attrName,
+ new Property(preResolve, resValue.getValue()));
}
}
}
diff --git a/tools/layoutlib/bridge/tests/Android.mk b/tools/layoutlib/bridge/tests/Android.mk
index 5c062d0..8a81d0b 100644
--- a/tools/layoutlib/bridge/tests/Android.mk
+++ b/tools/layoutlib/bridge/tests/Android.mk
@@ -16,8 +16,6 @@
include $(CLEAR_VARS)
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
-
# Only compile source java files in this lib.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_RESOURCE_DIRS := res
diff --git a/tools/layoutlib/create/Android.mk b/tools/layoutlib/create/Android.mk
index 47377ae..c7f2c41 100644
--- a/tools/layoutlib/create/Android.mk
+++ b/tools/layoutlib/create/Android.mk
@@ -16,8 +16,6 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
-
LOCAL_SRC_FILES := $(call all-java-files-under,src)
LOCAL_JAR_MANIFEST := manifest.txt
diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk
index c59528e..dafb9c6 100644
--- a/tools/layoutlib/create/tests/Android.mk
+++ b/tools/layoutlib/create/tests/Android.mk
@@ -15,8 +15,6 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
-
# Only compile source java files in this lib.
LOCAL_SRC_FILES := $(call all-java-files-under, com)