summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/svc/src/com/android/commands/svc/NfcCommand.java85
-rw-r--r--cmds/svc/src/com/android/commands/svc/Svc.java3
-rw-r--r--core/java/android/app/ActivityThread.java5
-rw-r--r--core/java/android/content/Intent.java38
-rw-r--r--core/java/android/content/pm/PackageParser.java11
-rw-r--r--core/java/android/content/res/Resources.java207
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java8
-rw-r--r--core/java/android/hardware/display/IDisplayManager.aidl3
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java2
-rw-r--r--core/java/android/net/IpReachabilityMonitor.java35
-rw-r--r--core/java/android/os/BatteryStats.java13
-rw-r--r--core/java/android/os/PowerManagerInternal.java11
-rw-r--r--core/java/android/provider/Settings.java1
-rw-r--r--core/java/android/view/Display.java133
-rw-r--r--core/java/android/view/DisplayInfo.java52
-rw-r--r--core/java/android/view/View.java6
-rw-r--r--core/java/android/widget/AbsListView.java46
-rw-r--r--core/java/android/widget/AdapterView.java19
-rw-r--r--core/java/android/widget/GridView.java2
-rw-r--r--core/java/android/widget/ListView.java2
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java105
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java45
-rw-r--r--core/java/com/android/internal/os/BatteryStatsHelper.java2
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java234
-rw-r--r--core/java/com/android/internal/os/CpuPowerCalculator.java37
-rw-r--r--core/java/com/android/internal/os/KernelCpuSpeedReader.java36
-rw-r--r--core/java/com/android/internal/os/KernelUidCpuTimeReader.java2
-rw-r--r--core/java/com/android/internal/os/PowerProfile.java82
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java14
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/values-mcc240-mnc01/config.xml27
-rw-r--r--core/res/res/values-mcc240-mnc05/config.xml27
-rw-r--r--core/res/res/values/config.xml22
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/xml/power_profile.xml35
-rw-r--r--core/tests/BTtraffic/Android.mk16
-rw-r--r--core/tests/BTtraffic/AndroidManifest.xml22
-rw-r--r--core/tests/BTtraffic/README45
-rw-r--r--core/tests/BTtraffic/res/values/strings.xml3
-rw-r--r--core/tests/BTtraffic/src/com/android/google/experimental/bttraffic/BTtraffic.java328
-rw-r--r--core/tests/SvcMonitor/Android.mk16
-rw-r--r--core/tests/SvcMonitor/AndroidManifest.xml21
-rw-r--r--core/tests/SvcMonitor/README27
-rw-r--r--core/tests/SvcMonitor/res/values/strings.xml3
-rw-r--r--core/tests/SvcMonitor/src/com/android/google/experimental/svcmoniter/SvcMonitor.java209
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java35
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/TetherUtil.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java4
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java31
-rw-r--r--services/core/java/com/android/server/GestureLauncherService.java13
-rw-r--r--services/core/java/com/android/server/VibratorService.java4
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java3
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkDiagnostics.java56
-rw-r--r--services/core/java/com/android/server/display/DisplayAdapter.java12
-rw-r--r--services/core/java/com/android/server/display/DisplayDevice.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceInfo.java18
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java24
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java236
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplay.java26
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java2
-rw-r--r--services/core/java/com/android/server/fingerprint/FingerprintService.java25
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java16
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java14
-rw-r--r--services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java51
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java24
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java6
-rw-r--r--services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java11
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java5
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java7
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java31
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java5
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl6
80 files changed, 2508 insertions, 389 deletions
diff --git a/cmds/svc/src/com/android/commands/svc/NfcCommand.java b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
new file mode 100644
index 000000000000..e0f09ee2c666
--- /dev/null
+++ b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.svc;
+
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.nfc.INfcAdapter;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+public class NfcCommand extends Svc.Command {
+
+ public NfcCommand() {
+ super("nfc");
+ }
+
+ @Override
+ public String shortHelp() {
+ return "Control NFC functions";
+ }
+
+ @Override
+ public String longHelp() {
+ return shortHelp() + "\n"
+ + "\n"
+ + "usage: svc nfc [enable|disable]\n"
+ + " Turn NFC on or off.\n\n";
+ }
+
+ @Override
+ public void run(String[] args) {
+ boolean validCommand = false;
+ if (args.length >= 2) {
+ boolean flag = false;
+ if ("enable".equals(args[1])) {
+ flag = true;
+ validCommand = true;
+ } else if ("disable".equals(args[1])) {
+ flag = false;
+ validCommand = true;
+ }
+ if (validCommand) {
+ IPackageManager pm = IPackageManager.Stub.asInterface(
+ ServiceManager.getService("package"));
+ try {
+ if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
+ INfcAdapter nfc = INfcAdapter.Stub
+ .asInterface(ServiceManager.getService(Context.NFC_SERVICE));
+ try {
+ if (flag) {
+ nfc.enable();
+ } else
+ nfc.disable(true);
+ } catch (RemoteException e) {
+ System.err.println("NFC operation failed: " + e);
+ }
+ } else {
+ System.err.println("NFC feature not supported.");
+ }
+ } catch (RemoteException e) {
+ System.err.println("RemoteException while calling PackageManager, is the "
+ + "system running?");
+ }
+ return;
+ }
+ }
+ System.err.println(longHelp());
+ }
+
+}
diff --git a/cmds/svc/src/com/android/commands/svc/Svc.java b/cmds/svc/src/com/android/commands/svc/Svc.java
index 0fbba11e927d..2cccd1a4dc92 100644
--- a/cmds/svc/src/com/android/commands/svc/Svc.java
+++ b/cmds/svc/src/com/android/commands/svc/Svc.java
@@ -95,6 +95,7 @@ public class Svc {
new PowerCommand(),
new DataCommand(),
new WifiCommand(),
- new UsbCommand()
+ new UsbCommand(),
+ new NfcCommand(),
};
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index da21eaffa95b..fd88a0549a10 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4235,6 +4235,11 @@ public final class ActivityThread {
configDiff = mConfiguration.updateFrom(config);
config = applyCompatConfiguration(mCurDefaultDisplayDpi);
+
+ final Theme systemTheme = getSystemContext().getTheme();
+ if ((systemTheme.getChangingConfigurations() & configDiff) != 0) {
+ systemTheme.rebase();
+ }
}
ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 87d52e4ee07e..12c26323296d 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1604,6 +1604,23 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.action.GET_PERMISSIONS_COUNT";
/**
+ * Broadcast action that requests list of all apps that have runtime permissions. It will
+ * respond to the request by sending a broadcast with action defined by
+ * {@link #EXTRA_GET_PERMISSIONS_PACKAGES_RESPONSE_INTENT}. The response will contain
+ * {@link #EXTRA_GET_PERMISSIONS_APP_LIST_RESULT}, as well as
+ * {@link #EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT}, with contents described below or
+ * a null upon failure.
+ *
+ * <p>{@link #EXTRA_GET_PERMISSIONS_APP_LIST_RESULT} will contain a list of package names of
+ * apps that have runtime permissions. {@link #EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT}
+ * will contain the list of app labels corresponding ot the apps in the first list.
+ *
+ * @hide
+ */
+ public static final String ACTION_GET_PERMISSIONS_PACKAGES
+ = "android.intent.action.GET_PERMISSIONS_PACKAGES";
+
+ /**
* Extra included in response to {@link #ACTION_GET_PERMISSIONS_COUNT}.
* @hide
*/
@@ -1618,6 +1635,20 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.extra.GET_PERMISSIONS_GROUP_LIST_RESULT";
/**
+ * String list of apps that have one or more runtime permissions.
+ * @hide
+ */
+ public static final String EXTRA_GET_PERMISSIONS_APP_LIST_RESULT
+ = "android.intent.extra.GET_PERMISSIONS_APP_LIST_RESULT";
+
+ /**
+ * String list of app labels for apps that have one or more runtime permissions.
+ * @hide
+ */
+ public static final String EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT
+ = "android.intent.extra.GET_PERMISSIONS_APP_LABEL_LIST_RESULT";
+
+ /**
* Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_COUNT} broadcasts.
* @hide
*/
@@ -1625,6 +1656,13 @@ public class Intent implements Parcelable, Cloneable {
= "android.intent.extra.GET_PERMISSIONS_RESONSE_INTENT";
/**
+ * Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_PACKAGES} broadcasts.
+ * @hide
+ */
+ public static final String EXTRA_GET_PERMISSIONS_PACKAGES_RESPONSE_INTENT
+ = "android.intent.extra.GET_PERMISSIONS_PACKAGES_RESONSE_INTENT";
+
+ /**
* Activity action: Launch UI to manage which apps have a given permission.
* <p>
* Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission access
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ed7a2a3ea30d..7032c9a861cf 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4520,6 +4520,17 @@ public class PackageParser {
return applicationInfo.isUpdatedSystemApp();
}
+ /**
+ * @hide
+ */
+ public boolean canHaveOatDir() {
+ // The following app types CANNOT have oat directory
+ // - non-updated system apps
+ // - forward-locked apps or apps installed in ASEC containers
+ return (!isSystemApp() || isUpdatedSystemApp())
+ && !isForwardLocked() && !applicationInfo.isExternalAsec();
+ }
+
public String toString() {
return "Package{"
+ Integer.toHexString(System.identityHashCode(this))
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 731903c158be..82724587d15d 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1438,10 +1438,12 @@ public class Resources {
* if not already defined in the theme.
*/
public void applyStyle(int resId, boolean force) {
- AssetManager.applyThemeStyle(mTheme, resId, force);
+ synchronized (mKey) {
+ AssetManager.applyThemeStyle(mTheme, resId, force);
- mThemeResId = resId;
- mKey.append(resId, force);
+ mThemeResId = resId;
+ mKey.append(resId, force);
+ }
}
/**
@@ -1454,10 +1456,14 @@ public class Resources {
* @param other The existing Theme to copy from.
*/
public void setTo(Theme other) {
- AssetManager.copyTheme(mTheme, other.mTheme);
+ synchronized (mKey) {
+ synchronized (other.mKey) {
+ AssetManager.copyTheme(mTheme, other.mTheme);
- mThemeResId = other.mThemeResId;
- mKey.setTo(other.getKey());
+ mThemeResId = other.mThemeResId;
+ mKey.setTo(other.getKey());
+ }
+ }
}
/**
@@ -1480,11 +1486,13 @@ public class Resources {
* @see #obtainStyledAttributes(AttributeSet, int[], int, int)
*/
public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
- final int len = attrs.length;
- final TypedArray array = TypedArray.obtain(Resources.this, len);
- array.mTheme = this;
- AssetManager.applyStyle(mTheme, 0, 0, 0, attrs, array.mData, array.mIndices);
- return array;
+ synchronized (mKey) {
+ final int len = attrs.length;
+ final TypedArray array = TypedArray.obtain(Resources.this, len);
+ array.mTheme = this;
+ AssetManager.applyStyle(mTheme, 0, 0, 0, attrs, array.mData, array.mIndices);
+ return array;
+ }
}
/**
@@ -1494,7 +1502,7 @@ public class Resources {
* <p>Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when you are done
* with the array.
*
- * @param resid The desired style resource.
+ * @param resId The desired style resource.
* @param attrs The desired attributes in the style.
*
* @throws NotFoundException Throws NotFoundException if the given ID does not exist.
@@ -1507,39 +1515,15 @@ public class Resources {
* @see #obtainStyledAttributes(int[])
* @see #obtainStyledAttributes(AttributeSet, int[], int, int)
*/
- public TypedArray obtainStyledAttributes(@StyleRes int resid, @StyleableRes int[] attrs)
+ public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs)
throws NotFoundException {
- final int len = attrs.length;
- final TypedArray array = TypedArray.obtain(Resources.this, len);
- array.mTheme = this;
- if (false) {
- int[] data = array.mData;
-
- System.out.println("**********************************************************");
- System.out.println("**********************************************************");
- System.out.println("**********************************************************");
- System.out.println("Attributes:");
- String s = " Attrs:";
- int i;
- for (i=0; i<attrs.length; i++) {
- s = s + " 0x" + Integer.toHexString(attrs[i]);
- }
- System.out.println(s);
- s = " Found:";
- TypedValue value = new TypedValue();
- for (i=0; i<attrs.length; i++) {
- int d = i*AssetManager.STYLE_NUM_ENTRIES;
- value.type = data[d+AssetManager.STYLE_TYPE];
- value.data = data[d+AssetManager.STYLE_DATA];
- value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
- value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
- s = s + " 0x" + Integer.toHexString(attrs[i])
- + "=" + value;
- }
- System.out.println(s);
+ synchronized (mKey) {
+ final int len = attrs.length;
+ final TypedArray array = TypedArray.obtain(Resources.this, len);
+ array.mTheme = this;
+ AssetManager.applyStyle(mTheme, 0, resId, 0, attrs, array.mData, array.mIndices);
+ return array;
}
- AssetManager.applyStyle(mTheme, 0, resid, 0, attrs, array.mData, array.mIndices);
- return array;
}
/**
@@ -1592,50 +1576,23 @@ public class Resources {
*/
public TypedArray obtainStyledAttributes(AttributeSet set,
@StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
- final int len = attrs.length;
- final TypedArray array = TypedArray.obtain(Resources.this, len);
-
- // XXX note that for now we only work with compiled XML files.
- // To support generic XML files we will need to manually parse
- // out the attributes from the XML file (applying type information
- // contained in the resources and such).
- final XmlBlock.Parser parser = (XmlBlock.Parser)set;
- AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
- parser != null ? parser.mParseState : 0, attrs, array.mData, array.mIndices);
+ synchronized (mKey) {
+ final int len = attrs.length;
+ final TypedArray array = TypedArray.obtain(Resources.this, len);
- array.mTheme = this;
- array.mXml = parser;
+ // XXX note that for now we only work with compiled XML files.
+ // To support generic XML files we will need to manually parse
+ // out the attributes from the XML file (applying type information
+ // contained in the resources and such).
+ final XmlBlock.Parser parser = (XmlBlock.Parser) set;
+ AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
+ parser != null ? parser.mParseState : 0,
+ attrs, array.mData, array.mIndices);
+ array.mTheme = this;
+ array.mXml = parser;
- if (false) {
- int[] data = array.mData;
-
- System.out.println("Attributes:");
- String s = " Attrs:";
- int i;
- for (i=0; i<set.getAttributeCount(); i++) {
- s = s + " " + set.getAttributeName(i);
- int id = set.getAttributeNameResource(i);
- if (id != 0) {
- s = s + "(0x" + Integer.toHexString(id) + ")";
- }
- s = s + "=" + set.getAttributeValue(i);
- }
- System.out.println(s);
- s = " Found:";
- TypedValue value = new TypedValue();
- for (i=0; i<attrs.length; i++) {
- int d = i*AssetManager.STYLE_NUM_ENTRIES;
- value.type = data[d+AssetManager.STYLE_TYPE];
- value.data = data[d+AssetManager.STYLE_DATA];
- value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE];
- value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID];
- s = s + " 0x" + Integer.toHexString(attrs[i])
- + "=" + value;
- }
- System.out.println(s);
+ return array;
}
-
- return array;
}
/**
@@ -1654,18 +1611,20 @@ public class Resources {
*/
@NonNull
public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
- final int len = attrs.length;
- if (values == null || len != values.length) {
- throw new IllegalArgumentException(
- "Base attribute values must the same length as attrs");
- }
+ synchronized (mKey) {
+ final int len = attrs.length;
+ if (values == null || len != values.length) {
+ throw new IllegalArgumentException(
+ "Base attribute values must the same length as attrs");
+ }
- final TypedArray array = TypedArray.obtain(Resources.this, len);
- AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
- array.mTheme = this;
- array.mXml = null;
+ final TypedArray array = TypedArray.obtain(Resources.this, len);
+ AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
+ array.mTheme = this;
+ array.mXml = null;
- return array;
+ return array;
+ }
}
/**
@@ -1686,14 +1645,9 @@ public class Resources {
* <var>outValue</var> is valid, else false.
*/
public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
- boolean got = mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
- if (false) {
- System.out.println(
- "resolveAttribute #" + Integer.toHexString(resid)
- + " got=" + got + ", type=0x" + Integer.toHexString(outValue.type)
- + ", data=0x" + Integer.toHexString(outValue.data));
+ synchronized (mKey) {
+ return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
}
- return got;
}
/**
@@ -1739,8 +1693,11 @@ public class Resources {
* @see ActivityInfo
*/
public int getChangingConfigurations() {
- final int nativeChangingConfig = AssetManager.getThemeChangingConfigurations(mTheme);
- return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
+ synchronized (mKey) {
+ final int nativeChangingConfig =
+ AssetManager.getThemeChangingConfigurations(mTheme);
+ return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
+ }
}
/**
@@ -1751,7 +1708,9 @@ public class Resources {
* @param prefix Text to prefix each line printed.
*/
public void dump(int priority, String tag, String prefix) {
- AssetManager.dumpTheme(mTheme, priority, tag, prefix);
+ synchronized (mKey) {
+ AssetManager.dumpTheme(mTheme, priority, tag, prefix);
+ }
}
@Override
@@ -1801,19 +1760,21 @@ public class Resources {
*/
@ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true)
public String[] getTheme() {
- final int N = mKey.mCount;
- final String[] themes = new String[N * 2];
- for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
- final int resId = mKey.mResId[j];
- final boolean forced = mKey.mForce[j];
- try {
- themes[i] = getResourceName(resId);
- } catch (NotFoundException e) {
- themes[i] = Integer.toHexString(i);
+ synchronized (mKey) {
+ final int N = mKey.mCount;
+ final String[] themes = new String[N * 2];
+ for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
+ final int resId = mKey.mResId[j];
+ final boolean forced = mKey.mForce[j];
+ try {
+ themes[i] = getResourceName(resId);
+ } catch (NotFoundException e) {
+ themes[i] = Integer.toHexString(i);
+ }
+ themes[i + 1] = forced ? "forced" : "not forced";
}
- themes[i + 1] = forced ? "forced" : "not forced";
+ return themes;
}
- return themes;
}
/** @hide */
@@ -1834,13 +1795,15 @@ public class Resources {
* @hide
*/
public void rebase() {
- AssetManager.clearTheme(mTheme);
-
- // Reapply the same styles in the same order.
- for (int i = 0; i < mKey.mCount; i++) {
- final int resId = mKey.mResId[i];
- final boolean force = mKey.mForce[i];
- AssetManager.applyThemeStyle(mTheme, resId, force);
+ synchronized (mKey) {
+ AssetManager.clearTheme(mTheme);
+
+ // Reapply the same styles in the same order.
+ for (int i = 0; i < mKey.mCount; i++) {
+ final int resId = mKey.mResId[i];
+ final boolean force = mKey.mForce[i];
+ AssetManager.applyThemeStyle(mTheme, resId, force);
+ }
}
}
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 21ba7bda493e..121a187b3639 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -359,6 +359,14 @@ public final class DisplayManagerGlobal {
}
}
+ public void requestColorTransform(int displayId, int colorTransformId) {
+ try {
+ mDm.requestColorTransform(displayId, colorTransformId);
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Failed to request color transform.", ex);
+ }
+ }
+
public VirtualDisplay createVirtualDisplay(Context context, MediaProjection projection,
String name, int width, int height, int densityDpi, Surface surface, int flags,
VirtualDisplay.Callback callback, Handler handler) {
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 4486dd4e0887..8a1abf18602a 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -59,6 +59,9 @@ interface IDisplayManager {
// No permissions required.
WifiDisplayStatus getWifiDisplayStatus();
+ // Requires CONFIGURE_DISPLAY_COLOR_TRANSFORM
+ void requestColorTransform(int displayId, int colorTransformId);
+
// Requires CAPTURE_VIDEO_OUTPUT, CAPTURE_SECURE_VIDEO_OUTPUT, or an appropriate
// MediaProjection token for certain combinations of flags.
int createVirtualDisplay(in IVirtualDisplayCallback callback,
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7fef5e17c5cb..122df2394b6b 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -775,7 +775,7 @@ public class FingerprintManager {
if (fingerId != reqFingerId) {
Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
}
- if (fingerId != reqFingerId) {
+ if (groupId != reqGroupId) {
Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
}
mRemovalCallback.onRemovalSucceeded(mRemovalFingerprint);
diff --git a/core/java/android/net/IpReachabilityMonitor.java b/core/java/android/net/IpReachabilityMonitor.java
index 88fb01437cd0..2283004c7759 100644
--- a/core/java/android/net/IpReachabilityMonitor.java
+++ b/core/java/android/net/IpReachabilityMonitor.java
@@ -18,6 +18,7 @@ package android.net;
import com.android.internal.annotations.GuardedBy;
+import android.content.Context;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.LinkProperties.ProvisioningChange;
@@ -31,6 +32,7 @@ import android.net.netlink.RtNetlinkNeighborMessage;
import android.net.netlink.StructNdaCacheInfo;
import android.net.netlink.StructNdMsg;
import android.net.netlink.StructNlMsgHdr;
+import android.os.PowerManager;
import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
@@ -74,6 +76,7 @@ public class IpReachabilityMonitor {
}
private final Object mLock = new Object();
+ private final PowerManager.WakeLock mWakeLock;
private final String mInterfaceName;
private final int mInterfaceIndex;
private final Callback mCallback;
@@ -136,7 +139,8 @@ public class IpReachabilityMonitor {
return returnValue;
}
- public IpReachabilityMonitor(String ifName, Callback callback) throws IllegalArgumentException {
+ public IpReachabilityMonitor(Context context, String ifName, Callback callback)
+ throws IllegalArgumentException {
mInterfaceName = ifName;
int ifIndex = -1;
try {
@@ -145,6 +149,8 @@ public class IpReachabilityMonitor {
} catch (SocketException | NullPointerException e) {
throw new IllegalArgumentException("invalid interface '" + ifName + "': ", e);
}
+ mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName);
mCallback = callback;
mNetlinkSocketObserver = new NetlinkSocketObserver();
mObserverThread = new Thread(mNetlinkSocketObserver);
@@ -291,6 +297,17 @@ public class IpReachabilityMonitor {
synchronized (mLock) {
ipProbeList.addAll(mIpWatchList.keySet());
}
+
+ if (!ipProbeList.isEmpty() && stillRunning()) {
+ // Keep the CPU awake long enough to allow all ARP/ND
+ // probes a reasonable chance at success. See b/23197666.
+ //
+ // The wakelock we use is (by default) refcounted, and this version
+ // of acquire(timeout) queues a release message to keep acquisitions
+ // and releases balanced.
+ mWakeLock.acquire(getProbeWakeLockDuration());
+ }
+
for (InetAddress target : ipProbeList) {
if (!stillRunning()) {
break;
@@ -299,6 +316,22 @@ public class IpReachabilityMonitor {
}
}
+ private long getProbeWakeLockDuration() {
+ // Ideally, this would be computed by examining the values of:
+ //
+ // /proc/sys/net/ipv[46]/neigh/<ifname>/ucast_solicit
+ //
+ // and:
+ //
+ // /proc/sys/net/ipv[46]/neigh/<ifname>/retrans_time_ms
+ //
+ // For now, just make some assumptions.
+ final long numUnicastProbes = 3;
+ final long retransTimeMs = 1000;
+ final long gracePeriodMs = 500;
+ return (numUnicastProbes * retransTimeMs) + gracePeriodMs;
+ }
+
// TODO: simply the number of objects by making this extend Thread.
private final class NetlinkSocketObserver implements Runnable {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index bad94fce20aa..8e86a53072e7 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -463,13 +463,15 @@ public abstract class BatteryStats implements Parcelable {
public abstract long getCpuPowerMaUs(int which);
/**
- * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed.
+ * Returns the approximate cpu time (in milliseconds) spent at a certain CPU speed for a
+ * given CPU cluster.
+ * @param cluster the index of the CPU cluster.
* @param step the index of the CPU speed. This is not the actual speed of the CPU.
* @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
- * @see BatteryStats#getCpuSpeedSteps()
+ * @see PowerProfile.getNumCpuClusters()
+ * @see PowerProfile.getNumSpeedStepsInCpuCluster(int)
*/
- @Deprecated
- public abstract long getTimeAtCpuSpeed(int step, int which);
+ public abstract long getTimeAtCpuSpeed(int cluster, int step, int which);
public static abstract class Sensor {
/*
@@ -2276,9 +2278,6 @@ public abstract class BatteryStats implements Parcelable {
public abstract Map<String, ? extends Timer> getKernelWakelockStats();
- /** Returns the number of different speeds that the CPU can run at */
- public abstract int getCpuSpeedSteps();
-
public abstract void writeToParcelWithoutUids(Parcel out, int flags);
private final static void formatTimeRaw(StringBuilder out, long seconds) {
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 70cff00636ac..b6d0fcb448f5 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -53,6 +53,15 @@ public abstract class PowerManagerInternal {
*/
public static final int WAKEFULNESS_DOZING = 3;
+
+ /**
+ * Power hint: The user is interacting with the device. The corresponding data field must be
+ * the expected duration of the fling, or 0 if unknown.
+ *
+ * This must be kept in sync with the values in hardware/libhardware/include/hardware/power.h
+ */
+ public static final int POWER_HINT_INTERACTION = 2;
+
public static String wakefulnessToString(int wakefulness) {
switch (wakefulness) {
case WAKEFULNESS_ASLEEP:
@@ -148,4 +157,6 @@ public abstract class PowerManagerInternal {
public abstract void updateUidProcState(int uid, int procState);
public abstract void uidGone(int uid);
+
+ public abstract void powerHint(int hintId, int data);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 501b771ec67a..33f94763608d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3283,7 +3283,6 @@ public final class Settings {
DOCK_SOUNDS_ENABLED, // moved to global
LOCKSCREEN_SOUNDS_ENABLED,
SHOW_WEB_SUGGESTIONS,
- NOTIFICATION_LIGHT_PULSE,
SIP_CALL_OPTIONS,
SIP_RECEIVE_CALLS,
POINTER_SPEED,
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 35c41928f214..1269ad93d306 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -16,7 +16,10 @@
package android.view;
+import android.annotation.RequiresPermission;
+import android.content.Context;
import android.content.res.CompatibilityInfo;
+import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -30,6 +33,8 @@ import android.util.Log;
import java.util.Arrays;
+import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM;
+
/**
* Provides information about the size and density of a logical display.
* <p>
@@ -679,6 +684,49 @@ public final class Display {
}
/**
+ * Request the display applies a color transform.
+ * @hide
+ */
+ @RequiresPermission(CONFIGURE_DISPLAY_COLOR_TRANSFORM)
+ public void requestColorTransform(ColorTransform colorTransform) {
+ mGlobal.requestColorTransform(mDisplayId, colorTransform.getId());
+ }
+
+ /**
+ * Returns the active color transform of this display
+ * @hide
+ */
+ public ColorTransform getColorTransform() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mDisplayInfo.getColorTransform();
+ }
+ }
+
+ /**
+ * Returns the default color transform of this display
+ * @hide
+ */
+ public ColorTransform getDefaultColorTransform() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mDisplayInfo.getDefaultColorTransform();
+ }
+ }
+
+ /**
+ * Gets the supported color transforms of this device.
+ * @hide
+ */
+ public ColorTransform[] getSupportedColorTransforms() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ ColorTransform[] transforms = mDisplayInfo.supportedColorTransforms;
+ return Arrays.copyOf(transforms, transforms.length);
+ }
+ }
+
+ /**
* Gets the app VSYNC offset, in nanoseconds. This is a positive value indicating
* the phase offset of the VSYNC events provided by Choreographer relative to the
* display refresh. For example, if Choreographer reports that the refresh occurred
@@ -1054,4 +1102,89 @@ public final class Display {
}
};
}
+
+ /**
+ * A color transform supported by a given display.
+ *
+ * @see Display#getSupportedColorTransforms()
+ * @hide
+ */
+ public static final class ColorTransform implements Parcelable {
+ public static final ColorTransform[] EMPTY_ARRAY = new ColorTransform[0];
+
+ private final int mId;
+ private final int mColorTransform;
+
+ public ColorTransform(int id, int colorTransform) {
+ mId = id;
+ mColorTransform = colorTransform;
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public int getColorTransform() {
+ return mColorTransform;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof ColorTransform)) {
+ return false;
+ }
+ ColorTransform that = (ColorTransform) other;
+ return mId == that.mId
+ && mColorTransform == that.mColorTransform;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 1;
+ hash = hash * 17 + mId;
+ hash = hash * 17 + mColorTransform;
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return new StringBuilder("{")
+ .append("id=").append(mId)
+ .append(", colorTransform=").append(mColorTransform)
+ .append("}")
+ .toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ private ColorTransform(Parcel in) {
+ this(in.readInt(), in.readInt());
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int parcelableFlags) {
+ out.writeInt(mId);
+ out.writeInt(mColorTransform);
+ }
+
+ @SuppressWarnings("hiding")
+ public static final Parcelable.Creator<ColorTransform> CREATOR
+ = new Parcelable.Creator<ColorTransform>() {
+ @Override
+ public ColorTransform createFromParcel(Parcel in) {
+ return new ColorTransform(in);
+ }
+
+ @Override
+ public ColorTransform[] newArray(int size) {
+ return new ColorTransform[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index cf1799040f5f..ee76274ca5a6 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -169,6 +169,15 @@ public final class DisplayInfo implements Parcelable {
*/
public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
+ /** The active color transform. */
+ public int colorTransformId;
+
+ /** The default color transform. */
+ public int defaultColorTransformId;
+
+ /** The list of supported color transforms */
+ public Display.ColorTransform[] supportedColorTransforms = Display.ColorTransform.EMPTY_ARRAY;
+
/**
* The logical display density which is the basis for density-independent
* pixels.
@@ -279,6 +288,8 @@ public final class DisplayInfo implements Parcelable {
&& rotation == other.rotation
&& modeId == other.modeId
&& defaultModeId == other.defaultModeId
+ && colorTransformId == other.colorTransformId
+ && defaultColorTransformId == other.defaultColorTransformId
&& logicalDensityDpi == other.logicalDensityDpi
&& physicalXDpi == other.physicalXDpi
&& physicalYDpi == other.physicalYDpi
@@ -317,6 +328,10 @@ public final class DisplayInfo implements Parcelable {
modeId = other.modeId;
defaultModeId = other.defaultModeId;
supportedModes = Arrays.copyOf(other.supportedModes, other.supportedModes.length);
+ colorTransformId = other.colorTransformId;
+ defaultColorTransformId = other.defaultColorTransformId;
+ supportedColorTransforms = Arrays.copyOf(
+ other.supportedColorTransforms, other.supportedColorTransforms.length);
logicalDensityDpi = other.logicalDensityDpi;
physicalXDpi = other.physicalXDpi;
physicalYDpi = other.physicalYDpi;
@@ -353,6 +368,13 @@ public final class DisplayInfo implements Parcelable {
for (int i = 0; i < nModes; i++) {
supportedModes[i] = Display.Mode.CREATOR.createFromParcel(source);
}
+ colorTransformId = source.readInt();
+ defaultColorTransformId = source.readInt();
+ int nColorTransforms = source.readInt();
+ supportedColorTransforms = new Display.ColorTransform[nColorTransforms];
+ for (int i = 0; i < nColorTransforms; i++) {
+ supportedColorTransforms[i] = Display.ColorTransform.CREATOR.createFromParcel(source);
+ }
logicalDensityDpi = source.readInt();
physicalXDpi = source.readFloat();
physicalYDpi = source.readFloat();
@@ -390,6 +412,12 @@ public final class DisplayInfo implements Parcelable {
for (int i = 0; i < supportedModes.length; i++) {
supportedModes[i].writeToParcel(dest, flags);
}
+ dest.writeInt(colorTransformId);
+ dest.writeInt(defaultColorTransformId);
+ dest.writeInt(supportedColorTransforms.length);
+ for (int i = 0; i < supportedColorTransforms.length; i++) {
+ supportedColorTransforms[i].writeToParcel(dest, flags);
+ }
dest.writeInt(logicalDensityDpi);
dest.writeFloat(physicalXDpi);
dest.writeFloat(physicalYDpi);
@@ -461,6 +489,24 @@ public final class DisplayInfo implements Parcelable {
return result;
}
+ public Display.ColorTransform getColorTransform() {
+ return findColorTransform(colorTransformId);
+ }
+
+ public Display.ColorTransform getDefaultColorTransform() {
+ return findColorTransform(defaultColorTransformId);
+ }
+
+ private Display.ColorTransform findColorTransform(int colorTransformId) {
+ for (int i = 0; i < supportedColorTransforms.length; i++) {
+ Display.ColorTransform colorTransform = supportedColorTransforms[i];
+ if (colorTransform.getId() == colorTransformId) {
+ return colorTransform;
+ }
+ }
+ throw new IllegalStateException("Unable to locate color transform: " + colorTransformId);
+ }
+
public void getAppMetrics(DisplayMetrics outMetrics) {
getAppMetrics(outMetrics, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
}
@@ -562,6 +608,12 @@ public final class DisplayInfo implements Parcelable {
sb.append(defaultModeId);
sb.append(", modes ");
sb.append(Arrays.toString(supportedModes));
+ sb.append(", colorTransformId ");
+ sb.append(colorTransformId);
+ sb.append(", defaultColorTransformId ");
+ sb.append(defaultColorTransformId);
+ sb.append(", supportedColorTransforms ");
+ sb.append(Arrays.toString(supportedColorTransforms));
sb.append(", rotation ");
sb.append(rotation);
sb.append(", density ");
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3b7f6aa0dc21..43c578fe7faf 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7391,7 +7391,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
public void getOutsets(Rect outOutsetRect) {
- outOutsetRect.set(mAttachInfo.mOutsets);
+ if (mAttachInfo != null) {
+ outOutsetRect.set(mAttachInfo.mOutsets);
+ } else {
+ outOutsetRect.setEmpty();
+ }
}
/**
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index ed858e7a9836..6e9a41857851 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2395,6 +2395,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
lp.itemId = mAdapter.getItemId(position);
}
lp.viewType = mAdapter.getItemViewType(position);
+ lp.isEnabled = mAdapter.isEnabled(position);
if (lp != vlp) {
child.setLayoutParams(lp);
}
@@ -2416,19 +2417,33 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
}
final int position = getPositionForView(host);
- final ListAdapter adapter = getAdapter();
-
- if ((position == INVALID_POSITION) || (adapter == null)) {
+ if (position == INVALID_POSITION || mAdapter == null) {
// Cannot perform actions on invalid items.
return false;
}
- if (!isEnabled() || !adapter.isEnabled(position)) {
- // Cannot perform actions on disabled items.
+ if (position >= mAdapter.getCount()) {
+ // The position is no longer valid, likely due to a data set
+ // change. We could fail here for all data set changes, since
+ // there is a chance that the data bound to the view may no
+ // longer exist at the same position within the adapter, but
+ // it's more consistent with the standard touch interaction to
+ // click at whatever may have moved into that position.
return false;
}
- final long id = getItemIdAtPosition(position);
+ final boolean isItemEnabled;
+ final ViewGroup.LayoutParams lp = host.getLayoutParams();
+ if (lp instanceof AbsListView.LayoutParams) {
+ isItemEnabled = ((AbsListView.LayoutParams) lp).isEnabled;
+ } else {
+ isItemEnabled = false;
+ }
+
+ if (!isEnabled() || !isItemEnabled) {
+ // Cannot perform actions on disabled items.
+ return false;
+ }
switch (action) {
case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: {
@@ -2445,11 +2460,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
} return false;
case AccessibilityNodeInfo.ACTION_CLICK: {
if (isClickable()) {
+ final long id = getItemIdAtPosition(position);
return performItemClick(host, position, id);
}
} return false;
case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
if (isLongClickable()) {
+ final long id = getItemIdAtPosition(position);
return performLongPress(host, position, id);
}
} return false;
@@ -2469,13 +2486,20 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
public void onInitializeAccessibilityNodeInfoForItem(
View view, int position, AccessibilityNodeInfo info) {
- final ListAdapter adapter = getAdapter();
- if (position == INVALID_POSITION || adapter == null) {
+ if (position == INVALID_POSITION) {
// The item doesn't exist, so there's not much we can do here.
return;
}
- if (!isEnabled() || !adapter.isEnabled(position)) {
+ final boolean isItemEnabled;
+ final ViewGroup.LayoutParams lp = view.getLayoutParams();
+ if (lp instanceof AbsListView.LayoutParams) {
+ isItemEnabled = ((AbsListView.LayoutParams) lp).isEnabled;
+ } else {
+ isItemEnabled = false;
+ }
+
+ if (!isEnabled() || !isItemEnabled) {
info.setEnabled(false);
return;
}
@@ -6315,6 +6339,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
*/
long itemId = -1;
+ /** Whether the adapter considers the item enabled. */
+ boolean isEnabled;
+
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}
@@ -6340,6 +6367,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
encoder.addProperty("list:viewType", viewType);
encoder.addProperty("list:recycledHeaderFooter", recycledHeaderFooter);
encoder.addProperty("list:forceAdd", forceAdd);
+ encoder.addProperty("list:isEnabled", isEnabled);
}
}
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 0cc1b25d19b7..2cfefba10c57 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -600,13 +600,20 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
}
/**
- * Get the position within the adapter's data set for the view, where view is a an adapter item
- * or a descendant of an adapter item.
+ * Returns the position within the adapter's data set for the view, where
+ * view is a an adapter item or a descendant of an adapter item.
+ * <p>
+ * <strong>Note:</strong> The result of this method only reflects the
+ * position of the data bound to <var>view</var> during the most recent
+ * layout pass. If the adapter's data set has changed without a subsequent
+ * layout pass, the position returned by this method may not match the
+ * current position of the data within the adapter.
*
- * @param view an adapter item, or a descendant of an adapter item. This must be visible in this
- * AdapterView at the time of the call.
- * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION}
- * if the view does not correspond to a list item (or it is not currently visible).
+ * @param view an adapter item, or a descendant of an adapter item. This
+ * must be visible in this AdapterView at the time of the call.
+ * @return the position within the adapter's data set of the view, or
+ * {@link #INVALID_POSITION} if the view does not correspond to a
+ * list item (or it is not currently visible)
*/
public int getPositionForView(View view) {
View listItem = view;
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index f994d4ad91be..607e955d5698 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1070,6 +1070,7 @@ public class GridView extends AbsListView {
child.setLayoutParams(p);
}
p.viewType = mAdapter.getItemViewType(0);
+ p.isEnabled = mAdapter.isEnabled(0);
p.forceAdd = true;
int childHeightSpec = getChildMeasureSpec(
@@ -1480,6 +1481,7 @@ public class GridView extends AbsListView {
p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
}
p.viewType = mAdapter.getItemViewType(position);
+ p.isEnabled = mAdapter.isEnabled(position);
if (recycled && !p.forceAdd) {
attachViewToParent(child, where, p);
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index c5632ec91fe4..00d017f9f576 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1200,6 +1200,7 @@ public class ListView extends AbsListView {
child.setLayoutParams(p);
}
p.viewType = mAdapter.getItemViewType(position);
+ p.isEnabled = mAdapter.isEnabled(position);
p.forceAdd = true;
final int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
@@ -1913,6 +1914,7 @@ public class ListView extends AbsListView {
p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
}
p.viewType = mAdapter.getItemViewType(position);
+ p.isEnabled = mAdapter.isEnabled(position);
if ((recycled && !p.forceAdd) || (p.recycledHeaderFooter
&& p.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index d9faece9485f..3219dcb5ad8b 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -104,6 +104,7 @@ public class ChooserActivity extends ResolverActivity {
sri.resultTargets);
}
unbindService(sri.connection);
+ sri.connection.destroy();
mServiceConnections.remove(sri.connection);
if (mServiceConnections.isEmpty()) {
mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
@@ -208,6 +209,8 @@ public class ChooserActivity extends ResolverActivity {
mRefinementResultReceiver.destroy();
mRefinementResultReceiver = null;
}
+ unbindRemainingServices();
+ mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_RESULT);
}
@Override
@@ -265,6 +268,11 @@ public class ChooserActivity extends ResolverActivity {
return true;
}
+ @Override
+ boolean shouldAutoLaunchSingleChoice() {
+ return false;
+ }
+
private void modifyTargetIntent(Intent in) {
final String action = in.getAction();
if (Intent.ACTION_SEND.equals(action) ||
@@ -371,7 +379,8 @@ public class ChooserActivity extends ResolverActivity {
continue;
}
- final ChooserTargetServiceConnection conn = new ChooserTargetServiceConnection(dri);
+ final ChooserTargetServiceConnection conn =
+ new ChooserTargetServiceConnection(this, dri);
if (bindServiceAsUser(serviceIntent, conn, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND,
UserHandle.CURRENT)) {
if (DEBUG) {
@@ -425,6 +434,7 @@ public class ChooserActivity extends ResolverActivity {
final ChooserTargetServiceConnection conn = mServiceConnections.get(i);
if (DEBUG) Log.d(TAG, "unbinding " + conn);
unbindService(conn);
+ conn.destroy();
}
mServiceConnections.clear();
mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
@@ -637,7 +647,8 @@ public class ChooserActivity extends ResolverActivity {
@Override
public CharSequence getExtendedInfo() {
- return mSourceInfo != null ? mSourceInfo.getExtendedInfo() : null;
+ // ChooserTargets have badge icons, so we won't show the extended info to disambiguate.
+ return null;
}
@Override
@@ -730,9 +741,8 @@ public class ChooserActivity extends ResolverActivity {
@Override
public boolean showsExtendedInfo(TargetInfo info) {
- // Reserve space to show extended info if any one of the items in the adapter has
- // extended info. This keeps grid item sizes uniform.
- return hasExtendedInfo();
+ // We have badges so we don't need this text shown.
+ return false;
}
@Override
@@ -1024,54 +1034,93 @@ public class ChooserActivity extends ResolverActivity {
}
}
- class ChooserTargetServiceConnection implements ServiceConnection {
+ static class ChooserTargetServiceConnection implements ServiceConnection {
private final DisplayResolveInfo mOriginalTarget;
+ private ComponentName mConnectedComponent;
+ private ChooserActivity mChooserActivity;
+ private final Object mLock = new Object();
private final IChooserTargetResult mChooserTargetResult = new IChooserTargetResult.Stub() {
@Override
public void sendResult(List<ChooserTarget> targets) throws RemoteException {
- filterServiceTargets(mOriginalTarget.getResolveInfo().activityInfo.packageName,
- targets);
- final Message msg = Message.obtain();
- msg.what = CHOOSER_TARGET_SERVICE_RESULT;
- msg.obj = new ServiceResultInfo(mOriginalTarget, targets,
- ChooserTargetServiceConnection.this);
- mChooserHandler.sendMessage(msg);
+ synchronized (mLock) {
+ if (mChooserActivity == null) {
+ Log.e(TAG, "destroyed ChooserTargetServiceConnection received result from "
+ + mConnectedComponent + "; ignoring...");
+ return;
+ }
+ mChooserActivity.filterServiceTargets(
+ mOriginalTarget.getResolveInfo().activityInfo.packageName, targets);
+ final Message msg = Message.obtain();
+ msg.what = CHOOSER_TARGET_SERVICE_RESULT;
+ msg.obj = new ServiceResultInfo(mOriginalTarget, targets,
+ ChooserTargetServiceConnection.this);
+ mChooserActivity.mChooserHandler.sendMessage(msg);
+ }
}
};
- public ChooserTargetServiceConnection(DisplayResolveInfo dri) {
+ public ChooserTargetServiceConnection(ChooserActivity chooserActivity,
+ DisplayResolveInfo dri) {
+ mChooserActivity = chooserActivity;
mOriginalTarget = dri;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Log.d(TAG, "onServiceConnected: " + name);
- final IChooserTargetService icts = IChooserTargetService.Stub.asInterface(service);
- try {
- icts.getChooserTargets(mOriginalTarget.getResolvedComponentName(),
- mOriginalTarget.getResolveInfo().filter, mChooserTargetResult);
- } catch (RemoteException e) {
- Log.e(TAG, "Querying ChooserTargetService " + name + " failed.", e);
- unbindService(this);
- mServiceConnections.remove(this);
+ synchronized (mLock) {
+ if (mChooserActivity == null) {
+ Log.e(TAG, "destroyed ChooserTargetServiceConnection got onServiceConnected");
+ return;
+ }
+
+ final IChooserTargetService icts = IChooserTargetService.Stub.asInterface(service);
+ try {
+ icts.getChooserTargets(mOriginalTarget.getResolvedComponentName(),
+ mOriginalTarget.getResolveInfo().filter, mChooserTargetResult);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Querying ChooserTargetService " + name + " failed.", e);
+ mChooserActivity.unbindService(this);
+ destroy();
+ mChooserActivity.mServiceConnections.remove(this);
+ }
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.d(TAG, "onServiceDisconnected: " + name);
- unbindService(this);
- mServiceConnections.remove(this);
- if (mServiceConnections.isEmpty()) {
- mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
- sendVoiceChoicesIfNeeded();
+ synchronized (mLock) {
+ if (mChooserActivity == null) {
+ Log.e(TAG,
+ "destroyed ChooserTargetServiceConnection got onServiceDisconnected");
+ return;
+ }
+
+ mChooserActivity.unbindService(this);
+ destroy();
+ mChooserActivity.mServiceConnections.remove(this);
+ if (mChooserActivity.mServiceConnections.isEmpty()) {
+ mChooserActivity.mChooserHandler.removeMessages(
+ CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
+ mChooserActivity.sendVoiceChoicesIfNeeded();
+ }
+ mConnectedComponent = null;
+ }
+ }
+
+ public void destroy() {
+ synchronized (mLock) {
+ mChooserActivity = null;
}
}
@Override
public String toString() {
- return mOriginalTarget.getResolveInfo().activityInfo.toString();
+ return "ChooserTargetServiceConnection{service="
+ + mConnectedComponent + ", activity="
+ + mOriginalTarget.getResolveInfo().activityInfo.toString() + "}";
}
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 7dd3bed079fc..ef9d1cebff57 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -234,7 +234,9 @@ public class ResolverActivity extends Activity {
mResolverComparator = new ResolverComparator(this, getTargetIntent(), referrerPackage);
- configureContentView(mIntents, initialIntents, rList, alwaysUseOption);
+ if (configureContentView(mIntents, initialIntents, rList, alwaysUseOption)) {
+ return;
+ }
// Prevent the Resolver window from becoming the top fullscreen window and thus from taking
// control of the system bars.
@@ -794,6 +796,10 @@ public class ResolverActivity extends Activity {
return false;
}
+ boolean shouldAutoLaunchSingleChoice() {
+ return true;
+ }
+
void showAppDetails(ResolveInfo ri) {
Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
.setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
@@ -808,7 +814,10 @@ public class ResolverActivity extends Activity {
launchedFromUid, filterLastUsed);
}
- void configureContentView(List<Intent> payloadIntents, Intent[] initialIntents,
+ /**
+ * Returns true if the activity is finishing and creation should halt
+ */
+ boolean configureContentView(List<Intent> payloadIntents, Intent[] initialIntents,
List<ResolveInfo> rList, boolean alwaysUseOption) {
// The last argument of createAdapter is whether to do special handling
// of the last used choice to highlight it in the list. We need to always
@@ -828,7 +837,9 @@ public class ResolverActivity extends Activity {
mAlwaysUseOption = alwaysUseOption;
int count = mAdapter.getUnfilteredCount();
- if (count > 1 || (count == 1 && mAdapter.getOtherProfile() != null)) {
+ if ((!shouldAutoLaunchSingleChoice() && count > 0)
+ || count > 1
+ || (count == 1 && mAdapter.getOtherProfile() != null)) {
setContentView(layoutId);
mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
onPrepareAdapterView(mAdapterView, mAdapter, alwaysUseOption);
@@ -837,7 +848,7 @@ public class ResolverActivity extends Activity {
mPackageMonitor.unregister();
mRegistered = false;
finish();
- return;
+ return true;
} else {
setContentView(R.layout.resolver_list);
@@ -847,6 +858,7 @@ public class ResolverActivity extends Activity {
mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
mAdapterView.setVisibility(View.GONE);
}
+ return false;
}
void onPrepareAdapterView(AbsListView adapterView, ResolveListAdapter adapter,
@@ -884,6 +896,7 @@ public class ResolverActivity extends Activity {
private final ResolveInfo mResolveInfo;
private final CharSequence mDisplayLabel;
private Drawable mDisplayIcon;
+ private Drawable mBadge;
private final CharSequence mExtendedInfo;
private final Intent mResolvedIntent;
private final List<Intent> mSourceIntents = new ArrayList<>();
@@ -928,7 +941,25 @@ public class ResolverActivity extends Activity {
}
public Drawable getBadgeIcon() {
- return null;
+ // We only expose a badge if we have extended info.
+ // The badge is a higher-priority disambiguation signal
+ // but we don't need one if we wouldn't show extended info at all.
+ if (TextUtils.isEmpty(getExtendedInfo())) {
+ return null;
+ }
+
+ if (mBadge == null && mResolveInfo != null && mResolveInfo.activityInfo != null
+ && mResolveInfo.activityInfo.applicationInfo != null) {
+ if (mResolveInfo.activityInfo.icon == 0 || mResolveInfo.activityInfo.icon
+ == mResolveInfo.activityInfo.applicationInfo.icon) {
+ // Badging an icon with exactly the same icon is silly.
+ // If the activityInfo icon resid is 0 it will fall back
+ // to the application's icon, making it a match.
+ return null;
+ }
+ mBadge = mResolveInfo.activityInfo.applicationInfo.loadIcon(mPm);
+ }
+ return mBadge;
}
@Override
@@ -1366,8 +1397,8 @@ public class ResolverActivity extends Activity {
} else {
mHasExtendedInfo = true;
boolean usePkg = false;
- CharSequence startApp = ro.getResolveInfoAt(0).activityInfo.applicationInfo
- .loadLabel(mPm);
+ final ApplicationInfo ai = ro.getResolveInfoAt(0).activityInfo.applicationInfo;
+ final CharSequence startApp = ai.loadLabel(mPm);
if (startApp == null) {
usePkg = true;
}
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 4f4d3e0faa44..f178c8cf7ece 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -338,7 +338,7 @@ public final class BatteryStatsHelper {
}
if (mCpuPowerCalculator == null) {
- mCpuPowerCalculator = new CpuPowerCalculator();
+ mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
}
mCpuPowerCalculator.reset();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 4ff786987028..6ccdd08498ce 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -105,7 +105,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 130 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 131 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -118,8 +118,6 @@ public final class BatteryStatsImpl extends BatteryStats {
// in to one common name.
private static final int MAX_WAKELOCKS_PER_UID = 100;
- private static int sNumSpeedSteps;
-
private final JournaledFile mFile;
public final AtomicFile mCheckinFile;
public final AtomicFile mDailyFile;
@@ -133,7 +131,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
private final KernelUidCpuTimeReader mKernelUidCpuTimeReader = new KernelUidCpuTimeReader();
- private final KernelCpuSpeedReader mKernelCpuSpeedReader = new KernelCpuSpeedReader();
+ private KernelCpuSpeedReader[] mKernelCpuSpeedReaders;
public interface BatteryCallback {
public void batteryNeedsCpuUpdate();
@@ -4411,7 +4409,7 @@ public final class BatteryStatsImpl extends BatteryStats {
LongSamplingCounter mUserCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
LongSamplingCounter mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase);
LongSamplingCounter mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase);
- LongSamplingCounter[] mSpeedBins;
+ LongSamplingCounter[][] mCpuClusterSpeed;
/**
* The statistics we have collected for this uid's wake locks.
@@ -4470,7 +4468,6 @@ public final class BatteryStatsImpl extends BatteryStats {
mWifiMulticastTimer = new StopwatchTimer(Uid.this, WIFI_MULTICAST_ENABLED,
mWifiMulticastTimers, mOnBatteryTimeBase);
mProcessStateTimer = new StopwatchTimer[NUM_PROCESS_STATE];
- mSpeedBins = new LongSamplingCounter[getCpuSpeedSteps()];
}
@Override
@@ -5008,10 +5005,18 @@ public final class BatteryStatsImpl extends BatteryStats {
}
@Override
- public long getTimeAtCpuSpeed(int step, int which) {
- if (step >= 0 && step < mSpeedBins.length) {
- if (mSpeedBins[step] != null) {
- return mSpeedBins[step].getCountLocked(which);
+ public long getTimeAtCpuSpeed(int cluster, int step, int which) {
+ if (mCpuClusterSpeed != null) {
+ if (cluster >= 0 && cluster < mCpuClusterSpeed.length) {
+ final LongSamplingCounter[] cpuSpeeds = mCpuClusterSpeed[cluster];
+ if (cpuSpeeds != null) {
+ if (step >= 0 && step < cpuSpeeds.length) {
+ final LongSamplingCounter c = cpuSpeeds[step];
+ if (c != null) {
+ return c.getCountLocked(which);
+ }
+ }
+ }
}
}
return 0;
@@ -5128,10 +5133,16 @@ public final class BatteryStatsImpl extends BatteryStats {
mUserCpuTime.reset(false);
mSystemCpuTime.reset(false);
mCpuPower.reset(false);
- for (int i = 0; i < mSpeedBins.length; i++) {
- LongSamplingCounter c = mSpeedBins[i];
- if (c != null) {
- c.reset(false);
+
+ if (mCpuClusterSpeed != null) {
+ for (LongSamplingCounter[] speeds : mCpuClusterSpeed) {
+ if (speeds != null) {
+ for (LongSamplingCounter speed : speeds) {
+ if (speed != null) {
+ speed.reset(false);
+ }
+ }
+ }
}
}
@@ -5280,10 +5291,16 @@ public final class BatteryStatsImpl extends BatteryStats {
mUserCpuTime.detach();
mSystemCpuTime.detach();
mCpuPower.detach();
- for (int i = 0; i < mSpeedBins.length; i++) {
- LongSamplingCounter c = mSpeedBins[i];
- if (c != null) {
- c.detach();
+
+ if (mCpuClusterSpeed != null) {
+ for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeed) {
+ if (cpuSpeeds != null) {
+ for (LongSamplingCounter c : cpuSpeeds) {
+ if (c != null) {
+ c.detach();
+ }
+ }
+ }
}
}
}
@@ -5461,15 +5478,27 @@ public final class BatteryStatsImpl extends BatteryStats {
mSystemCpuTime.writeToParcel(out);
mCpuPower.writeToParcel(out);
- out.writeInt(mSpeedBins.length);
- for (int i = 0; i < mSpeedBins.length; i++) {
- LongSamplingCounter c = mSpeedBins[i];
- if (c != null) {
- out.writeInt(1);
- c.writeToParcel(out);
- } else {
- out.writeInt(0);
+ if (mCpuClusterSpeed != null) {
+ out.writeInt(1);
+ out.writeInt(mCpuClusterSpeed.length);
+ for (LongSamplingCounter[] cpuSpeeds : mCpuClusterSpeed) {
+ if (cpuSpeeds != null) {
+ out.writeInt(1);
+ out.writeInt(cpuSpeeds.length);
+ for (LongSamplingCounter c : cpuSpeeds) {
+ if (c != null) {
+ out.writeInt(1);
+ c.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
+ } else {
+ out.writeInt(0);
+ }
}
+ } else {
+ out.writeInt(0);
}
}
@@ -5653,13 +5682,32 @@ public final class BatteryStatsImpl extends BatteryStats {
mSystemCpuTime = new LongSamplingCounter(mOnBatteryTimeBase, in);
mCpuPower = new LongSamplingCounter(mOnBatteryTimeBase, in);
- int bins = in.readInt();
- int steps = getCpuSpeedSteps();
- mSpeedBins = new LongSamplingCounter[bins >= steps ? bins : steps];
- for (int i = 0; i < bins; i++) {
- if (in.readInt() != 0) {
- mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ if (in.readInt() != 0) {
+ int numCpuClusters = in.readInt();
+ if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numCpuClusters) {
+ throw new ParcelFormatException("Incompatible number of cpu clusters");
+ }
+
+ mCpuClusterSpeed = new LongSamplingCounter[numCpuClusters][];
+ for (int cluster = 0; cluster < numCpuClusters; cluster++) {
+ if (in.readInt() != 0) {
+ int numSpeeds = in.readInt();
+ if (mPowerProfile != null &&
+ mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != numSpeeds) {
+ throw new ParcelFormatException("Incompatible number of cpu speeds");
+ }
+
+ final LongSamplingCounter[] cpuSpeeds = new LongSamplingCounter[numSpeeds];
+ mCpuClusterSpeed[cluster] = cpuSpeeds;
+ for (int speed = 0; speed < numSpeeds; speed++) {
+ if (in.readInt() != 0) {
+ cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+ }
+ }
+ }
}
+ } else {
+ mCpuClusterSpeed = null;
}
}
@@ -6874,6 +6922,19 @@ public final class BatteryStatsImpl extends BatteryStats {
public void setPowerProfile(PowerProfile profile) {
synchronized (this) {
mPowerProfile = profile;
+
+ // We need to initialize the KernelCpuSpeedReaders to read from
+ // the first cpu of each core. Once we have the PowerProfile, we have access to this
+ // information.
+ final int numClusters = mPowerProfile.getNumCpuClusters();
+ mKernelCpuSpeedReaders = new KernelCpuSpeedReader[numClusters];
+ int firstCpuOfCluster = 0;
+ for (int i = 0; i < numClusters; i++) {
+ final int numSpeedSteps = mPowerProfile.getNumSpeedStepsInCpuCluster(i);
+ mKernelCpuSpeedReaders[i] = new KernelCpuSpeedReader(firstCpuOfCluster,
+ numSpeedSteps);
+ firstCpuOfCluster += mPowerProfile.getNumCoresInCpuCluster(i);
+ }
}
}
@@ -6881,10 +6942,6 @@ public final class BatteryStatsImpl extends BatteryStats {
mCallback = cb;
}
- public void setNumSpeedSteps(int steps) {
- if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
- }
-
public void setRadioScanningTimeout(long timeout) {
if (mPhoneSignalScanningTimer != null) {
mPhoneSignalScanningTimer.setTimeout(timeout);
@@ -7997,9 +8054,11 @@ public final class BatteryStatsImpl extends BatteryStats {
// If no app is holding a wakelock, then the distribution is normal.
final int wakelockWeight = 50;
- // Read the time spent at various cpu frequencies.
- final int cpuSpeedSteps = getCpuSpeedSteps();
- final long[] cpuSpeeds = mKernelCpuSpeedReader.readDelta();
+ // Read the time spent for each cluster at various cpu frequencies.
+ final long[][] clusterSpeeds = new long[mKernelCpuSpeedReaders.length][];
+ for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) {
+ clusterSpeeds[cluster] = mKernelCpuSpeedReaders[cluster].readDelta();
+ }
int numWakelocks = 0;
@@ -8072,11 +8131,23 @@ public final class BatteryStatsImpl extends BatteryStats {
// Add the cpu speeds to this UID. These are used as a ratio
// for computing the power this UID used.
- for (int i = 0; i < cpuSpeedSteps; i++) {
- if (u.mSpeedBins[i] == null) {
- u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase);
+ if (u.mCpuClusterSpeed == null) {
+ u.mCpuClusterSpeed = new LongSamplingCounter[clusterSpeeds.length][];
+ }
+
+ for (int cluster = 0; cluster < clusterSpeeds.length; cluster++) {
+ if (u.mCpuClusterSpeed[cluster] == null) {
+ u.mCpuClusterSpeed[cluster] =
+ new LongSamplingCounter[clusterSpeeds[cluster].length];
+ }
+
+ final LongSamplingCounter[] cpuSpeeds = u.mCpuClusterSpeed[cluster];
+ for (int speed = 0; speed < clusterSpeeds[cluster].length; speed++) {
+ if (cpuSpeeds[speed] == null) {
+ cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase);
+ }
+ cpuSpeeds[speed].addCountLocked(clusterSpeeds[cluster][speed]);
}
- u.mSpeedBins[i].addCountLocked(cpuSpeeds[i]);
}
}
});
@@ -8776,11 +8847,6 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- @Override
- public int getCpuSpeedSteps() {
- return sNumSpeedSteps;
- }
-
/**
* Retrieve the statistics object for a particular uid, creating if needed.
*/
@@ -9216,11 +9282,6 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- sNumSpeedSteps = in.readInt();
- if (sNumSpeedSteps < 0 || sNumSpeedSteps > 100) {
- throw new ParcelFormatException("Bad speed steps in data: " + sNumSpeedSteps);
- }
-
final int NU = in.readInt();
if (NU > 10000) {
throw new ParcelFormatException("File corrupt: too many uids " + NU);
@@ -9304,17 +9365,33 @@ public final class BatteryStatsImpl extends BatteryStats {
u.mSystemCpuTime.readSummaryFromParcelLocked(in);
u.mCpuPower.readSummaryFromParcelLocked(in);
- int NSB = in.readInt();
- if (NSB > 100) {
- throw new ParcelFormatException("File corrupt: too many speed bins " + NSB);
- }
+ if (in.readInt() != 0) {
+ final int numClusters = in.readInt();
+ if (mPowerProfile != null && mPowerProfile.getNumCpuClusters() != numClusters) {
+ throw new ParcelFormatException("Incompatible cpu cluster arrangement");
+ }
- u.mSpeedBins = new LongSamplingCounter[NSB];
- for (int i=0; i<NSB; i++) {
- if (in.readInt() != 0) {
- u.mSpeedBins[i] = new LongSamplingCounter(mOnBatteryTimeBase);
- u.mSpeedBins[i].readSummaryFromParcelLocked(in);
+ u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][];
+ for (int cluster = 0; cluster < numClusters; cluster++) {
+ int NSB = in.readInt();
+ if (mPowerProfile != null &&
+ mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) {
+ throw new ParcelFormatException("File corrupt: too many speed bins " + NSB);
+ }
+
+ if (in.readInt() != 0) {
+ u.mCpuClusterSpeed[cluster] = new LongSamplingCounter[NSB];
+ for (int speed = 0; speed < NSB; speed++) {
+ if (in.readInt() != 0) {
+ u.mCpuClusterSpeed[cluster][speed] = new LongSamplingCounter(
+ mOnBatteryTimeBase);
+ u.mCpuClusterSpeed[cluster][speed].readSummaryFromParcelLocked(in);
+ }
+ }
+ }
}
+ } else {
+ u.mCpuClusterSpeed = null;
}
int NW = in.readInt();
@@ -9531,7 +9608,6 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- out.writeInt(sNumSpeedSteps);
final int NU = mUidStats.size();
out.writeInt(NU);
for (int iu = 0; iu < NU; iu++) {
@@ -9640,15 +9716,27 @@ public final class BatteryStatsImpl extends BatteryStats {
u.mSystemCpuTime.writeSummaryFromParcelLocked(out);
u.mCpuPower.writeSummaryFromParcelLocked(out);
- out.writeInt(u.mSpeedBins.length);
- for (int i = 0; i < u.mSpeedBins.length; i++) {
- LongSamplingCounter speedBin = u.mSpeedBins[i];
- if (speedBin != null) {
- out.writeInt(1);
- speedBin.writeSummaryFromParcelLocked(out);
- } else {
- out.writeInt(0);
+ if (u.mCpuClusterSpeed != null) {
+ out.writeInt(1);
+ out.writeInt(u.mCpuClusterSpeed.length);
+ for (LongSamplingCounter[] cpuSpeeds : u.mCpuClusterSpeed) {
+ if (cpuSpeeds != null) {
+ out.writeInt(1);
+ out.writeInt(cpuSpeeds.length);
+ for (LongSamplingCounter c : cpuSpeeds) {
+ if (c != null) {
+ out.writeInt(1);
+ c.writeSummaryFromParcelLocked(out);
+ } else {
+ out.writeInt(0);
+ }
+ }
+ } else {
+ out.writeInt(0);
+ }
}
+ } else {
+ out.writeInt(0);
}
final ArrayMap<String, Uid.Wakelock> wakeStats = u.mWakelockStats.getMap();
@@ -9897,8 +9985,6 @@ public final class BatteryStatsImpl extends BatteryStats {
mFlashlightTurnedOnTimers.clear();
mCameraTurnedOnTimers.clear();
- sNumSpeedSteps = in.readInt();
-
int numUids = in.readInt();
mUidStats.clear();
for (int i = 0; i < numUids; i++) {
@@ -10037,8 +10123,6 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(0);
}
- out.writeInt(sNumSpeedSteps);
-
if (inclUids) {
int size = mUidStats.size();
out.writeInt(size);
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index d62f7a689157..8417856d16d5 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -22,12 +22,47 @@ import android.util.Log;
public class CpuPowerCalculator extends PowerCalculator {
private static final String TAG = "CpuPowerCalculator";
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
+ private final PowerProfile mProfile;
+
+ public CpuPowerCalculator(PowerProfile profile) {
+ mProfile = profile;
+ }
@Override
public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
long rawUptimeUs, int statsType) {
+
app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
- app.cpuPowerMah = (double) u.getCpuPowerMaUs(statsType) / (60.0 * 60.0 * 1000.0 * 1000.0);
+
+ // Aggregate total time spent on each cluster.
+ long totalTime = 0;
+ final int numClusters = mProfile.getNumCpuClusters();
+ for (int cluster = 0; cluster < numClusters; cluster++) {
+ final int speedsForCluster = mProfile.getNumSpeedStepsInCpuCluster(cluster);
+ for (int speed = 0; speed < speedsForCluster; speed++) {
+ totalTime += u.getTimeAtCpuSpeed(cluster, speed, statsType);
+ }
+ }
+ totalTime = Math.max(totalTime, 1);
+
+ double cpuPowerMaMs = 0;
+ for (int cluster = 0; cluster < numClusters; cluster++) {
+ final int speedsForCluster = mProfile.getNumSpeedStepsInCpuCluster(cluster);
+ for (int speed = 0; speed < speedsForCluster; speed++) {
+ final double ratio = (double) u.getTimeAtCpuSpeed(cluster, speed, statsType) /
+ totalTime;
+ final double cpuSpeedStepPower = ratio * app.cpuTimeMs *
+ mProfile.getAveragePowerForCpu(cluster, speed);
+ if (DEBUG && ratio != 0) {
+ Log.d(TAG, "UID " + u.getUid() + ": CPU cluster #" + cluster + " step #"
+ + speed + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power="
+ + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
+ }
+ cpuPowerMaMs += cpuSpeedStepPower;
+ }
+ }
+ app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000);
+
if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) {
Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + app.cpuTimeMs + " ms power="
+ BatteryStatsHelper.makemAh(app.cpuPowerMah));
diff --git a/core/java/com/android/internal/os/KernelCpuSpeedReader.java b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
index c30df28c5c1f..5b776acf0cc8 100644
--- a/core/java/com/android/internal/os/KernelCpuSpeedReader.java
+++ b/core/java/com/android/internal/os/KernelCpuSpeedReader.java
@@ -24,8 +24,8 @@ import java.io.IOException;
import java.util.Arrays;
/**
- * Reads CPU time spent at various frequencies and provides a delta from the last call to
- * {@link #readDelta}. Each line in the proc file has the format:
+ * Reads CPU time of a specific core spent at various frequencies and provides a delta from the
+ * last call to {@link #readDelta}. Each line in the proc file has the format:
*
* freq time
*
@@ -33,12 +33,20 @@ import java.util.Arrays;
*/
public class KernelCpuSpeedReader {
private static final String TAG = "KernelCpuSpeedReader";
- private static final String sProcFile =
- "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state";
- private static final int MAX_SPEEDS = 60;
- private long[] mLastSpeedTimes = new long[MAX_SPEEDS];
- private long[] mDeltaSpeedTimes = new long[MAX_SPEEDS];
+ private final String mProcFile;
+ private final long[] mLastSpeedTimes;
+ private final long[] mDeltaSpeedTimes;
+
+ /**
+ * @param cpuNumber The cpu (cpu0, cpu1, etc) whose state to read.
+ */
+ public KernelCpuSpeedReader(int cpuNumber, int numSpeedSteps) {
+ mProcFile = String.format("/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state",
+ cpuNumber);
+ mLastSpeedTimes = new long[numSpeedSteps];
+ mDeltaSpeedTimes = new long[numSpeedSteps];
+ }
/**
* The returned array is modified in subsequent calls to {@link #readDelta}.
@@ -46,22 +54,28 @@ public class KernelCpuSpeedReader {
* {@link #readDelta}.
*/
public long[] readDelta() {
- try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(mProcFile))) {
TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
String line;
int speedIndex = 0;
- while ((line = reader.readLine()) != null) {
+ while (speedIndex < mLastSpeedTimes.length && (line = reader.readLine()) != null) {
splitter.setString(line);
Long.parseLong(splitter.next());
// The proc file reports time in 1/100 sec, so convert to milliseconds.
long time = Long.parseLong(splitter.next()) * 10;
- mDeltaSpeedTimes[speedIndex] = time - mLastSpeedTimes[speedIndex];
+ if (time < mLastSpeedTimes[speedIndex]) {
+ // The stats reset when the cpu hotplugged. That means that the time
+ // we read is offset from 0, so the time is the delta.
+ mDeltaSpeedTimes[speedIndex] = time;
+ } else {
+ mDeltaSpeedTimes[speedIndex] = time - mLastSpeedTimes[speedIndex];
+ }
mLastSpeedTimes[speedIndex] = time;
speedIndex++;
}
} catch (IOException e) {
- Slog.e(TAG, "Failed to read cpu-freq", e);
+ Slog.e(TAG, "Failed to read cpu-freq: " + e.getMessage());
Arrays.fill(mDeltaSpeedTimes, 0);
}
return mDeltaSpeedTimes;
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index 0df78ed6a68d..5d3043cc8a02 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -137,7 +137,7 @@ public class KernelUidCpuTimeReader {
mLastPowerMaUs.put(uid, powerMaUs);
}
} catch (IOException e) {
- Slog.e(TAG, "Failed to read uid_cputime", e);
+ Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage());
}
mLastTimeReadUs = nowUs;
}
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 4ede8ddab3bc..aaa9f734aba8 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -59,6 +59,7 @@ public class PowerProfile {
/**
* Power consumption when CPU is in power collapse mode.
*/
+ @Deprecated
public static final String POWER_CPU_ACTIVE = "cpu.active";
/**
@@ -163,6 +164,7 @@ public class PowerProfile {
*/
public static final String POWER_CAMERA = "camera.avg";
+ @Deprecated
public static final String POWER_CPU_SPEEDS = "cpu.speeds";
/**
@@ -191,6 +193,7 @@ public class PowerProfile {
if (sPowerMap.size() == 0) {
readPowerValuesFromXml(context);
}
+ initCpuClusters();
}
private void readPowerValuesFromXml(Context context) {
@@ -249,7 +252,7 @@ public class PowerProfile {
}
// Now collect other config variables.
- int[] configResIds = new int[] {
+ int[] configResIds = new int[]{
com.android.internal.R.integer.config_bluetooth_idle_cur_ma,
com.android.internal.R.integer.config_bluetooth_rx_cur_ma,
com.android.internal.R.integer.config_bluetooth_tx_cur_ma,
@@ -260,7 +263,7 @@ public class PowerProfile {
com.android.internal.R.integer.config_wifi_operating_voltage_mv,
};
- String[] configResIdKeys = new String[] {
+ String[] configResIdKeys = new String[]{
POWER_BLUETOOTH_CONTROLLER_IDLE,
POWER_BLUETOOTH_CONTROLLER_RX,
POWER_BLUETOOTH_CONTROLLER_TX,
@@ -279,6 +282,69 @@ public class PowerProfile {
}
}
+ private CpuClusterKey[] mCpuClusters;
+
+ private static final String POWER_CPU_CLUSTER_CORE_COUNT = "cpu.clusters.cores";
+ private static final String POWER_CPU_CLUSTER_SPEED_PREFIX = "cpu.speeds.cluster";
+ private static final String POWER_CPU_CLUSTER_ACTIVE_PREFIX = "cpu.active.cluster";
+
+ @SuppressWarnings("deprecated")
+ private void initCpuClusters() {
+ // Figure out how many CPU clusters we're dealing with
+ final Object obj = sPowerMap.get(POWER_CPU_CLUSTER_CORE_COUNT);
+ if (obj == null || !(obj instanceof Double[])) {
+ // Default to single.
+ mCpuClusters = new CpuClusterKey[1];
+ mCpuClusters[0] = new CpuClusterKey(POWER_CPU_SPEEDS, POWER_CPU_ACTIVE, 1);
+
+ } else {
+ final Double[] array = (Double[]) obj;
+ mCpuClusters = new CpuClusterKey[array.length];
+ for (int cluster = 0; cluster < array.length; cluster++) {
+ int numCpusInCluster = (int) Math.round(array[cluster]);
+ mCpuClusters[cluster] = new CpuClusterKey(
+ POWER_CPU_CLUSTER_SPEED_PREFIX + cluster,
+ POWER_CPU_CLUSTER_ACTIVE_PREFIX + cluster,
+ numCpusInCluster);
+ }
+ }
+ }
+
+ public static class CpuClusterKey {
+ private final String timeKey;
+ private final String powerKey;
+ private final int numCpus;
+
+ private CpuClusterKey(String timeKey, String powerKey, int numCpus) {
+ this.timeKey = timeKey;
+ this.powerKey = powerKey;
+ this.numCpus = numCpus;
+ }
+ }
+
+ public int getNumCpuClusters() {
+ return mCpuClusters.length;
+ }
+
+ public int getNumCoresInCpuCluster(int index) {
+ return mCpuClusters[index].numCpus;
+ }
+
+ public int getNumSpeedStepsInCpuCluster(int index) {
+ Object value = sPowerMap.get(mCpuClusters[index].timeKey);
+ if (value != null && value instanceof Double[]) {
+ return ((Double[])value).length;
+ }
+ return 1; // Only one speed
+ }
+
+ public double getAveragePowerForCpu(int cluster, int step) {
+ if (cluster >= 0 && cluster < mCpuClusters.length) {
+ return getAveragePower(mCpuClusters[cluster].powerKey, step);
+ }
+ return 0;
+ }
+
/**
* Returns the average current in mA consumed by the subsystem, or the given
* default value if the subsystem has no recorded value.
@@ -344,16 +410,4 @@ public class PowerProfile {
public double getBatteryCapacity() {
return getAveragePower(POWER_BATTERY_CAPACITY);
}
-
- /**
- * Returns the number of speeds that the CPU can be run at.
- * @return
- */
- public int getNumSpeedSteps() {
- Object value = sPowerMap.get(POWER_CPU_SPEEDS);
- if (value != null && value instanceof Double[]) {
- return ((Double[])value).length;
- }
- return 1; // Only one speed
- }
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a873ef8e0f59..82ae2f3f032e 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1071,12 +1071,22 @@ public class LockPatternUtils {
* enter a pattern.
*/
public long getLockoutAttemptDeadline(int userId) {
- final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
+ long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId);
final long now = SystemClock.elapsedRealtime();
- if (deadline < now || deadline > (now + timeoutMs)) {
+ if (deadline < now) {
+ // timeout expired
+ setLong(LOCKOUT_ATTEMPT_DEADLINE, 0, userId);
+ setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId);
return 0L;
}
+
+ if (deadline > (now + timeoutMs)) {
+ // device was rebooted, set new deadline
+ deadline = now + timeoutMs;
+ setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
+ }
+
return deadline;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5f4dd31d0a2e..b051de490d49 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2167,6 +2167,13 @@
<permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
android:protectionLevel="signature" />
+ <!-- Allows an application to control the color transforms applied to
+ displays system-wide.
+ <p>Not for use by third-party applications.</p>
+ @hide -->
+ <permission android:name="android.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows an application to control VPN.
<p>Not for use by third-party applications.</p>
@hide -->
diff --git a/core/res/res/values-mcc240-mnc01/config.xml b/core/res/res/values-mcc240-mnc01/config.xml
new file mode 100644
index 000000000000..7fb5c46309d0
--- /dev/null
+++ b/core/res/res/values-mcc240-mnc01/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Do not set the system language as value of EF LI/EF PL -->
+ <bool name="config_use_sim_language_file">false</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc240-mnc05/config.xml b/core/res/res/values-mcc240-mnc05/config.xml
new file mode 100644
index 000000000000..7fb5c46309d0
--- /dev/null
+++ b/core/res/res/values-mcc240-mnc05/config.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Do not set the system language as value of EF LI/EF PL -->
+ <bool name="config_use_sim_language_file">false</bool>
+
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9e89b24ce919..33ef8f906b30 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1758,6 +1758,28 @@
-->
<bool name="config_enableWifiDisplay">false</bool>
+ <!-- The color transform values that correspond to each respective configuration mode for the
+ built-in display, or -1 if the mode is unsupported by the device. The possible
+ configuration modes are:
+ 1. Wide-gamut ("Vibrant")
+ 2. Adobe RGB ("Natural")
+ 3. sRGB ("Standard")
+
+ For example, if a device had Wide-gamut as color transform mode 1, sRGB mode as color
+ transform mode 7, and did not support Adobe RGB at all this would look like:
+
+ <integer-array name="config_colorTransforms">
+ <item>1</item>
+ <item>-1</item>
+ <item>7</item>
+ </integer-array>
+ -->
+ <integer-array name="config_colorTransforms">
+ <item>-1</item>
+ <item>-1</item>
+ <item>-1</item>
+ </integer-array>
+
<!-- When true use the linux /dev/input/event subsystem to detect the switch changes
on the headphone/microphone jack. When false use the older uevent framework. -->
<bool name="config_useDevInputEventForAudioJack">false</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 490d306d30b6..1122c6278227 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1134,6 +1134,7 @@
<java-symbol type="array" name="config_telephonyHardware" />
<java-symbol type="array" name="config_keySystemUuidMapping" />
<java-symbol type="array" name="config_gpsParameters" />
+ <java-symbol type="array" name="config_colorTransforms" />
<java-symbol type="drawable" name="default_wallpaper" />
<java-symbol type="drawable" name="indicator_input_error" />
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 28d99d8784db..ddd0ca2a4bb2 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -47,17 +47,38 @@
<value>0.2</value> <!-- ~2mA -->
<value>0.1</value> <!-- ~1mA -->
</array>
- <!-- Different CPU speeds as reported in
- /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state -->
- <array name="cpu.speeds">
+
+ <!-- A list of heterogeneous CPU clusters, where the value for each cluster represents the
+ number of CPU cores for that cluster.
+
+ Ex:
+ <array name="cpu.clusters.cores">
+ <value>4</value> // cluster 0 has cpu0, cpu1, cpu2, cpu3
+ <value>2</value> // cluster 1 has cpu4, cpu5
+ </array> -->
+ <array name="cpu.clusters.cores">
+ <value>1</value> <!-- cluster 0 has cpu0 -->
+ </array>
+
+ <!-- Different CPU speeds for cluster 0 as reported in
+ /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state.
+
+ There must be one of these for each cluster, labeled:
+ cpu.speeds.cluster0, cpu.speeds.cluster1, etc... -->
+ <array name="cpu.speeds.cluster0">
<value>400000</value> <!-- 400 MHz CPU speed -->
</array>
- <!-- Current when CPU is idle -->
- <item name="cpu.idle">0.1</item>
- <!-- Current at each CPU speed, as per 'cpu.speeds' -->
- <array name="cpu.active">
+
+ <!-- Current at each CPU speed for cluster 0, as per 'cpu.speeds.cluster0'.
+ Like cpu.speeds.cluster0, there must be one of these present for
+ each heterogeneous CPU cluster. -->
+ <array name="cpu.active.cluster0">
<value>0.1</value> <!-- ~100mA -->
</array>
+
+ <!-- Current when CPU is idle -->
+ <item name="cpu.idle">0.1</item>
+
<!-- This is the battery capacity in mAh (measured at nominal voltage) -->
<item name="battery.capacity">1000</item>
diff --git a/core/tests/BTtraffic/Android.mk b/core/tests/BTtraffic/Android.mk
new file mode 100644
index 000000000000..7d8352717a34
--- /dev/null
+++ b/core/tests/BTtraffic/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := \
+ $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := bttraffic
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/BTtraffic/AndroidManifest.xml b/core/tests/BTtraffic/AndroidManifest.xml
new file mode 100644
index 000000000000..00d9707de2bf
--- /dev/null
+++ b/core/tests/BTtraffic/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.experimental.bttraffic" >
+
+ <uses-permission android:name="android.permission.BLUETOOTH"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+
+ <uses-sdk
+ android:minSdkVersion="18"
+ android:targetSdkVersion="18"
+ />
+ <application
+ android:allowBackup="false"
+ android:label="@string/app_name" >
+ <service
+ android:name=".BTtraffic"
+ android:enabled="true"
+ android:exported="true" >
+ </service>
+ </application>
+
+</manifest>
diff --git a/core/tests/BTtraffic/README b/core/tests/BTtraffic/README
new file mode 100644
index 000000000000..430488f656f9
--- /dev/null
+++ b/core/tests/BTtraffic/README
@@ -0,0 +1,45 @@
+This is a tool to generate classic Bluetooth traffic with specified period and package size.
+Together with the SvcMonitor, which will be called automatically in this android service, can be
+used to measure the CPU usage from the Java layer Bluetooth code and the underlying system service
+com.android.bluetooth.
+
+1. Server (Listener) - Client (Sender) model. Both run as an Android service.
+2. No pairing needed. Communicate via unsecured RFcomm. Client establishes the connection by
+providing the MAC addr of the server.
+3. Bluetooth has to be turned on on both side.
+4. Client can configure the traffic by specifying the transfer period and package size.
+5. A separate monitor process will be automatically forked and will be reading from /proc file
+system to calculate the cpu usage. The measurement is updated once per second.
+6. The monitor process (com.google.android.experimental.svcmonitor/.ScvMonitor) can be run as an
+independent service to measure cpu usage on any similarly configured tests (e.g. wifi, BLE). Refer
+to SvcMonitor's README for usage and details.
+
+Usage:
+To instal the test:
+On both the server and client device, install the 2 apk:
+$ adb install $OUT/system/app/bttraffic/bttraffic.apk
+$ adb install $OUT/system/app/svcmonitor/svcmonitor.apk
+
+To start the service on the SERVER side:
+$ adb shell am startservice -a start --ez ack true \
+com.google.android.experimental.bttraffic/.BTtraffic
+
+To start the service on the CLIENT side:
+$ adb shell am startservice -a start \
+-e addr "F8:A9:D0:A8:74:8E" --ei size 1000 --ei period 15 \
+com.google.android.experimental.bttraffic/.BTtraffic
+
+To stop the test:
+On either the server or client:
+$ adb shell am startservice -a stop \
+com.google.android.experimental.bttraffic/.BTtraffic
+
+To look at the data:
+$ adb logcat | grep bttraffic
+
+Options:
+-e addr: MAC addr of the server, in uppercase letter.
+--ei size: package size, unit: byte; default: 1024, MAX: 20MB
+--ei period: system sleep time between sending each package, unit: ms, default: 5000
+ ** if -1 is provided, client will only send the package once.
+--ez ack: whether acknowledge is required (true/false)
diff --git a/core/tests/BTtraffic/res/values/strings.xml b/core/tests/BTtraffic/res/values/strings.xml
new file mode 100644
index 000000000000..e70276e03647
--- /dev/null
+++ b/core/tests/BTtraffic/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">Bluetooth Test</string>
+</resources>
diff --git a/core/tests/BTtraffic/src/com/android/google/experimental/bttraffic/BTtraffic.java b/core/tests/BTtraffic/src/com/android/google/experimental/bttraffic/BTtraffic.java
new file mode 100644
index 000000000000..286c0aa2915f
--- /dev/null
+++ b/core/tests/BTtraffic/src/com/android/google/experimental/bttraffic/BTtraffic.java
@@ -0,0 +1,328 @@
+package com.google.android.experimental.bttraffic;
+
+import android.app.Service;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSocket;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.Exception;
+import java.lang.Runtime;
+import java.lang.RuntimeException;
+import java.lang.Process;
+import java.nio.ByteBuffer;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+
+public class BTtraffic extends Service {
+ public static final String TAG = "bttraffic";
+ static final String SERVICE_NAME = "bttraffic";
+ static final String SYS_SERVICE_NAME = "com.android.bluetooth";
+ static final UUID SERVICE_UUID = UUID.fromString("5e8945b0-1234-5432-a5e2-0800200c9a67");
+ volatile Thread mWorkerThread;
+ volatile boolean isShuttingDown = false;
+ volatile boolean isServer = false;
+
+ public BTtraffic() {}
+
+ static void safeClose(Closeable closeable) {
+ try {
+ closeable.close();
+ } catch (IOException e) {
+ Log.d(TAG, "Unable to close resource.\n");
+ }
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent == null) {
+ stopSelf();
+ return 0;
+ }
+ if ("stop".equals(intent.getAction())) {
+ stopService();
+ } else if ("start".equals(intent.getAction())) {
+ startWorker(intent);
+ } else {
+ Log.d(TAG, "unknown action: + " + intent.getAction());
+ }
+ return 0;
+ }
+
+ private void startWorker(Intent intent) {
+ if (mWorkerThread != null) {
+ Log.d(TAG, "worker thread already active");
+ return;
+ }
+ isShuttingDown = false;
+ String remoteAddr = intent.getStringExtra("addr");
+ Log.d(TAG, "startWorker: addr=" + remoteAddr);
+ Runnable worker =
+ remoteAddr == null
+ ? new ListenerRunnable(this, intent)
+ : new SenderRunnable(this, remoteAddr, intent);
+ isServer = remoteAddr == null ? true: false;
+ mWorkerThread = new Thread(worker, "BTtrafficWorker");
+ try {
+ startMonitor();
+ Log.d(TAG, "Monitor service started");
+ mWorkerThread.start();
+ Log.d(TAG, "Worker thread started");
+ } catch (Exception e) {
+ Log.d(TAG, "Failed to start service", e);
+ }
+ }
+
+ private void startMonitor()
+ throws Exception {
+ if (isServer) {
+ Log.d(TAG, "Start monitor on server");
+ String[] startmonitorCmd = {
+ "/system/bin/am",
+ "startservice",
+ "-a", "start",
+ "-e", "java", SERVICE_NAME,
+ "-e", "hal", SYS_SERVICE_NAME,
+ "com.google.android.experimental.svcmonitor/.SvcMonitor"
+ };
+ Process ps = new ProcessBuilder()
+ .command(startmonitorCmd)
+ .redirectErrorStream(true)
+ .start();
+ } else {
+ Log.d(TAG, "No need to start SvcMonitor on client");
+ }
+ }
+
+ private void stopMonitor()
+ throws Exception {
+ if (isServer) {
+ Log.d(TAG, "StopMonitor on server");
+ String[] stopmonitorCmd = {
+ "/system/bin/am",
+ "startservice",
+ "-a", "stop",
+ "com.google.android.experimental.svcmonitor/.SvcMonitor"
+ };
+ Process ps = new ProcessBuilder()
+ .command(stopmonitorCmd)
+ .redirectErrorStream(true)
+ .start();
+ } else {
+ Log.d(TAG, "No need to stop Svcmonitor on client");
+ }
+ }
+
+ public void stopService() {
+ if (mWorkerThread == null) {
+ Log.d(TAG, "no active thread");
+ return;
+ }
+
+ isShuttingDown = true;
+
+ try {
+ stopMonitor();
+ } catch (Exception e) {
+ Log.d(TAG, "Unable to stop SvcMonitor!", e);
+ }
+
+ if (Thread.currentThread() != mWorkerThread) {
+ mWorkerThread.interrupt();
+ Log.d(TAG, "Interrupting thread");
+ try {
+ mWorkerThread.join();
+ } catch (InterruptedException e) {
+ Log.d(TAG, "Unable to join thread!");
+ }
+ }
+
+ mWorkerThread = null;
+ stopSelf();
+ Log.d(TAG, "Service stopped");
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+ public static class ListenerRunnable implements Runnable {
+ private final BTtraffic bttraffic;
+ private final boolean sendAck;
+ private Intent intent;
+ private final int maxbuffersize = 20 * 1024 * 1024;
+
+ public ListenerRunnable(BTtraffic bttraffic, Intent intent) {
+ this.bttraffic = bttraffic;
+ this.sendAck = intent.getBooleanExtra("ack", true);
+ this.intent = intent;
+ }
+
+ @Override
+ public void run() {
+ BluetoothServerSocket serverSocket;
+
+ try {
+ Log.d(TAG, "getting server socket");
+ serverSocket = BluetoothAdapter.getDefaultAdapter()
+ .listenUsingInsecureRfcommWithServiceRecord(
+ SERVICE_NAME, SERVICE_UUID);
+ } catch (IOException e) {
+ Log.d(TAG, "error creating server socket, stopping thread");
+ bttraffic.stopService();
+ return;
+ }
+
+ Log.d(TAG, "got server socket, starting accept loop");
+ BluetoothSocket socket = null;
+ try {
+ Log.d(TAG, "accepting");
+ socket = serverSocket.accept();
+
+ if (!Thread.interrupted()) {
+ Log.d(TAG, "accepted, listening");
+ doListening(socket.getInputStream(), socket.getOutputStream());
+ Log.d(TAG, "listen finished");
+ }
+ } catch (IOException e) {
+ Log.d(TAG, "error while accepting or listening", e);
+ } finally {
+ Log.d(TAG, "Linster interruped");
+ Log.d(TAG, "closing socket and stopping service");
+ safeClose(serverSocket);
+ safeClose(socket);
+ if (!bttraffic.isShuttingDown)
+ bttraffic.stopService();
+ }
+
+ }
+
+ private void doListening(InputStream inputStream, OutputStream outputStream)
+ throws IOException {
+ ByteBuffer byteBuffer = ByteBuffer.allocate(maxbuffersize);
+
+ while (!Thread.interrupted()) {
+ readBytesIntoBuffer(inputStream, byteBuffer, 4);
+ byteBuffer.flip();
+ int length = byteBuffer.getInt();
+ if (Thread.interrupted())
+ break;
+ readBytesIntoBuffer(inputStream, byteBuffer, length);
+
+ if (sendAck)
+ outputStream.write(0x55);
+ }
+ }
+
+ void readBytesIntoBuffer(InputStream inputStream, ByteBuffer byteBuffer, int numToRead)
+ throws IOException {
+ byteBuffer.clear();
+ while (true) {
+ int position = byteBuffer.position();
+ int remaining = numToRead - position;
+ if (remaining == 0) {
+ break;
+ }
+ int count = inputStream.read(byteBuffer.array(), position, remaining);
+ if (count < 0) {
+ throw new IOException("read the EOF");
+ }
+ byteBuffer.position(position + count);
+ }
+ }
+ }
+
+ public static class SenderRunnable implements Runnable {
+ private final BTtraffic bttraffic;
+ private final String remoteAddr;
+ private final int pkgsize, period;
+ private final int defaultpkgsize = 1024;
+ private final int defaultperiod = 5000;
+ private static ByteBuffer lengthBuffer = ByteBuffer.allocate(4);
+
+ public SenderRunnable(BTtraffic bttraffic, String remoteAddr, Intent intent) {
+ this.bttraffic = bttraffic;
+ this.remoteAddr = remoteAddr;
+ this.pkgsize = intent.getIntExtra("size", defaultpkgsize);
+ this.period = intent.getIntExtra("period", defaultperiod);
+ }
+
+ @Override
+ public void run() {
+ BluetoothDevice device = null;
+ try {
+ device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr);
+ } catch (IllegalArgumentException e) {
+ Log.d(TAG, "Invalid BT MAC address!\n");
+ }
+ if (device == null) {
+ Log.d(TAG, "can't find matching device, stopping thread and service");
+ bttraffic.stopService();
+ return;
+ }
+
+ BluetoothSocket socket = null;
+ try {
+ Log.d(TAG, "connecting to device with MAC addr: " + remoteAddr);
+ socket = device.createInsecureRfcommSocketToServiceRecord(SERVICE_UUID);
+ socket.connect();
+ Log.d(TAG, "connected, starting to send");
+ doSending(socket.getOutputStream());
+ Log.d(TAG, "send stopped, stopping service");
+ } catch (Exception e) {
+ Log.d(TAG, "error while sending", e);
+ } finally {
+ Log.d(TAG, "finishing, closing thread and service");
+ safeClose(socket);
+ if (!bttraffic.isShuttingDown)
+ bttraffic.stopService();
+ }
+ }
+
+ private void doSending(OutputStream outputStream) throws IOException {
+ Log.w(TAG, "doSending");
+ try {
+ Random random = new Random(System.currentTimeMillis());
+
+ byte[] bytes = new byte[pkgsize];
+ random.nextBytes(bytes);
+ while (!Thread.interrupted()) {
+ writeBytes(outputStream, bytes.length);
+ outputStream.write(bytes, 0, bytes.length);
+ if (period < 0)
+ break;
+ if (period == 0)
+ continue;
+
+ SystemClock.sleep(period);
+ }
+ Log.d(TAG, "Sender interrupted");
+ } catch (IOException e) {
+ Log.d(TAG, "doSending got error", e);
+ }
+ }
+
+ private static void writeBytes(OutputStream outputStream, int value) throws IOException {
+ lengthBuffer.putInt(value);
+ lengthBuffer.flip();
+ outputStream.write(lengthBuffer.array(), lengthBuffer.position(), lengthBuffer.limit());
+ }
+ }
+
+}
diff --git a/core/tests/SvcMonitor/Android.mk b/core/tests/SvcMonitor/Android.mk
new file mode 100644
index 000000000000..2b8045506f02
--- /dev/null
+++ b/core/tests/SvcMonitor/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_RESOURCE_DIR := \
+ $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := svcmonitor
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/SvcMonitor/AndroidManifest.xml b/core/tests/SvcMonitor/AndroidManifest.xml
new file mode 100644
index 000000000000..de5a9bdaed41
--- /dev/null
+++ b/core/tests/SvcMonitor/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.experimental.svcmonitor" >
+
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+
+ <uses-sdk
+ android:minSdkVersion="18"
+ android:targetSdkVersion="18"
+ />
+ <application
+ android:allowBackup="false"
+ android:label="@string/app_name" >
+ <service
+ android:name=".SvcMonitor"
+ android:enabled="true"
+ android:exported="true" >
+ </service>
+ </application>
+
+</manifest>
diff --git a/core/tests/SvcMonitor/README b/core/tests/SvcMonitor/README
new file mode 100644
index 000000000000..13a4380589b4
--- /dev/null
+++ b/core/tests/SvcMonitor/README
@@ -0,0 +1,27 @@
+This Android service measures CPU usage of a program and an underlying system service it relies on.
+An example of this would be an android app XYZ communicates to some other device via Bluetooth. The
+SvcMonitor service can monitor the CPU usage of XYZ and com.android.bluetooth.
+
+Usage:
+
+To start the service:
+$ adb shell am startservice -a start \
+-e java XYZ -e hal com.android.bluetooth \
+com.google.android.experimental.svcmonitor/.SvcMonitor
+
+To stop the service:
+$ adb shell am startservice -a stop \
+com.google.android.experimental.svcmonitor/.SvcMonitor
+
+To stop the service config:
+$ adb shell am startservice -a change \
+-e java NewName -e hal NewService \
+com.google.android.experimental.svcmonitor/.SvcMonitor
+
+To monitor the data:
+$ adb logcat | grep XYZ
+
+Options:
+-e java NameOfProgram: any running process’s name.
+-e hal NameOfSysService: name of the system service the previous process relies on.
+--ei period: period between each measurement (frequency). Unit: ms, Default:1000, Min: 100
diff --git a/core/tests/SvcMonitor/res/values/strings.xml b/core/tests/SvcMonitor/res/values/strings.xml
new file mode 100644
index 000000000000..e70276e03647
--- /dev/null
+++ b/core/tests/SvcMonitor/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">Bluetooth Test</string>
+</resources>
diff --git a/core/tests/SvcMonitor/src/com/android/google/experimental/svcmoniter/SvcMonitor.java b/core/tests/SvcMonitor/src/com/android/google/experimental/svcmoniter/SvcMonitor.java
new file mode 100644
index 000000000000..a451445530cd
--- /dev/null
+++ b/core/tests/SvcMonitor/src/com/android/google/experimental/svcmoniter/SvcMonitor.java
@@ -0,0 +1,209 @@
+package com.google.android.experimental.svcmonitor;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.lang.Runnable;
+import java.lang.Thread;
+import java.util.Set;
+
+public class SvcMonitor extends Service {
+ public static final String TAG = "svcmonitor";
+ String javaProc, halProc;
+ volatile Thread tMonitor;
+ int period;
+
+ public SvcMonitor() {};
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent == null) {
+ stopSelf();
+ return 0;
+ }
+ Log.d(TAG, "Starting SvcMonitor");
+ if ("stop".equals(intent.getAction())) {
+ stopService();
+ } else if ("start".equals(intent.getAction())) {
+ startMonitor(intent);
+ } else if ("change".equals(intent.getAction())) {
+ changeConfig(intent);
+ } else {
+ Log.d(TAG, "unknown action: + " + intent.getAction());
+ }
+ return 0;
+ }
+
+ private void changeConfig(Intent intent) {
+ if (tMonitor == null) {
+ Log.d(TAG, "Service not active. Start service first");
+ return;
+ }
+ stopThread();
+ startMonitor(intent);
+ }
+
+ private void startMonitor(Intent intent) {
+ if (tMonitor != null) {
+ Log.d(TAG, "thread already active");
+ return;
+ }
+ javaProc = intent.getStringExtra("java");
+ halProc = intent.getStringExtra("hal");
+ period = intent.getIntExtra("period", 1000);
+ if (javaProc == null || halProc == null || period < 100) {
+ Log.d(TAG, "Failed starting monitor, invalid arguments.");
+ stopSelf();
+ return;
+ }
+ Runnable monitor = new MonitorRunnable(this);
+ tMonitor = new Thread(monitor);
+ tMonitor.start();
+ }
+
+ private void stopService() {
+ stopThread();
+ stopSelf();
+ Log.d(TAG, "SvcMonitor stopped");
+ }
+
+ private void stopThread() {
+ if (tMonitor == null) {
+ Log.d(TAG, "no active thread");
+ return;
+ }
+ Log.d(TAG, "interrupting monitor thread");
+ tMonitor.interrupt();
+ try {
+ tMonitor.join();
+ } catch (InterruptedException e) {
+ Log.d(TAG, "Unable to finish monitor thread");
+ }
+ tMonitor = null;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
+ public static class MonitorRunnable implements Runnable {
+ long java_time_old, hal_time_old, cpu_time_old = -1;
+ String javaPID, halPID;
+ SvcMonitor svcmonitor;
+ static String javaProcTAG;
+ int period;
+
+ public MonitorRunnable(SvcMonitor svcmonitor) {
+ this.svcmonitor = svcmonitor;
+ this.period = svcmonitor.period;
+ javaPID = getPIDof(svcmonitor.javaProc);
+ halPID = getPIDof(svcmonitor.halProc);
+ java_time_old = getPsTime(javaPID);
+ hal_time_old = getPsTime(halPID);
+ cpu_time_old = getPsTime("");
+ javaProcTAG = String.valueOf(svcmonitor.javaProc.toCharArray());
+ }
+
+ @Override
+ public void run() {
+ if (halPID.isEmpty() || javaPID.isEmpty()) {
+ Log.d(javaProcTAG, "No such process: " +
+ (halPID.isEmpty() ? svcmonitor.halProc : svcmonitor.javaProc));
+ return;
+ }
+ while (!Thread.interrupted()) {
+ calculateUsage();
+ SystemClock.sleep(period);
+ }
+ Log.d(TAG, "Stopping monitor thread");
+ }
+
+ private void calculateUsage() {
+ long java_time = getPsTime(javaPID);
+ long hal_time = getPsTime(halPID);
+ long cpu_time = getPsTime("");
+
+ if (cpu_time_old >= 0) {
+ float java_diff = (float) (java_time - java_time_old);
+ float hal_diff = (float) (hal_time - hal_time_old);
+ float cpu_diff = (float) (cpu_time - cpu_time_old);
+ Log.w(javaProcTAG, "\n----------------\n");
+ Log.w(javaProcTAG, "JAVA level CPU: "
+ + (java_diff * 100.0 / cpu_diff) + "%\n");
+ Log.w(javaProcTAG, " HAL level CPU: "
+ + (hal_diff * 100.0 / cpu_diff) + "%\n");
+ Log.w(javaProcTAG, " SYS level CPU: "
+ + ((java_diff + hal_diff) * 100.0 / cpu_diff) + "%\n");
+ } else {
+ Log.w(TAG, "Waiting for status\n");
+ }
+
+ java_time_old = java_time;
+ hal_time_old = hal_time;
+ cpu_time_old = cpu_time;
+ }
+
+ private String getPIDof(String psName) {
+ String pid = "";
+
+ try {
+ String[] cmd = {"/system/bin/sh", "-c", "ps | grep " + psName};
+ Process ps = Runtime.getRuntime().exec(cmd);
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(ps.getInputStream()));
+ String temp = in.readLine();
+ if (temp == null || temp.isEmpty())
+ throw new IOException("No such process: " + psName);
+ pid = temp.split(" +")[1];
+ in.close();
+ } catch (IOException e) {
+ Log.d(javaProcTAG, "Error finding PID of process: " + psName + "\n", e);
+ }
+ return pid;
+ }
+
+ private long getPsTime(String pid) {
+ String psStat = getPsStat("/" + pid);
+ String[] statBreakDown = psStat.split(" +");
+ long psTime;
+
+ if (pid.isEmpty()) {
+ psTime = Long.parseLong(statBreakDown[1])
+ + Long.parseLong(statBreakDown[2])
+ + Long.parseLong(statBreakDown[3])
+ + Long.parseLong(statBreakDown[4]);
+ } else {
+ psTime = Long.parseLong(statBreakDown[13])
+ + Long.parseLong(statBreakDown[14]);
+ }
+
+ return psTime;
+ }
+
+ private String getPsStat(String psname) {
+ String stat = "";
+ try {
+ FileInputStream fs = new FileInputStream("/proc" + psname + "/stat");
+ BufferedReader br = new BufferedReader(new InputStreamReader(fs));
+ stat = br.readLine();
+ fs.close();
+ } catch (IOException e) {
+ Log.d(TAG, "Error retreiving stat. \n");
+ }
+ return stat;
+ }
+ }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 47d8e283257b..e34286572cb6 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -129,6 +129,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
private static final int MSG_STARTED_WAKING_UP = 319;
private static final int MSG_FINISHED_GOING_TO_SLEEP = 320;
+ private static final int MSG_STARTED_GOING_TO_SLEEP = 321;
private static final int MSG_KEYGUARD_BOUNCER_CHANGED = 322;
private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 327;
private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 328;
@@ -170,6 +171,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
* until the Keyguard has been dismissed.
*/
private boolean mFingerprintAlreadyAuthenticated;
+ private boolean mGoingToSleep;
private boolean mBouncer;
private boolean mBootCompleted;
@@ -249,6 +251,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
case MSG_REPORT_EMERGENCY_CALL_ACTION:
handleReportEmergencyCallAction();
break;
+ case MSG_STARTED_GOING_TO_SLEEP:
+ handleStartedGoingToSleep(msg.arg1);
+ break;
case MSG_FINISHED_GOING_TO_SLEEP:
handleFinishedGoingToSleep(msg.arg1);
break;
@@ -884,19 +889,32 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
}
- protected void handleFinishedGoingToSleep(int arg1) {
+ protected void handleStartedGoingToSleep(int arg1) {
clearFingerprintRecognized();
final int count = mCallbacks.size();
for (int i = 0; i < count; i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
if (cb != null) {
- cb.onFinishedGoingToSleep(arg1);
+ cb.onStartedGoingToSleep(arg1);
}
}
+ mGoingToSleep = true;
mFingerprintAlreadyAuthenticated = false;
updateFingerprintListeningState();
}
+ protected void handleFinishedGoingToSleep(int arg1) {
+ mGoingToSleep = false;
+ final int count = mCallbacks.size();
+ for (int i = 0; i < count; i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onFinishedGoingToSleep(arg1);
+ }
+ }
+ updateFingerprintListeningState();
+ }
+
private void handleScreenTurnedOn() {
final int count = mCallbacks.size();
for (int i = 0; i < count; i++) {
@@ -1032,8 +1050,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
private boolean shouldListenForFingerprint() {
- return (mKeyguardIsVisible || !mDeviceInteractive || mBouncer) && !mSwitchingUser
- && !mFingerprintAlreadyAuthenticated && !isFingerprintDisabled(getCurrentUser());
+ return (mKeyguardIsVisible || !mDeviceInteractive || mBouncer || mGoingToSleep)
+ && !mSwitchingUser && !mFingerprintAlreadyAuthenticated
+ && !isFingerprintDisabled(getCurrentUser());
}
private void startListeningForFingerprint() {
@@ -1605,6 +1624,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
mHandler.sendEmptyMessage(MSG_STARTED_WAKING_UP);
}
+ public void dispatchStartedGoingToSleep(int why) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_STARTED_GOING_TO_SLEEP, why, 0));
+ }
+
public void dispatchFinishedGoingToSleep(int why) {
synchronized(this) {
mDeviceInteractive = false;
@@ -1630,6 +1653,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
return mDeviceInteractive;
}
+ public boolean isGoingToSleep() {
+ return mGoingToSleep;
+ }
+
/**
* Find the next SubscriptionId for a SIM in the given state, favoring lower slot numbers first.
* @param state
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 15ffe9f5ca7e..bd6c51c3b89c 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -153,6 +153,12 @@ public class KeyguardUpdateMonitorCallback {
public void onStartedWakingUp() { }
/**
+ * Called when the device has started going to sleep.
+ * @param why see {@link #onFinishedGoingToSleep(int)}
+ */
+ public void onStartedGoingToSleep(int why) { }
+
+ /**
* Called when the device has finished going to sleep.
* @param why either {@link WindowManagerPolicy#OFF_BECAUSE_OF_ADMIN},
* {@link WindowManagerPolicy#OFF_BECAUSE_OF_USER}, or
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index 5062423a964d..52941992c626 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -25,6 +25,7 @@ import android.net.wifi.WifiManager;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
public class TetherUtil {
@@ -62,6 +63,13 @@ public class TetherUtil {
return wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED;
}
+ private static boolean isEntitlementCheckRequired(Context context) {
+ final CarrierConfigManager configManager = (CarrierConfigManager) context
+ .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ return configManager.getConfig().getBoolean(CarrierConfigManager
+ .KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
+ }
+
public static boolean isProvisioningNeeded(Context context) {
// Keep in sync with other usage of config_mobile_hotspot_provision_app.
// ConnectivityManager#enforceTetherChangePermission
@@ -71,6 +79,10 @@ public class TetherUtil {
|| provisionApp == null) {
return false;
}
+ // Check carrier config for entitlement checks
+ if (isEntitlementCheckRequired(context) == false) {
+ return false;
+ }
return (provisionApp.length == 2);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index da4ffa4b9433..8a09b7c69f9d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -74,6 +74,8 @@ import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -152,6 +154,7 @@ public class KeyguardViewMediator extends SystemUI {
private static final int NOTIFY_STARTED_WAKING_UP = 21;
private static final int NOTIFY_SCREEN_TURNED_ON = 22;
private static final int NOTIFY_SCREEN_TURNED_OFF = 23;
+ private static final int NOTIFY_STARTED_GOING_TO_SLEEP = 24;
/**
* The default amount of time we stay awake (used for all key input)
@@ -649,6 +652,7 @@ public class KeyguardViewMediator extends SystemUI {
final boolean lockImmediately =
mLockPatternUtils.getPowerButtonInstantlyLocks(currentUser)
|| !mLockPatternUtils.isSecure(currentUser);
+ long timeout = getLockTimeout();
if (mExitSecureCallback != null) {
if (DEBUG) Log.d(TAG, "pending exit secure callback cancelled");
@@ -663,9 +667,9 @@ public class KeyguardViewMediator extends SystemUI {
}
} else if (mShowing) {
mPendingReset = true;
- } else if (why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT
+ } else if ((why == WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT && timeout > 0)
|| (why == WindowManagerPolicy.OFF_BECAUSE_OF_USER && !lockImmediately)) {
- doKeyguardLaterLocked();
+ doKeyguardLaterLocked(timeout);
} else if (!mLockPatternUtils.isLockScreenDisabled(currentUser)) {
mPendingLock = true;
}
@@ -674,6 +678,8 @@ public class KeyguardViewMediator extends SystemUI {
playSounds(true);
}
}
+ KeyguardUpdateMonitor.getInstance(mContext).dispatchStartedGoingToSleep(why);
+ notifyStartedGoingToSleep();
}
public void onFinishedGoingToSleep(int why) {
@@ -699,7 +705,7 @@ public class KeyguardViewMediator extends SystemUI {
KeyguardUpdateMonitor.getInstance(mContext).dispatchFinishedGoingToSleep(why);
}
- private void doKeyguardLaterLocked() {
+ private long getLockTimeout() {
// if the screen turned off because of timeout or the user hit the power button
// and we don't need to lock immediately, set an alarm
// to enable it a little bit later (i.e, give the user a chance
@@ -728,23 +734,30 @@ public class KeyguardViewMediator extends SystemUI {
} else {
timeout = lockAfterTimeout;
}
+ return timeout;
+ }
- if (timeout <= 0) {
- // Lock now
+ private void doKeyguardLaterLocked() {
+ long timeout = getLockTimeout();
+ if (timeout == 0) {
doKeyguardLocked(null);
} else {
- // Lock in the future
- long when = SystemClock.elapsedRealtime() + timeout;
- Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
- intent.putExtra("seq", mDelayedShowingSequence);
- PendingIntent sender = PendingIntent.getBroadcast(mContext,
- 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
- if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
- + mDelayedShowingSequence);
+ doKeyguardLaterLocked(timeout);
}
}
+ private void doKeyguardLaterLocked(long timeout) {
+ // Lock in the future
+ long when = SystemClock.elapsedRealtime() + timeout;
+ Intent intent = new Intent(DELAYED_KEYGUARD_ACTION);
+ intent.putExtra("seq", mDelayedShowingSequence);
+ PendingIntent sender = PendingIntent.getBroadcast(mContext,
+ 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
+ if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
+ + mDelayedShowingSequence);
+ }
+
private void cancelDoKeyguardLaterLocked() {
mDelayedShowingSequence++;
}
@@ -1090,6 +1103,11 @@ public class KeyguardViewMediator extends SystemUI {
mHandler.sendEmptyMessage(VERIFY_UNLOCK);
}
+ private void notifyStartedGoingToSleep() {
+ if (DEBUG) Log.d(TAG, "notifyStartedGoingToSleep");
+ mHandler.sendEmptyMessage(NOTIFY_STARTED_GOING_TO_SLEEP);
+ }
+
private void notifyFinishedGoingToSleep() {
if (DEBUG) Log.d(TAG, "notifyFinishedGoingToSleep");
mHandler.sendEmptyMessage(NOTIFY_FINISHED_GOING_TO_SLEEP);
@@ -1201,6 +1219,9 @@ public class KeyguardViewMediator extends SystemUI {
case VERIFY_UNLOCK:
handleVerifyUnlock();
break;
+ case NOTIFY_STARTED_GOING_TO_SLEEP:
+ handleNotifyStartedGoingToSleep();
+ break;
case NOTIFY_FINISHED_GOING_TO_SLEEP:
handleNotifyFinishedGoingToSleep();
break;
@@ -1528,6 +1549,13 @@ public class KeyguardViewMediator extends SystemUI {
}
}
+ private void handleNotifyStartedGoingToSleep() {
+ synchronized (KeyguardViewMediator.this) {
+ if (DEBUG) Log.d(TAG, "handleNotifyStartedGoingToSleep");
+ mStatusBarKeyguardViewManager.onStartedGoingToSleep();
+ }
+ }
+
/**
* Handle message sent by {@link #notifyFinishedGoingToSleep()}
* @see #NOTIFY_FINISHED_GOING_TO_SLEEP
@@ -1625,6 +1653,30 @@ public class KeyguardViewMediator extends SystemUI {
return mViewMediatorCallback;
}
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.print(" mSystemReady: "); pw.println(mSystemReady);
+ pw.print(" mBootCompleted: "); pw.println(mBootCompleted);
+ pw.print(" mBootSendUserPresent: "); pw.println(mBootSendUserPresent);
+ pw.print(" mExternallyEnabled: "); pw.println(mExternallyEnabled);
+ pw.print(" mNeedToReshowWhenReenabled: "); pw.println(mNeedToReshowWhenReenabled);
+ pw.print(" mShowing: "); pw.println(mShowing);
+ pw.print(" mInputRestricted: "); pw.println(mInputRestricted);
+ pw.print(" mOccluded: "); pw.println(mOccluded);
+ pw.print(" mDelayedShowingSequence: "); pw.println(mDelayedShowingSequence);
+ pw.print(" mExitSecureCallback: "); pw.println(mExitSecureCallback);
+ pw.print(" mDeviceInteractive: "); pw.println(mDeviceInteractive);
+ pw.print(" mGoingToSleep: "); pw.println(mGoingToSleep);
+ pw.print(" mHiding: "); pw.println(mHiding);
+ pw.print(" mWaitingUntilKeyguardVisible: "); pw.println(mWaitingUntilKeyguardVisible);
+ pw.print(" mKeyguardDonePending: "); pw.println(mKeyguardDonePending);
+ pw.print(" mHideAnimationRun: "); pw.println(mHideAnimationRun);
+ pw.print(" mPendingReset: "); pw.println(mPendingReset);
+ pw.print(" mPendingLock: "); pw.println(mPendingLock);
+ pw.print(" mWakeAndUnlocking: "); pw.println(mWakeAndUnlocking);
+ pw.print(" mDrawnCallback: "); pw.println(mDrawnCallback);
+ }
+
private static class StartKeyguardExitAnimParams {
long startTime;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 84082dbe0d12..29129638fc6c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -93,6 +93,8 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
private KeyguardViewMediator mKeyguardViewMediator;
private ScrimController mScrimController;
private PhoneStatusBar mPhoneStatusBar;
+ private boolean mGoingToSleep;
+ private int mPendingAuthenticatedUserId = -1;
public FingerprintUnlockController(Context context,
StatusBarWindowManager statusBarWindowManager,
@@ -161,6 +163,10 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
@Override
public void onFingerprintAuthenticated(int userId) {
+ if (mUpdateMonitor.isGoingToSleep()) {
+ mPendingAuthenticatedUserId = userId;
+ return;
+ }
boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
mMode = calculateMode();
if (!wasDeviceInteractive) {
@@ -205,6 +211,26 @@ public class FingerprintUnlockController extends KeyguardUpdateMonitorCallback {
mPhoneStatusBar.notifyFpAuthModeChanged();
}
+ @Override
+ public void onStartedGoingToSleep(int why) {
+ mPendingAuthenticatedUserId = -1;
+ }
+
+ @Override
+ public void onFinishedGoingToSleep(int why) {
+ if (mPendingAuthenticatedUserId != -1) {
+
+ // Post this to make sure it's executed after the device is fully locked.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onFingerprintAuthenticated(mPendingAuthenticatedUserId);
+ }
+ });
+ }
+ mPendingAuthenticatedUserId = -1;
+ }
+
public int getMode() {
return mMode;
}
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 548125d4bc32..2bedef70c49a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -312,6 +312,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
boolean mLeaveOpenOnKeyguardHide;
KeyguardIndicationController mKeyguardIndicationController;
+ // Keyguard is going away soon.
+ private boolean mKeyguardGoingAway;
+ // Keyguard is actually fading away now.
private boolean mKeyguardFadingAway;
private long mKeyguardFadingAwayDelay;
private long mKeyguardFadingAwayDuration;
@@ -485,12 +488,18 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private boolean mLaunchTransitionFadingAway;
private ExpandableNotificationRow mDraggedDownRow;
private boolean mLaunchCameraOnScreenTurningOn;
+ private boolean mLaunchCameraOnFinishedGoingToSleep;
private PowerManager.WakeLock mGestureWakeLock;
private Vibrator mVibrator;
// Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
private int mLastLoggedStateFingerprint;
+ /**
+ * If set, the device has started going to sleep but isn't fully non-interactive yet.
+ */
+ protected boolean mStartedGoingToSleep;
+
private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_CARD
| StackViewState.LOCATION_MAIN_AREA;
@@ -3558,6 +3567,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Treat Keyguard exit animation as an app transition to achieve nice transition for status
// bar.
+ mKeyguardGoingAway = true;
mIconController.appTransitionPending();
}
@@ -3589,6 +3599,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
*/
public void finishKeyguardFadingAway() {
mKeyguardFadingAway = false;
+ mKeyguardGoingAway = false;
}
public void stopWaitingForKeyguardExit() {
@@ -3903,15 +3914,32 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */);
}
+ public void onStartedGoingToSleep() {
+ mStartedGoingToSleep = true;
+ }
+
public void onFinishedGoingToSleep() {
mNotificationPanel.onAffordanceLaunchEnded();
releaseGestureWakeLock();
mLaunchCameraOnScreenTurningOn = false;
+ mStartedGoingToSleep = false;
mDeviceInteractive = false;
mWakeUpComingFromTouch = false;
mWakeUpTouchLocation = null;
mStackScroller.setAnimationsEnabled(false);
updateVisibleToUser();
+ if (mLaunchCameraOnFinishedGoingToSleep) {
+ mLaunchCameraOnFinishedGoingToSleep = false;
+
+ // This gets executed before we will show Keyguard, so post it in order that the state
+ // is correct.
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ onCameraLaunchGestureDetected();
+ }
+ });
+ }
}
public void onStartedWakingUp() {
@@ -3931,7 +3959,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
private void vibrateForCameraGesture() {
- mVibrator.vibrate(750L);
+ // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
+ mVibrator.vibrate(new long[] { 0, 750L }, -1 /* repeat */);
}
public void onScreenTurnedOn() {
@@ -4079,9 +4108,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
public void appTransitionStarting(long startTime, long duration) {
// Use own timings when Keyguard is going away, see keyguardGoingAway and
- // setKeyguardFadingAway. When duration is 0, skip this one because no animation is really
- // playing.
- if (!mKeyguardFadingAway && duration > 0) {
+ // setKeyguardFadingAway.
+ if (!mKeyguardGoingAway) {
mIconController.appTransitionStarting(startTime, duration);
}
if (mIconPolicy != null) {
@@ -4091,6 +4119,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public void onCameraLaunchGestureDetected() {
+ if (mStartedGoingToSleep) {
+ mLaunchCameraOnFinishedGoingToSleep = true;
+ return;
+ }
if (!mNotificationPanel.canCameraGestureBeLaunched(
mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
return;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index e26f42301830..394ff3f8245c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -164,6 +164,10 @@ public class StatusBarKeyguardViewManager {
}
}
+ public void onStartedGoingToSleep() {
+ mPhoneStatusBar.onStartedGoingToSleep();
+ }
+
public void onFinishedGoingToSleep() {
mDeviceInteractive = false;
mPhoneStatusBar.onFinishedGoingToSleep();
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d1e1683d6478..6190a5ab357e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2270,8 +2270,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetworkRequestInfoLogs.log("REGISTER " + nri);
if (!nri.isRequest) {
for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
- if (network.satisfiesImmutableCapabilitiesOf(nri.request)) {
- updateSignalStrengthThresholds(network);
+ if (nri.request.networkCapabilities.hasSignalStrength() &&
+ network.satisfiesImmutableCapabilitiesOf(nri.request)) {
+ updateSignalStrengthThresholds(network, "REGISTER", nri.request);
}
}
}
@@ -2388,8 +2389,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
// if this listen request applies and remove it.
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
nai.networkRequests.remove(nri.request.requestId);
- if (nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
- updateSignalStrengthThresholds(nai);
+ if (nri.request.networkCapabilities.hasSignalStrength() &&
+ nai.satisfiesImmutableCapabilitiesOf(nri.request)) {
+ updateSignalStrengthThresholds(nai, "RELEASE", nri.request);
}
}
}
@@ -3639,9 +3641,24 @@ public class ConnectivityService extends IConnectivityManager.Stub
return new ArrayList<Integer>(thresholds);
}
- private void updateSignalStrengthThresholds(NetworkAgentInfo nai) {
+ private void updateSignalStrengthThresholds(
+ NetworkAgentInfo nai, String reason, NetworkRequest request) {
+ ArrayList<Integer> thresholdsArray = getSignalStrengthThresholds(nai);
Bundle thresholds = new Bundle();
- thresholds.putIntegerArrayList("thresholds", getSignalStrengthThresholds(nai));
+ thresholds.putIntegerArrayList("thresholds", thresholdsArray);
+
+ // TODO: Switch to VDBG.
+ if (DBG) {
+ String detail;
+ if (request != null && request.networkCapabilities.hasSignalStrength()) {
+ detail = reason + " " + request.networkCapabilities.getSignalStrength();
+ } else {
+ detail = reason;
+ }
+ log(String.format("updateSignalStrengthThresholds: %s, sending %s to %s",
+ detail, Arrays.toString(thresholdsArray.toArray()), nai.name()));
+ }
+
nai.asyncChannel.sendMessage(
android.net.NetworkAgent.CMD_SET_SIGNAL_STRENGTH_THRESHOLDS,
0, 0, thresholds);
@@ -4624,7 +4641,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// so we could decide to tear it down immediately afterwards. That's fine though - on
// disconnection NetworkAgents should stop any signal strength monitoring they have been
// doing.
- updateSignalStrengthThresholds(networkAgent);
+ updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
// Consider network even though it is not yet validated.
rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP);
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 69f0cef6d39e..bd7d4b27e02c 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -101,8 +101,8 @@ public class GestureLauncherService extends SystemService {
* Whether camera double tap power button gesture is currently enabled;
*/
private boolean mCameraDoubleTapPowerEnabled;
- private long mLastPowerDownWhileNonInteractive = 0;
-
+ private long mLastPowerDownWhileNonInteractive;
+ private long mLastPowerDownWhileInteractive;
public GestureLauncherService(Context context) {
super(context);
@@ -251,23 +251,30 @@ public class GestureLauncherService extends SystemService {
public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive) {
boolean launched = false;
+ boolean intercept = false;
synchronized (this) {
if (!mCameraDoubleTapPowerEnabled) {
mLastPowerDownWhileNonInteractive = 0;
+ mLastPowerDownWhileInteractive = 0;
return false;
}
if (event.getEventTime() - mLastPowerDownWhileNonInteractive
< CAMERA_POWER_DOUBLE_TAP_TIME_MS) {
launched = true;
+ intercept = true;
+ } else if (event.getEventTime() - mLastPowerDownWhileInteractive
+ < CAMERA_POWER_DOUBLE_TAP_TIME_MS) {
+ launched = true;
}
mLastPowerDownWhileNonInteractive = interactive ? 0 : event.getEventTime();
+ mLastPowerDownWhileInteractive = interactive ? event.getEventTime() : 0;
}
if (launched) {
Slog.i(TAG, "Power button double tap gesture detected, launching camera.");
launched = handleCameraLaunchGesture(false /* useWakelock */,
MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE);
}
- return launched;
+ return intercept && launched;
}
/**
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 30f4dce310ca..c2284224502d 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -59,6 +59,7 @@ public class VibratorService extends IVibratorService.Stub
implements InputManager.InputDeviceListener {
private static final String TAG = "VibratorService";
private static final boolean DEBUG = false;
+ private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
private final LinkedList<Vibration> mVibrations;
private final LinkedList<VibrationInfo> mPreviousVibrations;
@@ -147,7 +148,8 @@ public class VibratorService extends IVibratorService.Stub
}
public boolean isSystemHapticFeedback() {
- return (mUid == Process.SYSTEM_UID || mUid == 0) && mRepeat < 0;
+ return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
+ && mRepeat < 0;
}
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 335288da005b..62768c3b6475 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -171,12 +171,11 @@ public final class BatteryStatsService extends IBatteryStats.Stub
public void publish(Context context) {
mContext = context;
- ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
- mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps());
mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
com.android.internal.R.integer.config_radioScanningTimeout)
* 1000L);
mStats.setPowerProfile(new PowerProfile(context));
+ ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
}
/**
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index aca699152e02..5fd39c02a10a 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -18,6 +18,7 @@ package com.android.server.connectivity;
import static android.system.OsConstants.*;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkUtils;
@@ -27,6 +28,7 @@ import android.system.ErrnoException;
import android.system.Os;
import android.system.StructTimeval;
import android.text.TextUtils;
+import android.util.Pair;
import com.android.internal.util.IndentingPrintWriter;
@@ -149,6 +151,8 @@ public class NetworkDiagnostics {
}
private final Map<InetAddress, Measurement> mIcmpChecks = new HashMap<>();
+ private final Map<Pair<InetAddress, InetAddress>, Measurement> mExplicitSourceIcmpChecks =
+ new HashMap<>();
private final Map<InetAddress, Measurement> mDnsUdpChecks = new HashMap<>();
private final String mDescription;
@@ -178,7 +182,11 @@ public class NetworkDiagnostics {
for (RouteInfo route : mLinkProperties.getRoutes()) {
if (route.hasGateway()) {
- prepareIcmpMeasurement(route.getGateway());
+ InetAddress gateway = route.getGateway();
+ prepareIcmpMeasurement(gateway);
+ if (route.isIPv6Default()) {
+ prepareExplicitSourceIcmpMeasurements(gateway);
+ }
}
}
for (InetAddress nameserver : mLinkProperties.getDnsServers()) {
@@ -213,6 +221,20 @@ public class NetworkDiagnostics {
}
}
+ private void prepareExplicitSourceIcmpMeasurements(InetAddress target) {
+ for (LinkAddress l : mLinkProperties.getLinkAddresses()) {
+ InetAddress source = l.getAddress();
+ if (source instanceof Inet6Address && l.isGlobalPreferred()) {
+ Pair<InetAddress, InetAddress> srcTarget = new Pair<>(source, target);
+ if (!mExplicitSourceIcmpChecks.containsKey(srcTarget)) {
+ Measurement measurement = new Measurement();
+ measurement.thread = new Thread(new IcmpCheck(source, target, measurement));
+ mExplicitSourceIcmpChecks.put(srcTarget, measurement);
+ }
+ }
+ }
+ }
+
private void prepareDnsMeasurement(InetAddress target) {
if (!mDnsUdpChecks.containsKey(target)) {
Measurement measurement = new Measurement();
@@ -222,13 +244,16 @@ public class NetworkDiagnostics {
}
private int totalMeasurementCount() {
- return mIcmpChecks.size() + mDnsUdpChecks.size();
+ return mIcmpChecks.size() + mExplicitSourceIcmpChecks.size() + mDnsUdpChecks.size();
}
private void startMeasurements() {
for (Measurement measurement : mIcmpChecks.values()) {
measurement.thread.start();
}
+ for (Measurement measurement : mExplicitSourceIcmpChecks.values()) {
+ measurement.thread.start();
+ }
for (Measurement measurement : mDnsUdpChecks.values()) {
measurement.thread.start();
}
@@ -261,6 +286,10 @@ public class NetworkDiagnostics {
pw.println(entry.getValue().toString());
}
}
+ for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
+ mExplicitSourceIcmpChecks.entrySet()) {
+ pw.println(entry.getValue().toString());
+ }
for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
if (entry.getKey() instanceof Inet4Address) {
pw.println(entry.getValue().toString());
@@ -276,13 +305,15 @@ public class NetworkDiagnostics {
private class SimpleSocketCheck implements Closeable {
+ protected final InetAddress mSource; // Usually null.
protected final InetAddress mTarget;
protected final int mAddressFamily;
protected final Measurement mMeasurement;
protected FileDescriptor mFileDescriptor;
protected SocketAddress mSocketAddress;
- protected SimpleSocketCheck(InetAddress target, Measurement measurement) {
+ protected SimpleSocketCheck(
+ InetAddress source, InetAddress target, Measurement measurement) {
mMeasurement = measurement;
if (target instanceof Inet6Address) {
@@ -301,6 +332,14 @@ public class NetworkDiagnostics {
mTarget = target;
mAddressFamily = AF_INET;
}
+
+ // We don't need to check the scope ID here because we currently only do explicit-source
+ // measurements from global IPv6 addresses.
+ mSource = source;
+ }
+
+ protected SimpleSocketCheck(InetAddress target, Measurement measurement) {
+ this(null, target, measurement);
}
protected void setupSocket(
@@ -314,6 +353,9 @@ public class NetworkDiagnostics {
SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(readTimeout));
// TODO: Use IP_RECVERR/IPV6_RECVERR, pending OsContants availability.
mNetwork.bindSocket(mFileDescriptor);
+ if (mSource != null) {
+ Os.bind(mFileDescriptor, mSource, 0);
+ }
Os.connect(mFileDescriptor, mTarget, dstPort);
mSocketAddress = Os.getsockname(mFileDescriptor);
}
@@ -343,8 +385,8 @@ public class NetworkDiagnostics {
private final int mProtocol;
private final int mIcmpType;
- public IcmpCheck(InetAddress target, Measurement measurement) {
- super(target, measurement);
+ public IcmpCheck(InetAddress source, InetAddress target, Measurement measurement) {
+ super(source, target, measurement);
if (mAddressFamily == AF_INET6) {
mProtocol = IPPROTO_ICMPV6;
@@ -359,6 +401,10 @@ public class NetworkDiagnostics {
mMeasurement.description += " dst{" + mTarget.getHostAddress() + "}";
}
+ public IcmpCheck(InetAddress target, Measurement measurement) {
+ this(null, target, measurement);
+ }
+
@Override
public void run() {
// Check if this measurement has already failed during setup.
diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java
index 6ba25a53248d..701b9f179f9c 100644
--- a/services/core/java/com/android/server/display/DisplayAdapter.java
+++ b/services/core/java/com/android/server/display/DisplayAdapter.java
@@ -49,6 +49,13 @@ abstract class DisplayAdapter {
*/
private static final AtomicInteger NEXT_DISPLAY_MODE_ID = new AtomicInteger(1); // 0 = no mode.
+ /**
+ * Used to generate globally unique color transform ids.
+ *
+ * Valid IDs start at 1 with 0 as the sentinel value for the default mode.
+ */
+ private static final AtomicInteger NEXT_COLOR_TRANSFORM_ID = new AtomicInteger(1);
+
// Called with SyncRoot lock held.
public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener, String name) {
@@ -134,6 +141,11 @@ abstract class DisplayAdapter {
NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate);
}
+ public static Display.ColorTransform createColorTransform(int colorTransform) {
+ return new Display.ColorTransform(
+ NEXT_COLOR_TRANSFORM_ID.getAndIncrement(), colorTransform);
+ }
+
public interface Listener {
public void onDisplayDeviceEvent(DisplayDevice device, int event);
public void onTraversalRequested();
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 93bda46873a1..7af0bdbdc357 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -135,7 +135,7 @@ abstract class DisplayDevice {
/**
* Sets the mode, if supported.
*/
- public void requestModeInTransactionLocked(int id) {
+ public void requestColorTransformAndModeInTransactionLocked(int colorTransformId, int modeId) {
}
/**
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 97ada1542466..55ba3025c516 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -155,6 +155,15 @@ final class DisplayDeviceInfo {
*/
public Display.Mode[] supportedModes = Display.Mode.EMPTY_ARRAY;
+ /** The active color transform of the display */
+ public int colorTransformId;
+
+ /** The default color transform of the display */
+ public int defaultColorTransformId;
+
+ /** The supported color transforms of the display */
+ public Display.ColorTransform[] supportedColorTransforms = Display.ColorTransform.EMPTY_ARRAY;
+
/**
* The nominal apparent density of the display in DPI used for layout calculations.
* This density is sensitive to the viewing distance. A big TV and a tablet may have
@@ -276,6 +285,9 @@ final class DisplayDeviceInfo {
|| modeId != other.modeId
|| defaultModeId != other.defaultModeId
|| !Arrays.equals(supportedModes, other.supportedModes)
+ || colorTransformId != other.colorTransformId
+ || defaultColorTransformId != other.defaultColorTransformId
+ || !Arrays.equals(supportedColorTransforms, other.supportedColorTransforms)
|| densityDpi != other.densityDpi
|| xDpi != other.xDpi
|| yDpi != other.yDpi
@@ -306,6 +318,9 @@ final class DisplayDeviceInfo {
modeId = other.modeId;
defaultModeId = other.defaultModeId;
supportedModes = other.supportedModes;
+ colorTransformId = other.colorTransformId;
+ defaultColorTransformId = other.defaultColorTransformId;
+ supportedColorTransforms = other.supportedColorTransforms;
densityDpi = other.densityDpi;
xDpi = other.xDpi;
yDpi = other.yDpi;
@@ -331,6 +346,9 @@ final class DisplayDeviceInfo {
sb.append(", modeId ").append(modeId);
sb.append(", defaultModeId ").append(defaultModeId);
sb.append(", supportedModes ").append(Arrays.toString(supportedModes));
+ sb.append(", colorTransformId ").append(colorTransformId);
+ sb.append(", defaultColorTransformId ").append(defaultColorTransformId);
+ sb.append(", supportedColorTransforms ").append(Arrays.toString(supportedColorTransforms));
sb.append(", density ").append(densityDpi);
sb.append(", ").append(xDpi).append(" x ").append(yDpi).append(" dpi");
sb.append(", appVsyncOff ").append(appVsyncOffsetNanos);
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index b2ab797a409e..6a6570b97205 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -540,6 +540,17 @@ public final class DisplayManagerService extends SystemService {
}
}
+ private void requestColorTransformInternal(int displayId, int colorTransformId) {
+ synchronized (mSyncRoot) {
+ LogicalDisplay display = mLogicalDisplays.get(displayId);
+ if (display != null &&
+ display.getRequestedColorTransformIdLocked() != colorTransformId) {
+ display.setRequestedColorTransformIdLocked(colorTransformId);
+ scheduleTraversalLocked(false);
+ }
+ }
+ }
+
private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
IMediaProjection projection, int callingUid, String packageName,
String name, int width, int height, int densityDpi, Surface surface, int flags) {
@@ -1340,6 +1351,19 @@ public final class DisplayManagerService extends SystemService {
}
@Override // Binder call
+ public void requestColorTransform(int displayId, int colorTransformId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.CONFIGURE_DISPLAY_COLOR_TRANSFORM,
+ "Permission required to change the display color transform");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ requestColorTransformInternal(displayId, colorTransformId);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
public int createVirtualDisplay(IVirtualDisplayCallback callback,
IMediaProjection projection, String packageName, String name,
int width, int height, int densityDpi, Surface surface, int flags) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 517a825f6fcb..be37f524eb8d 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -31,6 +31,7 @@ import android.os.SystemProperties;
import android.os.Trace;
import android.util.Slog;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.view.Display;
import android.view.DisplayEventReceiver;
import android.view.Surface;
@@ -38,6 +39,7 @@ import android.view.SurfaceControl;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
/**
* A display adapter for the local displays managed by Surface Flinger.
@@ -143,14 +145,22 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private final int mBuiltInDisplayId;
private final Light mBacklight;
private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>();
+ private final SparseArray<Display.ColorTransform> mSupportedColorTransforms =
+ new SparseArray<>();
private DisplayDeviceInfo mInfo;
private boolean mHavePendingChanges;
private int mState = Display.STATE_UNKNOWN;
private int mBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+ private int mActivePhysIndex;
private int mDefaultModeId;
private int mActiveModeId;
private boolean mActiveModeInvalid;
+ private int mDefaultColorTransformId;
+ private int mActiveColorTransformId;
+ private boolean mActiveColorTransformInvalid;
+
+ private SurfaceControl.PhysicalDisplayInfo mDisplayInfos[];
public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) {
@@ -167,22 +177,73 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public boolean updatePhysicalDisplayInfoLocked(
SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo) {
+ mDisplayInfos = Arrays.copyOf(physicalDisplayInfos, physicalDisplayInfos.length);
+ mActivePhysIndex = activeDisplayInfo;
+ ArrayList<Display.ColorTransform> colorTransforms = new ArrayList<>();
+
+ // Build an updated list of all existing color transforms.
+ boolean colorTransformsAdded = false;
+ Display.ColorTransform activeColorTransform = null;
+ for (int i = 0; i < physicalDisplayInfos.length; i++) {
+ SurfaceControl.PhysicalDisplayInfo info = physicalDisplayInfos[i];
+ // First check to see if we've already added this color transform
+ boolean existingMode = false;
+ for (int j = 0; j < colorTransforms.size(); j++) {
+ if (colorTransforms.get(j).getColorTransform() == info.colorTransform) {
+ existingMode = true;
+ break;
+ }
+ }
+ if (existingMode) {
+ continue;
+ }
+ Display.ColorTransform colorTransform = findColorTransform(info);
+ if (colorTransform == null) {
+ colorTransform = createColorTransform(info.colorTransform);
+ colorTransformsAdded = true;
+ }
+ colorTransforms.add(colorTransform);
+ if (i == activeDisplayInfo) {
+ activeColorTransform = colorTransform;
+ }
+ }
+
// Build an updated list of all existing modes.
- boolean modesAdded = false;
- DisplayModeRecord activeRecord = null;
ArrayList<DisplayModeRecord> records = new ArrayList<DisplayModeRecord>();
+ boolean modesAdded = false;
for (int i = 0; i < physicalDisplayInfos.length; i++) {
SurfaceControl.PhysicalDisplayInfo info = physicalDisplayInfos[i];
+ // First, check to see if we've already added a matching mode. Since not all
+ // configuration options are exposed via Display.Mode, it's possible that we have
+ // multiple PhysicalDisplayInfos that would generate the same Display.Mode.
+ boolean existingMode = false;
+ for (int j = 0; j < records.size(); j++) {
+ if (records.get(j).hasMatchingMode(info)) {
+ existingMode = true;
+ break;
+ }
+ }
+ if (existingMode) {
+ continue;
+ }
+ // If we haven't already added a mode for this configuration to the new set of
+ // supported modes then check to see if we have one in the prior set of supported
+ // modes to reuse.
DisplayModeRecord record = findDisplayModeRecord(info);
- if (record != null) {
- record.mPhysIndex = i;
- } else {
- record = new DisplayModeRecord(info, i);
+ if (record == null) {
+ record = new DisplayModeRecord(info);
modesAdded = true;
}
records.add(record);
- if (i == activeDisplayInfo) {
+ }
+
+ // Get the currently active mode
+ DisplayModeRecord activeRecord = null;
+ for (int i = 0; i < records.size(); i++) {
+ DisplayModeRecord record = records.get(i);
+ if (record.hasMatchingMode(physicalDisplayInfos[activeDisplayInfo])){
activeRecord = record;
+ break;
}
}
// Check whether surface flinger spontaneously changed modes out from under us. Schedule
@@ -192,25 +253,48 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mActiveModeInvalid = true;
sendTraversalRequestLocked();
}
- // If no modes were added and we have the same number of modes as before, then nothing
- // actually changed except possibly the physical index (which we only care about when
- // setting the mode) so we're done.
- if (records.size() == mSupportedModes.size() && !modesAdded) {
+ // Check whether surface flinger spontaneously changed color transforms out from under
+ // us.
+ if (mActiveColorTransformId != 0
+ && mActiveColorTransformId != activeColorTransform.getId()) {
+ mActiveColorTransformInvalid = true;
+ sendTraversalRequestLocked();
+ }
+
+ boolean colorTransformsChanged =
+ colorTransforms.size() != mSupportedColorTransforms.size()
+ || colorTransformsAdded;
+ boolean recordsChanged = records.size() != mSupportedModes.size() || modesAdded;
+ // If neither the records nor the supported color transforms have changed then we're
+ // done here.
+ if (!recordsChanged && !colorTransformsChanged) {
return false;
}
// Update the index of modes.
mHavePendingChanges = true;
+
mSupportedModes.clear();
for (DisplayModeRecord record : records) {
mSupportedModes.put(record.mMode.getModeId(), record);
}
- // Update the default mode if needed.
- if (mSupportedModes.indexOfKey(mDefaultModeId) < 0) {
+ mSupportedColorTransforms.clear();
+ for (Display.ColorTransform colorTransform : colorTransforms) {
+ mSupportedColorTransforms.put(colorTransform.getId(), colorTransform);
+ }
+
+ // Update the default mode and color transform if needed. This needs to be done in
+ // tandem so we always have a default state to fall back to.
+ if (findDisplayInfoIndexLocked(mDefaultColorTransformId, mDefaultModeId) < 0) {
if (mDefaultModeId != 0) {
- Slog.w(TAG, "Default display mode no longer available, using currently active"
- + " mode as default.");
+ Slog.w(TAG, "Default display mode no longer available, using currently"
+ + " active mode as default.");
}
mDefaultModeId = activeRecord.mMode.getModeId();
+ if (mDefaultColorTransformId != 0) {
+ Slog.w(TAG, "Default color transform no longer available, using currently"
+ + " active color transform as default");
+ }
+ mDefaultColorTransformId = activeColorTransform.getId();
}
// Determine whether the active mode is still there.
if (mSupportedModes.indexOfKey(mActiveModeId) < 0) {
@@ -221,6 +305,16 @@ final class LocalDisplayAdapter extends DisplayAdapter {
mActiveModeId = mDefaultModeId;
mActiveModeInvalid = true;
}
+
+ // Determine whether the active color transform is still there.
+ if (mSupportedColorTransforms.indexOfKey(mActiveColorTransformId) < 0) {
+ if (mActiveColorTransformId != 0) {
+ Slog.w(TAG, "Active color transform no longer available, reverting"
+ + " to default transform.");
+ }
+ mActiveColorTransformId = mDefaultColorTransformId;
+ mActiveColorTransformInvalid = true;
+ }
// Schedule traversals so that we apply pending changes.
sendTraversalRequestLocked();
return true;
@@ -229,13 +323,23 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private DisplayModeRecord findDisplayModeRecord(SurfaceControl.PhysicalDisplayInfo info) {
for (int i = 0; i < mSupportedModes.size(); i++) {
DisplayModeRecord record = mSupportedModes.valueAt(i);
- if (record.mPhys.equals(info)) {
+ if (record.hasMatchingMode(info)) {
return record;
}
}
return null;
}
+ private Display.ColorTransform findColorTransform(SurfaceControl.PhysicalDisplayInfo info) {
+ for (int i = 0; i < mSupportedColorTransforms.size(); i++) {
+ Display.ColorTransform transform = mSupportedColorTransforms.valueAt(i);
+ if (transform.getColorTransform() == info.colorTransform) {
+ return transform;
+ }
+ }
+ return null;
+ }
+
@Override
public void applyPendingDisplayDeviceInfoChangesLocked() {
if (mHavePendingChanges) {
@@ -247,7 +351,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
@Override
public DisplayDeviceInfo getDisplayDeviceInfoLocked() {
if (mInfo == null) {
- SurfaceControl.PhysicalDisplayInfo phys = mSupportedModes.get(mActiveModeId).mPhys;
+ SurfaceControl.PhysicalDisplayInfo phys = mDisplayInfos[mActivePhysIndex];
mInfo = new DisplayDeviceInfo();
mInfo.width = phys.width;
mInfo.height = phys.height;
@@ -258,6 +362,13 @@ final class LocalDisplayAdapter extends DisplayAdapter {
DisplayModeRecord record = mSupportedModes.valueAt(i);
mInfo.supportedModes[i] = record.mMode;
}
+ mInfo.colorTransformId = mActiveColorTransformId;
+ mInfo.defaultColorTransformId = mDefaultColorTransformId;
+ mInfo.supportedColorTransforms =
+ new Display.ColorTransform[mSupportedColorTransforms.size()];
+ for (int i = 0; i < mSupportedColorTransforms.size(); i++) {
+ mInfo.supportedColorTransforms[i] = mSupportedColorTransforms.valueAt(i);
+ }
mInfo.appVsyncOffsetNanos = phys.appVsyncOffsetNanos;
mInfo.presentationDeadlineNanos = phys.presentationDeadlineNanos;
mInfo.state = mState;
@@ -402,7 +513,8 @@ final class LocalDisplayAdapter extends DisplayAdapter {
}
@Override
- public void requestModeInTransactionLocked(int modeId) {
+ public void requestColorTransformAndModeInTransactionLocked(
+ int colorTransformId, int modeId) {
if (modeId == 0) {
modeId = mDefaultModeId;
} else if (mSupportedModes.indexOfKey(modeId) < 0) {
@@ -410,13 +522,37 @@ final class LocalDisplayAdapter extends DisplayAdapter {
+ " reverting to default display mode.");
modeId = mDefaultModeId;
}
- if (mActiveModeId == modeId && !mActiveModeInvalid) {
+
+ if (colorTransformId == 0) {
+ colorTransformId = mDefaultColorTransformId;
+ } else if (mSupportedColorTransforms.indexOfKey(colorTransformId) < 0) {
+ Slog.w(TAG, "Requested color transform " + colorTransformId + " is not supported"
+ + " by this display, reverting to the default color transform");
+ colorTransformId = mDefaultColorTransformId;
+ }
+ int physIndex = findDisplayInfoIndexLocked(colorTransformId, modeId);
+ if (physIndex < 0) {
+ Slog.w(TAG, "Requested color transform, mode ID pair (" + colorTransformId + ", "
+ + modeId + ") not available, trying color transform with default mode ID");
+ modeId = mDefaultModeId;
+ physIndex = findDisplayInfoIndexLocked(colorTransformId, modeId);
+ if (physIndex < 0) {
+ Slog.w(TAG, "Requested color transform with default mode ID still not"
+ + " available, falling back to default color transform with default"
+ + " mode.");
+ colorTransformId = mDefaultColorTransformId;
+ physIndex = findDisplayInfoIndexLocked(colorTransformId, modeId);
+ }
+ }
+ if (physIndex > 0 && mActivePhysIndex == physIndex) {
return;
}
- DisplayModeRecord record = mSupportedModes.get(modeId);
- SurfaceControl.setActiveConfig(getDisplayTokenLocked(), record.mPhysIndex);
+ SurfaceControl.setActiveConfig(getDisplayTokenLocked(), physIndex);
+ mActivePhysIndex = physIndex;
mActiveModeId = modeId;
mActiveModeInvalid = false;
+ mActiveColorTransformId = colorTransformId;
+ mActiveColorTransformInvalid = false;
updateDeviceInfoLocked();
}
@@ -424,10 +560,43 @@ final class LocalDisplayAdapter extends DisplayAdapter {
public void dumpLocked(PrintWriter pw) {
super.dumpLocked(pw);
pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
+ pw.println("mActivePhysIndex=" + mActivePhysIndex);
pw.println("mActiveModeId=" + mActiveModeId);
+ pw.println("mActiveColorTransformId=" + mActiveColorTransformId);
pw.println("mState=" + Display.stateToString(mState));
pw.println("mBrightness=" + mBrightness);
pw.println("mBacklight=" + mBacklight);
+ pw.println("mDisplayInfos=");
+ for (int i = 0; i < mDisplayInfos.length; i++) {
+ pw.println(" " + mDisplayInfos[i]);
+ }
+ pw.println("mSupportedModes=");
+ for (int i = 0; i < mSupportedModes.size(); i++) {
+ pw.println(" " + mSupportedModes.valueAt(i));
+ }
+ pw.println("mSupportedColorTransforms=[");
+ for (int i = 0; i < mSupportedColorTransforms.size(); i++) {
+ if (i != 0) {
+ pw.print(", ");
+ }
+ pw.print(mSupportedColorTransforms.valueAt(i));
+ }
+ pw.println("]");
+ }
+
+ private int findDisplayInfoIndexLocked(int colorTransformId, int modeId) {
+ DisplayModeRecord record = mSupportedModes.get(modeId);
+ Display.ColorTransform transform = mSupportedColorTransforms.get(colorTransformId);
+ if (record != null && transform != null) {
+ for (int i = 0; i < mDisplayInfos.length; i++) {
+ SurfaceControl.PhysicalDisplayInfo info = mDisplayInfos[i];
+ if (info.colorTransform == transform.getColorTransform()
+ && record.hasMatchingMode(info)){
+ return i;
+ }
+ }
+ }
+ return -1;
}
private void updateDeviceInfoLocked() {
@@ -441,13 +610,28 @@ final class LocalDisplayAdapter extends DisplayAdapter {
*/
private static final class DisplayModeRecord {
public final Display.Mode mMode;
- public final SurfaceControl.PhysicalDisplayInfo mPhys;
- public int mPhysIndex;
- public DisplayModeRecord(SurfaceControl.PhysicalDisplayInfo phys, int physIndex) {
+ public DisplayModeRecord(SurfaceControl.PhysicalDisplayInfo phys) {
mMode = createMode(phys.width, phys.height, phys.refreshRate);
- mPhys = phys;
- mPhysIndex = physIndex;
+ }
+
+ /**
+ * Returns whether the mode generated by the given PhysicalDisplayInfo matches the mode
+ * contained by the record modulo mode ID.
+ *
+ * Note that this doesn't necessarily mean the the PhysicalDisplayInfos are identical, just
+ * that they generate identical modes.
+ */
+ public boolean hasMatchingMode(SurfaceControl.PhysicalDisplayInfo info) {
+ int modeRefreshRate = Float.floatToIntBits(mMode.getRefreshRate());
+ int displayInfoRefreshRate = Float.floatToIntBits(info.refreshRate);
+ return mMode.getPhysicalWidth() == info.width
+ && mMode.getPhysicalHeight() == info.height
+ && modeRefreshRate == displayInfoRefreshRate;
+ }
+
+ public String toString() {
+ return "DisplayModeRecord{mMode=" + mMode + "}";
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 6efc99a0c342..6dae397cff21 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -74,6 +74,7 @@ final class LogicalDisplay {
private boolean mHasContent;
private int mRequestedModeId;
+ private int mRequestedColorTransformId;
// The display offsets to apply to the display projection.
private int mDisplayOffsetX;
@@ -235,6 +236,11 @@ final class LogicalDisplay {
mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
mBaseDisplayInfo.supportedModes = Arrays.copyOf(
deviceInfo.supportedModes, deviceInfo.supportedModes.length);
+ mBaseDisplayInfo.colorTransformId = deviceInfo.colorTransformId;
+ mBaseDisplayInfo.defaultColorTransformId = deviceInfo.defaultColorTransformId;
+ mBaseDisplayInfo.supportedColorTransforms = Arrays.copyOf(
+ deviceInfo.supportedColorTransforms,
+ deviceInfo.supportedColorTransforms.length);
mBaseDisplayInfo.logicalDensityDpi = deviceInfo.densityDpi;
mBaseDisplayInfo.physicalXDpi = deviceInfo.xDpi;
mBaseDisplayInfo.physicalYDpi = deviceInfo.yDpi;
@@ -275,11 +281,12 @@ final class LogicalDisplay {
// Set the layer stack.
device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);
- // Set the mode.
+ // Set the color transform and mode.
if (device == mPrimaryDisplayDevice) {
- device.requestModeInTransactionLocked(mRequestedModeId);
+ device.requestColorTransformAndModeInTransactionLocked(
+ mRequestedColorTransformId, mRequestedModeId);
} else {
- device.requestModeInTransactionLocked(0); // Revert to default.
+ device.requestColorTransformAndModeInTransactionLocked(0, 0); // Revert to default.
}
// Only grab the display info now as it may have been changed based on the requests above.
@@ -383,6 +390,18 @@ final class LogicalDisplay {
}
/**
+ * Requests the given color transform.
+ */
+ public void setRequestedColorTransformIdLocked(int colorTransformId) {
+ mRequestedColorTransformId = colorTransformId;
+ }
+
+ /** Returns the pending requested color transform. */
+ public int getRequestedColorTransformIdLocked() {
+ return mRequestedColorTransformId;
+ }
+
+ /**
* Gets the burn-in offset in X.
*/
public int getDisplayOffsetXLocked() {
@@ -409,6 +428,7 @@ final class LogicalDisplay {
pw.println("mLayerStack=" + mLayerStack);
pw.println("mHasContent=" + mHasContent);
pw.println("mRequestedMode=" + mRequestedModeId);
+ pw.println("mRequestedColorTransformId=" + mRequestedColorTransformId);
pw.println("mDisplayOffset=(" + mDisplayOffsetX + ", " + mDisplayOffsetY + ")");
pw.println("mPrimaryDisplayDevice=" + (mPrimaryDisplayDevice != null ?
mPrimaryDisplayDevice.getNameLocked() : "null"));
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 0bddff076c18..cf6264ace34f 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -310,7 +310,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
}
@Override
- public void requestModeInTransactionLocked(int id) {
+ public void requestColorTransformAndModeInTransactionLocked(int color, int id) {
int index = -1;
if (id == 0) {
// Use the default.
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index ea7d85e36944..ec7c1c437d92 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -337,7 +337,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
return;
}
stopPendingOperations(true);
- mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted);
+ mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted, token.toString());
final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
try {
final int result = daemon.enroll(cryptoToken, groupId, timeout);
@@ -417,14 +417,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
void startAuthentication(IBinder token, long opId, int groupId,
- IFingerprintServiceReceiver receiver, int flags, boolean restricted) {
+ IFingerprintServiceReceiver receiver, int flags, boolean restricted,
+ String opPackageName) {
IFingerprintDaemon daemon = getFingerprintDaemon();
if (daemon == null) {
Slog.w(TAG, "startAuthentication: no fingeprintd!");
return;
}
stopPendingOperations(true);
- mAuthClient = new ClientMonitor(token, receiver, groupId, restricted);
+ mAuthClient = new ClientMonitor(token, receiver, groupId, restricted, opPackageName);
if (inLockoutMode()) {
Slog.v(TAG, "In lockout mode; disallowing authentication");
if (!mAuthClient.sendError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
@@ -481,7 +482,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
stopPendingOperations(true);
- mRemoveClient = new ClientMonitor(token, receiver, userId, restricted);
+ mRemoveClient = new ClientMonitor(token, receiver, userId, restricted, token.toString());
// The fingerprint template ids will be removed when we get confirmation from the HAL
try {
final int result = daemon.remove(fingerId, userId);
@@ -574,11 +575,11 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
}
if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
!= AppOpsManager.MODE_ALLOWED) {
- Slog.v(TAG, "Rejecting " + opPackageName + " ; permission denied");
+ Slog.w(TAG, "Rejecting " + opPackageName + " ; permission denied");
return false;
}
if (foregroundOnly && !isForegroundActivity(uid, pid)) {
- Slog.v(TAG, "Rejecting " + opPackageName + " ; not in foreground");
+ Slog.w(TAG, "Rejecting " + opPackageName + " ; not in foreground");
return false;
}
return true;
@@ -606,13 +607,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
IFingerprintServiceReceiver receiver;
int userId;
boolean restricted; // True if client does not have MANAGE_FINGERPRINT permission
+ String owner;
public ClientMonitor(IBinder token, IFingerprintServiceReceiver receiver, int userId,
- boolean restricted) {
+ boolean restricted, String owner) {
this.token = token;
this.receiver = receiver;
this.userId = userId;
this.restricted = restricted;
+ this.owner = owner; // name of the client that owns this - for debugging
try {
token.linkToDeath(this, 0);
} catch (RemoteException e) {
@@ -695,6 +698,10 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
if (!authenticated) {
receiver.onAuthenticationFailed(mHalDeviceId);
} else {
+ if (DEBUG) {
+ Slog.v(TAG, "onAuthenticated(owner=" + mAuthClient.owner
+ + ", id=" + fpId + ", gp=" + groupId + ")");
+ }
Fingerprint fp = !restricted ?
new Fingerprint("" /* TODO */, groupId, fpId, mHalDeviceId) : null;
receiver.onAuthenticationSucceeded(mHalDeviceId, fp);
@@ -915,6 +922,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
final IFingerprintServiceReceiver receiver, final int flags,
final String opPackageName) {
if (!canUseFingerprint(opPackageName, true /* foregroundOnly */)) {
+ if (DEBUG) Slog.v(TAG, "authenticate(): reject " + opPackageName);
return;
}
@@ -927,7 +935,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
@Override
public void run() {
MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
- startAuthentication(token, opId, effectiveGroupId, receiver, flags, restricted);
+ startAuthentication(token, opId, effectiveGroupId, receiver, flags, restricted,
+ opPackageName);
}
});
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 96a5e0057d61..b5046056e913 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -245,6 +245,8 @@ final class DefaultPermissionGrantPolicy {
if (verifierPackage != null
&& doesPackageSupportRuntimePermissions(verifierPackage)) {
grantRuntimePermissionsLPw(verifierPackage, STORAGE_PERMISSIONS, true, userId);
+ grantRuntimePermissionsLPw(verifierPackage, PHONE_PERMISSIONS, false, userId);
+ grantRuntimePermissionsLPw(verifierPackage, SMS_PERMISSIONS, false, userId);
}
// SetupWizard
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 7024ec8b13b9..8c23648f0f0f 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -217,8 +217,7 @@ final class PackageDexOptimizer {
@Nullable
private String createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet)
throws IOException {
- if ((pkg.isSystemApp() && !pkg.isUpdatedSystemApp()) || pkg.isForwardLocked()
- || pkg.applicationInfo.isExternalAsec()) {
+ if (!pkg.canHaveOatDir()) {
return null;
}
File codePath = new File(pkg.codePath);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 96c546058442..3330a502236e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13628,7 +13628,21 @@ public class PackageManagerService extends IPackageManager.Stub {
// TODO(multiArch): Extend getSizeInfo to look at *all* instruction sets, not
// just the primary.
String[] dexCodeInstructionSets = getDexCodeInstructionSets(getAppDexInstructionSets(ps));
- int res = mInstaller.getSizeInfo(p.volumeUuid, packageName, userHandle, p.baseCodePath,
+
+ String apkPath;
+ File packageDir = new File(p.codePath);
+
+ if (packageDir.isDirectory() && p.canHaveOatDir()) {
+ apkPath = packageDir.getAbsolutePath();
+ // If libDirRoot is inside a package dir, set it to null to avoid it being counted twice
+ if (libDirRoot != null && libDirRoot.startsWith(apkPath)) {
+ libDirRoot = null;
+ }
+ } else {
+ apkPath = p.baseCodePath;
+ }
+
+ int res = mInstaller.getSizeInfo(p.volumeUuid, packageName, userHandle, apkPath,
libDirRoot, publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
if (res < 0) {
return false;
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index fb461ae3bfb0..80c604fc1b6b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -266,9 +266,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowManagerFuncs mWindowManagerFuncs;
WindowManagerInternal mWindowManagerInternal;
PowerManager mPowerManager;
- PowerManagerInternal mPowerManagerInternal;
ActivityManagerInternal mActivityManagerInternal;
DreamManagerInternal mDreamManagerInternal;
+ PowerManagerInternal mPowerManagerInternal;
IStatusBarService mStatusBarService;
boolean mPreloadedRecentApps;
final Object mServiceAquireLock = new Object();
@@ -1332,6 +1332,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
+ mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
@@ -1509,6 +1510,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
@Override
+ public void onFling(int duration) {
+ if (mPowerManagerInternal != null) {
+ mPowerManagerInternal.powerHint(
+ PowerManagerInternal.POWER_HINT_INTERACTION, duration);
+ }
+ }
+ @Override
public void onDebug() {
// no-op
}
@@ -6086,6 +6094,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mKeyguardDelegate.bindService(mContext);
mKeyguardDelegate.onBootCompleted();
}
+ mSystemGestures.systemReady();
}
/** {@inheritDoc} */
@@ -7029,5 +7038,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (mBurnInProtectionHelper != null) {
mBurnInProtectionHelper.dump(prefix, pw);
}
+ if (mKeyguardDelegate != null) {
+ mKeyguardDelegate.dump(prefix, pw);
+ }
}
}
diff --git a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
index 627b3284be18..e4bd21d40233 100644
--- a/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
+++ b/services/core/java/com/android/server/policy/SystemGesturesPointerEventListener.java
@@ -17,9 +17,14 @@
package com.android.server.policy;
import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
import android.util.Slog;
+import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.WindowManagerPolicy.PointerEventListener;
+import android.widget.OverScroller;
/*
* Listens for system-wide input gestures, firing callbacks when detected.
@@ -31,12 +36,14 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
private static final long SWIPE_TIMEOUT_MS = 500;
private static final int MAX_TRACKED_POINTERS = 32; // max per input system
private static final int UNTRACKED_POINTER = -1;
+ private static final int MAX_FLING_TIME_MILLIS = 5000;
private static final int SWIPE_NONE = 0;
private static final int SWIPE_FROM_TOP = 1;
private static final int SWIPE_FROM_BOTTOM = 2;
private static final int SWIPE_FROM_RIGHT = 3;
+ private final Context mContext;
private final int mSwipeStartThreshold;
private final int mSwipeDistanceThreshold;
private final Callbacks mCallbacks;
@@ -45,13 +52,18 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
private final float[] mDownY = new float[MAX_TRACKED_POINTERS];
private final long[] mDownTime = new long[MAX_TRACKED_POINTERS];
+ private GestureDetector mGestureDetector;
+ private OverScroller mOverscroller;
+
int screenHeight;
int screenWidth;
private int mDownPointers;
private boolean mSwipeFireable;
private boolean mDebugFireable;
+ private long mLastFlingTime;
public SystemGesturesPointerEventListener(Context context, Callbacks callbacks) {
+ mContext = context;
mCallbacks = checkNull("callbacks", callbacks);
mSwipeStartThreshold = checkNull("context", context).getResources()
.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
@@ -67,8 +79,17 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
return arg;
}
+ public void systemReady() {
+ Handler h = new Handler(Looper.myLooper());
+ mGestureDetector = new GestureDetector(mContext, new FlingGestureDetector(), h);
+ mOverscroller = new OverScroller(mContext);
+ }
+
@Override
public void onPointerEvent(MotionEvent event) {
+ if (mGestureDetector != null) {
+ mGestureDetector.onTouchEvent(event);
+ }
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
mSwipeFireable = true;
@@ -190,10 +211,40 @@ public class SystemGesturesPointerEventListener implements PointerEventListener
return SWIPE_NONE;
}
+ private final class FlingGestureDetector extends GestureDetector.SimpleOnGestureListener {
+ @Override
+ public boolean onSingleTapUp(MotionEvent e) {
+ if (!mOverscroller.isFinished()) {
+ mOverscroller.forceFinished(true);
+ }
+ return true;
+ }
+ @Override
+ public boolean onFling(MotionEvent down, MotionEvent up,
+ float velocityX, float velocityY) {
+ mOverscroller.computeScrollOffset();
+ long now = SystemClock.uptimeMillis();
+
+ if (mLastFlingTime != 0 && now > mLastFlingTime + MAX_FLING_TIME_MILLIS) {
+ mOverscroller.forceFinished(true);
+ }
+ mOverscroller.fling(0, 0, (int)velocityX, (int)velocityY,
+ Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);
+ int duration = mOverscroller.getDuration();
+ if (duration > MAX_FLING_TIME_MILLIS) {
+ duration = MAX_FLING_TIME_MILLIS;
+ }
+ mLastFlingTime = now;
+ mCallbacks.onFling(duration);
+ return true;
+ }
+ }
+
interface Callbacks {
void onSwipeFromTop();
void onSwipeFromBottom();
void onSwipeFromRight();
+ void onFling(int durationMs);
void onDown();
void onUpOrCancel();
void onDebug();
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 6b45941d91ec..7ae3c79e0fe5 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -23,6 +23,8 @@ import com.android.internal.policy.IKeyguardDrawnCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
+import java.io.PrintWriter;
+
/**
* A local class that keeps a cache of keyguard state that can be restored in the event
* keyguard crashes. It currently also allows runtime-selectable
@@ -393,4 +395,26 @@ public class KeyguardServiceDelegate {
mKeyguardService.onActivityDrawn();
}
}
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + TAG);
+ prefix += " ";
+ pw.println(prefix + "showing=" + mKeyguardState.showing);
+ pw.println(prefix + "showingAndNotOccluded=" + mKeyguardState.showingAndNotOccluded);
+ pw.println(prefix + "inputRestricted=" + mKeyguardState.inputRestricted);
+ pw.println(prefix + "occluded=" + mKeyguardState.occluded);
+ pw.println(prefix + "secure=" + mKeyguardState.secure);
+ pw.println(prefix + "dreaming=" + mKeyguardState.dreaming);
+ pw.println(prefix + "systemIsReady=" + mKeyguardState.systemIsReady);
+ pw.println(prefix + "deviceHasKeyguard=" + mKeyguardState.deviceHasKeyguard);
+ pw.println(prefix + "enabled=" + mKeyguardState.enabled);
+ pw.println(prefix + "offReason=" + mKeyguardState.offReason);
+ pw.println(prefix + "currentUser=" + mKeyguardState.currentUser);
+ pw.println(prefix + "bootCompleted=" + mKeyguardState.bootCompleted);
+ pw.println(prefix + "screenState=" + mKeyguardState.screenState);
+ pw.println(prefix + "interactiveState=" + mKeyguardState.interactiveState);
+ if (mKeyguardService != null) {
+ mKeyguardService.dump(prefix, pw);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index cd88b664e2f8..429b18866a61 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -27,6 +27,8 @@ import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
import com.android.internal.policy.IKeyguardStateCallback;
+import java.io.PrintWriter;
+
/**
* A wrapper class for KeyguardService. It implements IKeyguardService to ensure the interface
* remains consistent.
@@ -239,4 +241,8 @@ public class KeyguardServiceWrapper implements IKeyguardService {
public boolean isInputRestricted() {
return mKeyguardStateMonitor.isInputRestricted();
}
+
+ public void dump(String prefix, PrintWriter pw) {
+ mKeyguardStateMonitor.dump(prefix, pw);
+ }
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index f1f9c5087aa7..30cff039f11a 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -25,6 +25,8 @@ import com.android.internal.policy.IKeyguardService;
import com.android.internal.policy.IKeyguardStateCallback;
import com.android.internal.widget.LockPatternUtils;
+import java.io.PrintWriter;
+
/**
* Maintains a cached copy of Keyguard's state.
* @hide
@@ -90,4 +92,13 @@ public class KeyguardStateMonitor extends IKeyguardStateCallback.Stub {
public void onInputRestrictedStateChanged(boolean inputRestricted) {
mInputRestricted = inputRestricted;
}
+
+ public void dump(String prefix, PrintWriter pw) {
+ pw.println(prefix + TAG);
+ prefix += " ";
+ pw.println(prefix + "mIsShowing=" + mIsShowing);
+ pw.println(prefix + "mSimSecure=" + mSimSecure);
+ pw.println(prefix + "mInputRestricted=" + mInputRestricted);
+ pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
+ }
} \ No newline at end of file
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a06ea1f1f752..2cb3db2fe596 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -76,6 +76,7 @@ import java.util.Arrays;
import libcore.util.Objects;
+import static android.os.PowerManagerInternal.POWER_HINT_INTERACTION;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING;
@@ -150,7 +151,6 @@ public final class PowerManagerService extends SystemService
private static final int SCREEN_BRIGHTNESS_BOOST_TIMEOUT = 5 * 1000;
// Power hints defined in hardware/libhardware/include/hardware/power.h.
- private static final int POWER_HINT_INTERACTION = 2;
private static final int POWER_HINT_LOW_POWER = 5;
// Power features defined in hardware/libhardware/include/hardware/power.h.
@@ -3565,5 +3565,10 @@ public final class PowerManagerService extends SystemService
public void uidGone(int uid) {
uidGoneInternal(uid);
}
+
+ @Override
+ public void powerHint(int hintId, int data) {
+ powerHintInternal(hintId, data);
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b888a78e6156..2166e7e8a843 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -996,7 +996,6 @@ public class WindowManagerService extends IWindowManager.Stub
SurfaceControl.closeTransaction();
}
- updateCircularDisplayMaskIfNeeded();
showEmulatorDisplayOverlayIfNeeded();
}
@@ -5943,7 +5942,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- public void updateCircularDisplayMaskIfNeeded() {
+ private void updateCircularDisplayMaskIfNeeded() {
// we're fullscreen and not hosted in an ActivityView
if (mContext.getResources().getConfiguration().isScreenRound()
&& mContext.getResources().getBoolean(
@@ -7659,6 +7658,8 @@ public class WindowManagerService extends IWindowManager.Stub
mActivityManager.updateConfiguration(null);
} catch (RemoteException e) {
}
+
+ updateCircularDisplayMaskIfNeeded();
}
private void displayReady(int displayId) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 7dd16d145e32..3effe6371a98 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1047,6 +1047,12 @@ public final class SystemServer {
w.getDefaultDisplay().getMetrics(metrics);
context.getResources().updateConfiguration(config, metrics);
+ // The system context's theme may be configuration-dependent.
+ final Theme systemTheme = context.getTheme();
+ if (systemTheme.getChangingConfigurations() != 0) {
+ systemTheme.rebase();
+ }
+
try {
// TODO: use boot phase
mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 1321281d00ed..49062d068d8a 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -417,10 +417,9 @@ public class UsbDeviceManager {
private boolean setUsbConfig(String config) {
if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
// set the new configuration
- String oldConfig = SystemProperties.get(USB_CONFIG_PROPERTY);
- if (!config.equals(oldConfig)) {
- SystemProperties.set(USB_CONFIG_PROPERTY, config);
- }
+ // we always set it due to b/23631400, where adbd was getting killed
+ // and not restarted due to property timeouts on some devices
+ SystemProperties.set(USB_CONFIG_PROPERTY, config);
return waitForState(config);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e675c6df166e..aa4da4b1b690 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -78,6 +78,15 @@ public class CarrierConfigManager {
public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
/**
+ * Flag to require or skip entitlement checks.
+ * If true, entitlement checks will be executed if device has been configured for it,
+ * If false, entitlement checks will be skipped.
+ * @hide
+ */
+ public static final String
+ KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
+
+ /**
* If true, enable vibration (haptic feedback) for key presses in the EmergencyDialer activity.
* The pattern is set on a per-platform basis using config_virtualKeyVibePattern. To be
* consistent with the regular Dialer, this value should agree with the corresponding values
@@ -277,6 +286,17 @@ public class CarrierConfigManager {
"carrier_instant_lettering_invalid_chars_string";
/**
+ * When IMS instant lettering is available for a carrier (see
+ * {@link #KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL}), determines a list of characters which
+ * must be escaped with a backslash '\' character. Should be specified as a string containing
+ * the characters to be escaped. For example to escape quote and backslash the string would be
+ * a quote and a backslash.
+ * @hide
+ */
+ public static final String KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING =
+ "carrier_instant_lettering_escaped_chars_string";
+
+ /**
* If Voice Radio Technology is RIL_RADIO_TECHNOLOGY_LTE:14 or RIL_RADIO_TECHNOLOGY_UNKNOWN:0
* this is the value that should be used instead. A configuration value of
* RIL_RADIO_TECHNOLOGY_UNKNOWN:0 means there is no replacement value and that the default
@@ -299,6 +319,14 @@ public class CarrierConfigManager {
public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL =
"carrier_force_disable_etws_cmas_test_bool";
+ /**
+ * The default flag specifying whether "Turn on Notifications" option will be always shown in
+ * Settings->More->Emergency broadcasts menu regardless developer options is turned on or not.
+ * @hide
+ */
+ public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL =
+ "always_show_emergency_alert_onoff_bool";
+
/* The following 3 fields are related to carrier visual voicemail. */
/**
@@ -463,6 +491,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING, "");
+ sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_ESCAPED_CHARS_STRING, "");
sDefaults.putBoolean(KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL, false);
sDefaults.putBoolean(KEY_DTMF_TYPE_ENABLED_BOOL, false);
sDefaults.putBoolean(KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL, true);
@@ -483,6 +512,7 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL, false);
sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_UI_BOOL, false);
sDefaults.putBoolean(KEY_WORLD_PHONE_BOOL, false);
+ sDefaults.putBoolean(KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL, true);
sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0);
sDefaults.putString(KEY_DEFAULT_SIM_CALL_MANAGER_STRING, "");
sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
@@ -494,6 +524,7 @@ public class CarrierConfigManager {
sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING, "");
sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING, "");
sDefaults.putBoolean(KEY_CSP_ENABLED_BOOL, false);
+ sDefaults.putBoolean(KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL, false);
sDefaults.putStringArray(KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, null);
sDefaults.putStringArray(KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, null);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f6e4bed86b16..d22727d14829 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3611,11 +3611,12 @@ public class TelephonyManager {
*
* @hide
*/
- public boolean setNetworkSelectionModeManual(int subId, OperatorInfo operator) {
+ public boolean setNetworkSelectionModeManual(int subId, OperatorInfo operator,
+ boolean persistSelection) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.setNetworkSelectionModeManual(subId, operator);
+ return telephony.setNetworkSelectionModeManual(subId, operator, persistSelection);
} catch (RemoteException ex) {
Rlog.e(TAG, "setNetworkSelectionModeManual RemoteException", ex);
} catch (NullPointerException ex) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 661f12db3f9c..dcece26d6c27 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -707,9 +707,13 @@ interface ITelephony {
*
* @param subId the id of the subscription.
* @param operatorInfo the operator to attach to.
+ * @param persistSelection should the selection persist till reboot or its
+ * turned off? Will also result in notification being not shown to
+ * the user if the signal is lost.
* @return true if the request suceeded.
*/
- boolean setNetworkSelectionModeManual(int subId, in OperatorInfo operator);
+ boolean setNetworkSelectionModeManual(int subId, in OperatorInfo operator,
+ boolean persistSelection);
/**
* Set the preferred network type.