summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--api/system-current.txt1
-rw-r--r--api/test-current.txt1
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java3
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java2
-rw-r--r--core/java/android/app/FragmentManager.java54
-rw-r--r--core/java/android/content/pm/PackageParser.java122
-rwxr-xr-xcore/java/android/provider/Settings.java17
-rw-r--r--core/java/android/text/InputFilter.java128
-rw-r--r--core/java/android/text/TextLine.java17
-rw-r--r--core/java/android/text/TextUtils.java71
-rw-r--r--core/java/android/text/method/AllCapsTransformationMethod.java67
-rw-r--r--core/jni/android/graphics/Paint.cpp26
-rw-r--r--core/res/AndroidManifest.xml6
-rw-r--r--core/tests/coretests/apks/install_multi_package/Android.mk12
-rw-r--r--core/tests/coretests/apks/install_multi_package/AndroidManifest.xml104
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java24
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java30
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java24
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java30
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java24
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java57
-rw-r--r--core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java30
-rw-r--r--core/tests/coretests/assets/fonts/underlineTestFont.ttfbin0 -> 612 bytes
-rw-r--r--core/tests/coretests/assets/fonts/underlineTestFont.ttx163
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageParserTest.java126
-rw-r--r--core/tests/coretests/src/android/graphics/PaintTest.java34
-rw-r--r--core/tests/coretests/src/android/text/TextUtilsTest.java92
-rw-r--r--graphics/java/android/graphics/Paint.java12
-rw-r--r--libs/hwui/hwui/Canvas.cpp34
-rw-r--r--libs/hwui/hwui/Paint.h9
-rw-r--r--lowpan/java/android/net/lowpan/LowpanBeaconInfo.java4
-rw-r--r--lowpan/java/android/net/lowpan/LowpanChannelInfo.java5
-rw-r--r--lowpan/java/android/net/lowpan/LowpanCommissioningSession.java4
-rw-r--r--lowpan/java/android/net/lowpan/LowpanCredential.java6
-rw-r--r--lowpan/java/android/net/lowpan/LowpanEnergyScanResult.java3
-rw-r--r--lowpan/java/android/net/lowpan/LowpanException.java2
-rw-r--r--lowpan/java/android/net/lowpan/LowpanIdentity.java14
-rw-r--r--lowpan/java/android/net/lowpan/LowpanInterface.java85
-rw-r--r--lowpan/java/android/net/lowpan/LowpanManager.java67
-rw-r--r--lowpan/java/android/net/lowpan/LowpanProvision.java8
-rw-r--r--lowpan/java/android/net/lowpan/LowpanScanner.java47
-rw-r--r--packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java21
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java26
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java25
-rw-r--r--packages/SystemUI/res/values/config.xml3
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeHost.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java8
-rw-r--r--proto/src/metrics_constants.proto5
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java6
-rw-r--r--telephony/java/android/telephony/Telephony.java23
-rw-r--r--tools/aapt2/Main.cpp2
-rw-r--r--tools/aapt2/readme.md14
64 files changed, 1729 insertions, 382 deletions
diff --git a/api/current.txt b/api/current.txt
index a71c63ae598c..a04f95bde91d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41102,6 +41102,7 @@ package android.text {
public static class InputFilter.AllCaps implements android.text.InputFilter {
ctor public InputFilter.AllCaps();
+ ctor public InputFilter.AllCaps(java.util.Locale);
method public java.lang.CharSequence filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index fbe210925ab3..99208d5b3730 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -44647,6 +44647,7 @@ package android.text {
public static class InputFilter.AllCaps implements android.text.InputFilter {
ctor public InputFilter.AllCaps();
+ ctor public InputFilter.AllCaps(java.util.Locale);
method public java.lang.CharSequence filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 96bda4f3c808..9326217e21d4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -41329,6 +41329,7 @@ package android.text {
public static class InputFilter.AllCaps implements android.text.InputFilter {
ctor public InputFilter.AllCaps();
+ ctor public InputFilter.AllCaps(java.util.Locale);
method public java.lang.CharSequence filter(java.lang.CharSequence, int, int, android.text.Spanned, int, int);
}
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 1bcfb22fe2f2..1b77427c5b72 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -270,7 +270,8 @@ public final class Bmgr {
case BackupManager.ERROR_TRANSPORT_ABORTED:
return "Transport error";
case BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED:
- return "Transport rejected package";
+ return "Transport rejected package because it wasn't able to process it"
+ + " at the time";
case BackupManager.ERROR_AGENT_FAILURE:
return "Agent error";
case BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED:
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index d71573f7ca50..9813cb1631ce 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1033,7 +1033,7 @@ public final class Pm {
if (info != null) {
System.out.println("Success: created user id " + info.id);
- return 1;
+ return 0;
} else {
System.err.println("Error: couldn't create User.");
return 1;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 9fb9c00ee9e9..3ad30bf2b045 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -679,7 +679,8 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
ArrayList<Integer> mAvailBackStackIndices;
ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
- CopyOnWriteArrayList<Pair<FragmentLifecycleCallbacks, Boolean>> mLifecycleCallbacks;
+ final CopyOnWriteArrayList<Pair<FragmentLifecycleCallbacks, Boolean>>
+ mLifecycleCallbacks = new CopyOnWriteArrayList<>();
int mCurState = Fragment.INITIALIZING;
FragmentHostCallback<?> mHost;
@@ -3189,17 +3190,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
public void registerFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb,
boolean recursive) {
- if (mLifecycleCallbacks == null) {
- mLifecycleCallbacks = new CopyOnWriteArrayList<>();
- }
- mLifecycleCallbacks.add(new Pair(cb, recursive));
+ mLifecycleCallbacks.add(new Pair<>(cb, recursive));
}
public void unregisterFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb) {
- if (mLifecycleCallbacks == null) {
- return;
- }
-
synchronized (mLifecycleCallbacks) {
for (int i = 0, N = mLifecycleCallbacks.size(); i < N; i++) {
if (mLifecycleCallbacks.get(i).first == cb) {
@@ -3218,9 +3212,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentPreAttached(f, context, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentPreAttached(this, f, context);
@@ -3236,9 +3227,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentAttached(f, context, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentAttached(this, f, context);
@@ -3255,9 +3243,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentPreCreated(f, savedInstanceState, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentPreCreated(this, f, savedInstanceState);
@@ -3273,9 +3258,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentCreated(f, savedInstanceState, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentCreated(this, f, savedInstanceState);
@@ -3292,9 +3274,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentActivityCreated(f, savedInstanceState, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentActivityCreated(this, f, savedInstanceState);
@@ -3311,9 +3290,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentViewCreated(f, v, savedInstanceState, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentViewCreated(this, f, v, savedInstanceState);
@@ -3329,9 +3305,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentStarted(f, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentStarted(this, f);
@@ -3347,9 +3320,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentResumed(f, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentResumed(this, f);
@@ -3365,9 +3335,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentPaused(f, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentPaused(this, f);
@@ -3383,9 +3350,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentStopped(f, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentStopped(this, f);
@@ -3401,9 +3365,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentSaveInstanceState(f, outState, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentSaveInstanceState(this, f, outState);
@@ -3419,9 +3380,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentViewDestroyed(f, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentViewDestroyed(this, f);
@@ -3437,9 +3395,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentDestroyed(f, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentDestroyed(this, f);
@@ -3455,9 +3410,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
.dispatchOnFragmentDetached(f, true);
}
}
- if (mLifecycleCallbacks == null) {
- return;
- }
for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
if (!onlyRecursive || p.second) {
p.first.onFragmentDetached(this, f);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 9b0bab427478..6109531474d9 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -27,9 +27,9 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VER
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.content.pm.ApplicationInfo.FLAG_SUSPENDED;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
@@ -50,9 +50,9 @@ import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.pm.split.SplitAssetDependencyLoader;
import android.content.pm.split.SplitAssetLoader;
-import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -148,8 +148,9 @@ public class PackageParser {
private static final String PROPERTY_CHILD_PACKAGES_ENABLED =
"persist.sys.child_packages_enabled";
+ // TODO: Decide the correct default before O-MR1.
private static final boolean MULTI_PACKAGE_APK_ENABLED = Build.IS_DEBUGGABLE &&
- SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
+ SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, true);
private static final int MAX_PACKAGES_PER_APK = 5;
@@ -498,11 +499,25 @@ public class PackageParser {
}
}
+ /**
+ * Cached parse state for new components.
+ *
+ * Allows reuse of the same parse argument records to avoid GC pressure. Lifetime is carefully
+ * scoped to the parsing of a single application element.
+ */
+ private static class CachedComponentArgs {
+ ParseComponentArgs mActivityArgs;
+ ParseComponentArgs mActivityAliasArgs;
+ ParseComponentArgs mServiceArgs;
+ ParseComponentArgs mProviderArgs;
+ }
+
+ /**
+ * Cached state for parsing instrumentation to avoid GC pressure.
+ *
+ * Must be manually reset to null for each new manifest.
+ */
private ParsePackageItemArgs mParseInstrumentationArgs;
- private ParseComponentArgs mParseActivityArgs;
- private ParseComponentArgs mParseActivityAliasArgs;
- private ParseComponentArgs mParseServiceArgs;
- private ParseComponentArgs mParseProviderArgs;
/** If set to true, we will only allow package files that exactly match
* the DTD. Otherwise, we try to get as much from the package as we
@@ -1335,9 +1350,6 @@ public class PackageParser {
parsePackageSplitNames(parser, attrs);
mParseInstrumentationArgs = null;
- mParseActivityArgs = null;
- mParseServiceArgs = null;
- mParseProviderArgs = null;
int type;
@@ -2044,9 +2056,6 @@ public class PackageParser {
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
mParseInstrumentationArgs = null;
- mParseActivityArgs = null;
- mParseServiceArgs = null;
- mParseProviderArgs = null;
int type;
boolean foundApp = false;
@@ -3638,6 +3647,9 @@ public class PackageParser {
}
final int innerDepth = parser.getDepth();
+ // IMPORTANT: These must only be cached for a single <application> to avoid components
+ // getting added to the wrong package.
+ final CachedComponentArgs cachedArgs = new CachedComponentArgs();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
@@ -3647,7 +3659,7 @@ public class PackageParser {
String tagName = parser.getName();
if (tagName.equals("activity")) {
- Activity a = parseActivity(owner, res, parser, flags, outError, false,
+ Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
@@ -3657,7 +3669,8 @@ public class PackageParser {
owner.activities.add(a);
} else if (tagName.equals("receiver")) {
- Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
+ Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
+ true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
@@ -3666,7 +3679,7 @@ public class PackageParser {
owner.receivers.add(a);
} else if (tagName.equals("service")) {
- Service s = parseService(owner, res, parser, flags, outError);
+ Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
@@ -3675,7 +3688,7 @@ public class PackageParser {
owner.services.add(s);
} else if (tagName.equals("provider")) {
- Provider p = parseProvider(owner, res, parser, flags, outError);
+ Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
if (p == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
@@ -3684,7 +3697,7 @@ public class PackageParser {
owner.providers.add(p);
} else if (tagName.equals("activity-alias")) {
- Activity a = parseActivityAlias(owner, res, parser, flags, outError);
+ Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
@@ -3892,9 +3905,12 @@ public class PackageParser {
ComponentInfo parsedComponent = null;
+ // IMPORTANT: These must only be cached for a single <application> to avoid components
+ // getting added to the wrong package.
+ final CachedComponentArgs cachedArgs = new CachedComponentArgs();
String tagName = parser.getName();
if (tagName.equals("activity")) {
- Activity a = parseActivity(owner, res, parser, flags, outError, false,
+ Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
owner.baseHardwareAccelerated);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
@@ -3905,7 +3921,8 @@ public class PackageParser {
parsedComponent = a.info;
} else if (tagName.equals("receiver")) {
- Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
+ Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
+ true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
@@ -3915,7 +3932,7 @@ public class PackageParser {
parsedComponent = a.info;
} else if (tagName.equals("service")) {
- Service s = parseService(owner, res, parser, flags, outError);
+ Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
@@ -3925,7 +3942,7 @@ public class PackageParser {
parsedComponent = s.info;
} else if (tagName.equals("provider")) {
- Provider p = parseProvider(owner, res, parser, flags, outError);
+ Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
if (p == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
@@ -3935,7 +3952,7 @@ public class PackageParser {
parsedComponent = p.info;
} else if (tagName.equals("activity-alias")) {
- Activity a = parseActivityAlias(owner, res, parser, flags, outError);
+ Activity a = parseActivityAlias(owner, res, parser, flags, outError, cachedArgs);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
@@ -4081,13 +4098,13 @@ public class PackageParser {
}
private Activity parseActivity(Package owner, Resources res,
- XmlResourceParser parser, int flags, String[] outError,
+ XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
boolean receiver, boolean hardwareAccelerated)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
- if (mParseActivityArgs == null) {
- mParseActivityArgs = new ParseComponentArgs(owner, outError,
+ if (cachedArgs.mActivityArgs == null) {
+ cachedArgs.mActivityArgs = new ParseComponentArgs(owner, outError,
R.styleable.AndroidManifestActivity_name,
R.styleable.AndroidManifestActivity_label,
R.styleable.AndroidManifestActivity_icon,
@@ -4100,11 +4117,11 @@ public class PackageParser {
R.styleable.AndroidManifestActivity_enabled);
}
- mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
- mParseActivityArgs.sa = sa;
- mParseActivityArgs.flags = flags;
+ cachedArgs.mActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
+ cachedArgs.mActivityArgs.sa = sa;
+ cachedArgs.mActivityArgs.flags = flags;
- Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
+ Activity a = new Activity(cachedArgs.mActivityArgs, new ActivityInfo());
if (outError[0] != null) {
sa.recycle();
return null;
@@ -4576,7 +4593,8 @@ public class PackageParser {
}
private Activity parseActivityAlias(Package owner, Resources res,
- XmlResourceParser parser, int flags, String[] outError)
+ XmlResourceParser parser, int flags, String[] outError,
+ CachedComponentArgs cachedArgs)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestActivityAlias);
@@ -4597,8 +4615,8 @@ public class PackageParser {
return null;
}
- if (mParseActivityAliasArgs == null) {
- mParseActivityAliasArgs = new ParseComponentArgs(owner, outError,
+ if (cachedArgs.mActivityAliasArgs == null) {
+ cachedArgs.mActivityAliasArgs = new ParseComponentArgs(owner, outError,
com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
@@ -4609,11 +4627,11 @@ public class PackageParser {
0,
com.android.internal.R.styleable.AndroidManifestActivityAlias_description,
com.android.internal.R.styleable.AndroidManifestActivityAlias_enabled);
- mParseActivityAliasArgs.tag = "<activity-alias>";
+ cachedArgs.mActivityAliasArgs.tag = "<activity-alias>";
}
- mParseActivityAliasArgs.sa = sa;
- mParseActivityAliasArgs.flags = flags;
+ cachedArgs.mActivityAliasArgs.sa = sa;
+ cachedArgs.mActivityAliasArgs.flags = flags;
Activity target = null;
@@ -4660,7 +4678,7 @@ public class PackageParser {
info.maxAspectRatio = target.info.maxAspectRatio;
info.encryptionAware = info.directBootAware = target.info.directBootAware;
- Activity a = new Activity(mParseActivityAliasArgs, info);
+ Activity a = new Activity(cachedArgs.mActivityAliasArgs, info);
if (outError[0] != null) {
sa.recycle();
return null;
@@ -4766,13 +4784,14 @@ public class PackageParser {
}
private Provider parseProvider(Package owner, Resources res,
- XmlResourceParser parser, int flags, String[] outError)
+ XmlResourceParser parser, int flags, String[] outError,
+ CachedComponentArgs cachedArgs)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestProvider);
- if (mParseProviderArgs == null) {
- mParseProviderArgs = new ParseComponentArgs(owner, outError,
+ if (cachedArgs.mProviderArgs == null) {
+ cachedArgs.mProviderArgs = new ParseComponentArgs(owner, outError,
com.android.internal.R.styleable.AndroidManifestProvider_name,
com.android.internal.R.styleable.AndroidManifestProvider_label,
com.android.internal.R.styleable.AndroidManifestProvider_icon,
@@ -4783,13 +4802,13 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestProvider_process,
com.android.internal.R.styleable.AndroidManifestProvider_description,
com.android.internal.R.styleable.AndroidManifestProvider_enabled);
- mParseProviderArgs.tag = "<provider>";
+ cachedArgs.mProviderArgs.tag = "<provider>";
}
- mParseProviderArgs.sa = sa;
- mParseProviderArgs.flags = flags;
+ cachedArgs.mProviderArgs.sa = sa;
+ cachedArgs.mProviderArgs.flags = flags;
- Provider p = new Provider(mParseProviderArgs, new ProviderInfo());
+ Provider p = new Provider(cachedArgs.mProviderArgs, new ProviderInfo());
if (outError[0] != null) {
sa.recycle();
return null;
@@ -5120,13 +5139,14 @@ public class PackageParser {
}
private Service parseService(Package owner, Resources res,
- XmlResourceParser parser, int flags, String[] outError)
+ XmlResourceParser parser, int flags, String[] outError,
+ CachedComponentArgs cachedArgs)
throws XmlPullParserException, IOException {
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestService);
- if (mParseServiceArgs == null) {
- mParseServiceArgs = new ParseComponentArgs(owner, outError,
+ if (cachedArgs.mServiceArgs == null) {
+ cachedArgs.mServiceArgs = new ParseComponentArgs(owner, outError,
com.android.internal.R.styleable.AndroidManifestService_name,
com.android.internal.R.styleable.AndroidManifestService_label,
com.android.internal.R.styleable.AndroidManifestService_icon,
@@ -5137,13 +5157,13 @@ public class PackageParser {
com.android.internal.R.styleable.AndroidManifestService_process,
com.android.internal.R.styleable.AndroidManifestService_description,
com.android.internal.R.styleable.AndroidManifestService_enabled);
- mParseServiceArgs.tag = "<service>";
+ cachedArgs.mServiceArgs.tag = "<service>";
}
- mParseServiceArgs.sa = sa;
- mParseServiceArgs.flags = flags;
+ cachedArgs.mServiceArgs.sa = sa;
+ cachedArgs.mServiceArgs.flags = flags;
- Service s = new Service(mParseServiceArgs, new ServiceInfo());
+ Service s = new Service(cachedArgs.mServiceArgs, new ServiceInfo());
if (outError[0] != null) {
sa.recycle();
return null;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 784ed7a25a47..4e70f4b12a5e 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3973,6 +3973,15 @@ public final class Settings {
};
/**
+ * Keys we no longer back up under the current schema, but want to continue to
+ * process when restoring historical backup datasets.
+ *
+ * @hide
+ */
+ public static final String[] LEGACY_RESTORE_SETTINGS = {
+ };
+
+ /**
* These are all public system settings
*
* @hide
@@ -7100,6 +7109,10 @@ public final class Settings {
NOTIFICATION_BADGING
};
+ /** @hide */
+ public static final String[] LEGACY_RESTORE_SETTINGS = {
+ };
+
/**
* These entries are considered common between the personal and the managed profile,
* since the managed profile doesn't get to change them.
@@ -10103,6 +10116,10 @@ public final class Settings {
BLUETOOTH_ON
};
+ /** @hide */
+ public static final String[] LEGACY_RESTORE_SETTINGS = {
+ };
+
private static final ContentProviderHolder sProviderHolder =
new ContentProviderHolder(CONTENT_URI);
diff --git a/core/java/android/text/InputFilter.java b/core/java/android/text/InputFilter.java
index bff09a20e595..d773158ed0cb 100644
--- a/core/java/android/text/InputFilter.java
+++ b/core/java/android/text/InputFilter.java
@@ -16,6 +16,10 @@
package android.text;
+import android.annotation.Nullable;
+
+import java.util.Locale;
+
/**
* InputFilters can be attached to {@link Editable}s to constrain the
* changes that can be made to them.
@@ -33,40 +37,122 @@ public interface InputFilter
* as this is what happens when you delete text. Also beware that
* you should not attempt to make any changes to <code>dest</code>
* from this method; you may only examine it for context.
- *
+ *
* Note: If <var>source</var> is an instance of {@link Spanned} or
- * {@link Spannable}, the span objects in the <var>source</var> should be
- * copied into the filtered result (i.e. the non-null return value).
- * {@link TextUtils#copySpansFrom} can be used for convenience.
+ * {@link Spannable}, the span objects in the <var>source</var> should be
+ * copied into the filtered result (i.e. the non-null return value).
+ * {@link TextUtils#copySpansFrom} can be used for convenience if the
+ * span boundary indices would be remaining identical relative to the source.
*/
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend);
/**
- * This filter will capitalize all the lower case letters that are added
- * through edits.
+ * This filter will capitalize all the lowercase and titlecase letters that are added
+ * through edits. (Note that if there are no lowercase or titlecase letters in the input, the
+ * text would not be transformed, even if the result of capitalization of the string is
+ * different from the string.)
*/
public static class AllCaps implements InputFilter {
+ private final Locale mLocale;
+
+ public AllCaps() {
+ mLocale = null;
+ }
+
+ /**
+ * Constructs a locale-specific AllCaps filter, to make sure capitalization rules of that
+ * locale are used for transforming the sequence.
+ */
+ public AllCaps(@Nullable Locale locale) {
+ mLocale = locale;
+ }
+
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
- for (int i = start; i < end; i++) {
- if (Character.isLowerCase(source.charAt(i))) {
- char[] v = new char[end - start];
- TextUtils.getChars(source, start, end, v, 0);
- String s = new String(v).toUpperCase();
-
- if (source instanceof Spanned) {
- SpannableString sp = new SpannableString(s);
- TextUtils.copySpansFrom((Spanned) source,
- start, end, null, sp, 0);
- return sp;
- } else {
- return s;
- }
+ final CharSequence wrapper = new CharSequenceWrapper(source, start, end);
+
+ boolean lowerOrTitleFound = false;
+ final int length = end - start;
+ for (int i = 0, cp; i < length; i += Character.charCount(cp)) {
+ // We access 'wrapper' instead of 'source' to make sure no code unit beyond 'end' is
+ // ever accessed.
+ cp = Character.codePointAt(wrapper, i);
+ if (Character.isLowerCase(cp) || Character.isTitleCase(cp)) {
+ lowerOrTitleFound = true;
+ break;
}
}
+ if (!lowerOrTitleFound) {
+ return null; // keep original
+ }
+
+ final boolean copySpans = source instanceof Spanned;
+ final CharSequence upper = TextUtils.toUpperCase(mLocale, wrapper, copySpans);
+ if (upper == wrapper) {
+ // Nothing was changed in the uppercasing operation. This is weird, since
+ // we had found at least one lowercase or titlecase character. But we can't
+ // do anything better than keeping the original in this case.
+ return null; // keep original
+ }
+ // Return a SpannableString or String for backward compatibility.
+ return copySpans ? new SpannableString(upper) : upper.toString();
+ }
+
+ private static class CharSequenceWrapper implements CharSequence, Spanned {
+ private final CharSequence mSource;
+ private final int mStart, mEnd;
+ private final int mLength;
+
+ CharSequenceWrapper(CharSequence source, int start, int end) {
+ mSource = source;
+ mStart = start;
+ mEnd = end;
+ mLength = end - start;
+ }
- return null; // keep original
+ public int length() {
+ return mLength;
+ }
+
+ public char charAt(int index) {
+ if (index < 0 || index >= mLength) {
+ throw new IndexOutOfBoundsException();
+ }
+ return mSource.charAt(mStart + index);
+ }
+
+ public CharSequence subSequence(int start, int end) {
+ if (start < 0 || end < 0 || end > mLength || start > end) {
+ throw new IndexOutOfBoundsException();
+ }
+ return new CharSequenceWrapper(mSource, mStart + start, mStart + end);
+ }
+
+ public String toString() {
+ return mSource.subSequence(mStart, mEnd).toString();
+ }
+
+ public <T> T[] getSpans(int start, int end, Class<T> type) {
+ return ((Spanned) mSource).getSpans(mStart + start, mStart + end, type);
+ }
+
+ public int getSpanStart(Object tag) {
+ return ((Spanned) mSource).getSpanStart(tag) - mStart;
+ }
+
+ public int getSpanEnd(Object tag) {
+ return ((Spanned) mSource).getSpanEnd(tag) - mStart;
+ }
+
+ public int getSpanFlags(Object tag) {
+ return ((Spanned) mSource).getSpanFlags(tag);
+ }
+
+ public int nextSpanTransition(int start, int limit, Class type) {
+ return ((Spanned) mSource).nextSpanTransition(mStart + start, mStart + limit, type)
+ - mStart;
+ }
}
}
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index e4ed62a1ead9..1aaf73e6e12c 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -827,7 +827,9 @@ class TextLine {
underlineXLeft, underlineXRight, y);
}
if (info.isUnderlineText) {
- drawUnderline(wp, c, wp.getColor(), ((Paint) wp).getUnderlineThickness(),
+ final float thickness =
+ Math.max(((Paint) wp).getUnderlineThickness(), 1.0f);
+ drawUnderline(wp, c, wp.getColor(), thickness,
underlineXLeft, underlineXRight, y);
}
}
@@ -986,7 +988,17 @@ class TextLine {
return 0f;
}
+ final boolean needsSpanMeasurement;
if (mSpanned == null) {
+ needsSpanMeasurement = false;
+ } else {
+ mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit);
+ mCharacterStyleSpanSet.init(mSpanned, mStart + start, mStart + limit);
+ needsSpanMeasurement = mMetricAffectingSpanSpanSet.numberOfSpans != 0
+ || mCharacterStyleSpanSet.numberOfSpans != 0;
+ }
+
+ if (!needsSpanMeasurement) {
final TextPaint wp = mWorkPaint;
wp.set(mPaint);
wp.setHyphenEdit(adjustHyphenEdit(start, limit, wp.getHyphenEdit()));
@@ -994,9 +1006,6 @@ class TextLine {
y, bottom, fmi, needWidth, measureLimit, null);
}
- mMetricAffectingSpanSpanSet.init(mSpanned, mStart + start, mStart + limit);
- mCharacterStyleSpanSet.init(mSpanned, mStart + start, mStart + limit);
-
// Shaping needs to take into account context up to metric boundaries,
// but rendering needs to take into account character style boundaries.
// So we iterate through metric runs to get metric bounds,
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 3baadd4c64c5..440c88e8cabb 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -23,6 +23,8 @@ import android.annotation.PluralsRes;
import android.content.Context;
import android.content.res.Resources;
import android.icu.lang.UCharacter;
+import android.icu.text.CaseMap;
+import android.icu.text.Edits;
import android.icu.util.ULocale;
import android.os.Parcel;
import android.os.Parcelable;
@@ -1072,6 +1074,75 @@ public class TextUtils {
}
}
+ /**
+ * Transforms a CharSequences to uppercase, copying the sources spans and keeping them spans as
+ * much as possible close to their relative original places. In the case the the uppercase
+ * string is identical to the sources, the source itself is returned instead of being copied.
+ *
+ * If copySpans is set, source must be an instance of Spanned.
+ *
+ * {@hide}
+ */
+ @NonNull
+ public static CharSequence toUpperCase(@Nullable Locale locale, @NonNull CharSequence source,
+ boolean copySpans) {
+ final Edits edits = new Edits();
+ if (!copySpans) { // No spans. Just uppercase the characters.
+ final StringBuilder result = CaseMap.toUpper().apply(
+ locale, source, new StringBuilder(), edits);
+ return edits.hasChanges() ? result : source;
+ }
+
+ final SpannableStringBuilder result = CaseMap.toUpper().apply(
+ locale, source, new SpannableStringBuilder(), edits);
+ if (!edits.hasChanges()) {
+ // No changes happened while capitalizing. We can return the source as it was.
+ return source;
+ }
+
+ final Edits.Iterator iterator = edits.getFineIterator();
+ final int sourceLength = source.length();
+ final Spanned spanned = (Spanned) source;
+ final Object[] spans = spanned.getSpans(0, sourceLength, Object.class);
+ for (Object span : spans) {
+ final int sourceStart = spanned.getSpanStart(span);
+ final int sourceEnd = spanned.getSpanEnd(span);
+ final int flags = spanned.getSpanFlags(span);
+ // Make sure the indices are not at the end of the string, since in that case
+ // iterator.findSourceIndex() would fail.
+ final int destStart = sourceStart == sourceLength ? result.length() :
+ toUpperMapToDest(iterator, sourceStart);
+ final int destEnd = sourceEnd == sourceLength ? result.length() :
+ toUpperMapToDest(iterator, sourceEnd);
+ result.setSpan(span, destStart, destEnd, flags);
+ }
+ return result;
+ }
+
+ // helper method for toUpperCase()
+ private static int toUpperMapToDest(Edits.Iterator iterator, int sourceIndex) {
+ // Guaranteed to succeed if sourceIndex < source.length().
+ iterator.findSourceIndex(sourceIndex);
+ if (sourceIndex == iterator.sourceIndex()) {
+ return iterator.destinationIndex();
+ }
+ // We handle the situation differently depending on if we are in the changed slice or an
+ // unchanged one: In an unchanged slice, we can find the exact location the span
+ // boundary was before and map there.
+ //
+ // But in a changed slice, we need to treat the whole destination slice as an atomic unit.
+ // We adjust the span boundary to the end of that slice to reduce of the chance of adjacent
+ // spans in the source overlapping in the result. (The choice for the end vs the beginning
+ // is somewhat arbitrary, but was taken because we except to see slightly more spans only
+ // affecting a base character compared to spans only affecting a combining character.)
+ if (iterator.hasChange()) {
+ return iterator.destinationIndex() + iterator.newLength();
+ } else {
+ // Move the index 1:1 along with this unchanged piece of text.
+ return iterator.destinationIndex() + (sourceIndex - iterator.sourceIndex());
+ }
+ }
+
public enum TruncateAt {
START,
MIDDLE,
diff --git a/core/java/android/text/method/AllCapsTransformationMethod.java b/core/java/android/text/method/AllCapsTransformationMethod.java
index 15f40d5121ef..c807e7da4f1b 100644
--- a/core/java/android/text/method/AllCapsTransformationMethod.java
+++ b/core/java/android/text/method/AllCapsTransformationMethod.java
@@ -15,12 +15,12 @@
*/
package android.text.method;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
-import android.icu.text.CaseMap;
-import android.icu.text.Edits;
-import android.text.SpannableStringBuilder;
import android.text.Spanned;
+import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
@@ -38,12 +38,12 @@ public class AllCapsTransformationMethod implements TransformationMethod2 {
private boolean mEnabled;
private Locale mLocale;
- public AllCapsTransformationMethod(Context context) {
+ public AllCapsTransformationMethod(@NonNull Context context) {
mLocale = context.getResources().getConfiguration().getLocales().get(0);
}
@Override
- public CharSequence getTransformation(CharSequence source, View view) {
+ public CharSequence getTransformation(@Nullable CharSequence source, View view) {
if (!mEnabled) {
Log.w(TAG, "Caller did not enable length changes; not transforming text");
return source;
@@ -60,61 +60,8 @@ public class AllCapsTransformationMethod implements TransformationMethod2 {
if (locale == null) {
locale = mLocale;
}
-
- if (!(source instanceof Spanned)) { // No spans
- return CaseMap.toUpper().apply(
- locale, source, new StringBuilder(),
- null /* we don't need the edits */);
- }
-
- final Edits edits = new Edits();
- final SpannableStringBuilder result = CaseMap.toUpper().apply(
- locale, source, new SpannableStringBuilder(), edits);
- if (!edits.hasChanges()) {
- // No changes happened while capitalizing. We can return the source as it was.
- return source;
- }
-
- final Edits.Iterator iterator = edits.getFineIterator();
- final Spanned spanned = (Spanned) source;
- final int sourceLength = source.length();
- final Object[] spans = spanned.getSpans(0, sourceLength, Object.class);
- for (Object span : spans) {
- final int sourceStart = spanned.getSpanStart(span);
- final int sourceEnd = spanned.getSpanEnd(span);
- final int flags = spanned.getSpanFlags(span);
- // Make sure the indexes are not at the end of the string, since in that case
- // iterator.findSourceIndex() would fail.
- final int destStart = sourceStart == sourceLength ? result.length() :
- mapToDest(iterator, sourceStart);
- final int destEnd = sourceEnd == sourceLength ? result.length() :
- mapToDest(iterator, sourceEnd);
- result.setSpan(span, destStart, destEnd, flags);
- }
- return result;
- }
-
- private static int mapToDest(Edits.Iterator iterator, int sourceIndex) {
- // Guaranteed to succeed if sourceIndex < source.length().
- iterator.findSourceIndex(sourceIndex);
- if (sourceIndex == iterator.sourceIndex()) {
- return iterator.destinationIndex();
- }
- // We handle the situation differently depending on if we are in the changed slice or an
- // unchanged one: In an unchanged slice, we can find the exact location the span
- // boundary was before and map there.
- //
- // But in a changed slice, we need to treat the whole destination slice as an atomic unit.
- // We adjust the span boundary to the end of that slice to reduce of the chance of adjacent
- // spans in the source overlapping in the result. (The choice for the end vs the beginning
- // is somewhat arbitrary, but was taken because we except to see slightly more spans only
- // affecting a base character compared to spans only affecting a combining character.)
- if (iterator.hasChange()) {
- return iterator.destinationIndex() + iterator.newLength();
- } else {
- // Move the index 1:1 along with this unchanged piece of text.
- return iterator.destinationIndex() + (sourceIndex - iterator.sourceIndex());
- }
+ final boolean copySpans = source instanceof Spanned;
+ return TextUtils.toUpperCase(locale, source, copySpans);
}
@Override
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index fa25a8f0c596..b93697398020 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -961,6 +961,30 @@ namespace PaintGlue {
return SkScalarToFloat(metrics.fDescent);
}
+ static jfloat getUnderlinePosition(jlong paintHandle, jlong typefaceHandle) {
+ Paint::FontMetrics metrics;
+ getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+ SkScalar position;
+ if (metrics.hasUnderlinePosition(&position)) {
+ return SkScalarToFloat(position);
+ } else {
+ const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize();
+ return SkScalarToFloat(Paint::kStdUnderline_Top * textSize);
+ }
+ }
+
+ static jfloat getUnderlineThickness(jlong paintHandle, jlong typefaceHandle) {
+ Paint::FontMetrics metrics;
+ getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+ SkScalar thickness;
+ if (metrics.hasUnderlineThickness(&thickness)) {
+ return SkScalarToFloat(thickness);
+ } else {
+ const SkScalar textSize = reinterpret_cast<Paint*>(paintHandle)->getTextSize();
+ return SkScalarToFloat(Paint::kStdUnderline_Thickness * textSize);
+ }
+ }
+
static void setShadowLayer(jlong paintHandle, jfloat radius,
jfloat dx, jfloat dy, jint color) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
@@ -1072,6 +1096,8 @@ static const JNINativeMethod methods[] = {
{"nSetHyphenEdit", "(JI)V", (void*) PaintGlue::setHyphenEdit},
{"nAscent","(JJ)F", (void*) PaintGlue::ascent},
{"nDescent","(JJ)F", (void*) PaintGlue::descent},
+ {"nGetUnderlinePosition","(JJ)F", (void*) PaintGlue::getUnderlinePosition},
+ {"nGetUnderlineThickness","(JJ)F", (void*) PaintGlue::getUnderlineThickness},
{"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer},
{"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer}
};
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 004ecfcd12cf..958592b581a7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2616,6 +2616,12 @@
<permission android:name="android.permission.TV_VIRTUAL_REMOTE_CONTROLLER"
android:protectionLevel="signature|privileged" />
+ <!-- Allows an application to change HDMI CEC active source.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an application to modify parental controls
<p>Not for use by third-party applications.
@hide -->
diff --git a/core/tests/coretests/apks/install_multi_package/Android.mk b/core/tests/coretests/apks/install_multi_package/Android.mk
new file mode 100644
index 000000000000..2813dad2339a
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := install_multi_package
+
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+#include $(BUILD_PACKAGE)
+
diff --git a/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml b/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml
new file mode 100644
index 000000000000..5164cae9e5c0
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/AndroidManifest.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.install_multi_package">
+
+<!--
+ This manifest is has child packages with components.
+-->
+
+ <uses-feature
+ android:name="com.android.frameworks.coretests.nonexistent" />
+ <uses-configuration
+ android:reqFiveWayNav="false" />
+
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.frameworks.coretests"
+ android:label="Frameworks Core Tests" />
+
+ <permission
+ android:label="test permission"
+ android:name="test_permission"
+ android:protectionLevel="normal" />
+ <uses-permission android:name="android.permission.INTERNET" />
+
+<!--
+ NOTE: This declares a child package, application, then another child
+ package, to test potential bugs that are order-dependent. Also, each
+ one varies the order.
+-->
+
+ <package package="com.android.frameworks.coretests.install_multi_package.first_child">
+ <uses-permission android:name="android.permission.NFC" />
+ <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. -->
+ <permission
+ android:label="test permission"
+ android:name="first_child_permission"
+ android:protectionLevel="signature" />
+ <application
+ android:hasCode="true">
+ <activity
+ android:name="com.android.frameworks.coretests.FirstChildTestActivity">
+ </activity>
+ <provider
+ android:name="com.android.frameworks.coretests.FirstChildTestProvider"
+ android:authorities="com.android.frameworks.coretests.testprovider" />
+ <receiver
+ android:name="com.android.frameworks.coretests.FirstChildTestReceiver" />
+ <service
+ android:name="com.android.frameworks.coretests.FirstChildTestService" />
+ </application>
+ </package>
+
+ <application
+ android:hasCode="true">
+ <service
+ android:name="com.android.frameworks.coretests.TestService" />
+ <activity
+ android:name="com.android.frameworks.coretests.TestActivity">
+ </activity>
+ <provider
+ android:name="com.android.frameworks.coretests.TestProvider"
+ android:authorities="com.android.frameworks.coretests.testprovider" />
+ <receiver
+ android:name="com.android.frameworks.coretests.TestReceiver" />
+ </application>
+
+ <package package="com.android.frameworks.coretests.blah.second_child">
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission-sdk-23 android:name="android.permission.READ_CONTACTS" />
+ <!-- NOTE: A declared permission is ignored since the tag is not whitelisted. -->
+ <permission
+ android:label="test permission"
+ android:name="second_child_permission"
+ android:protectionLevel="dangerous" />
+ <application
+ android:hasCode="true">
+ <receiver
+ android:name="com.android.frameworks.coretests.SecondChildTestReceiver" />
+ <service
+ android:name="com.android.frameworks.coretests.SecondChildTestService" />
+ <activity
+ android:name="com.android.frameworks.coretests.SecondChildTestActivity">
+ </activity>
+ <provider
+ android:name="com.android.frameworks.coretests.SecondChildTestProvider"
+ android:authorities="com.android.frameworks.coretests.testprovider" />
+ </application>
+ </package>
+</manifest>
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java
new file mode 100644
index 000000000000..57afcb0e1a0d
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestActivity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.app.Activity;
+
+public class FirstChildTestActivity extends Activity {
+
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java
new file mode 100644
index 000000000000..2816865b2f1f
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class FirstChildTestProvider extends ContentProvider {
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java
new file mode 100644
index 000000000000..ffe84b73dd37
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestReceiver.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class FirstChildTestReceiver extends ContentProvider {
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java
new file mode 100644
index 000000000000..faa6e9cff2b2
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/FirstChildTestService.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class FirstChildTestService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java
new file mode 100644
index 000000000000..e89f26489959
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestActivity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.app.Activity;
+
+public class SecondChildTestActivity extends Activity {
+
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java
new file mode 100644
index 000000000000..2bd40a5df94d
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class SecondChildTestProvider extends ContentProvider {
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java
new file mode 100644
index 000000000000..a6c4ddc90c6a
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestReceiver.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class SecondChildTestReceiver extends ContentProvider {
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java
new file mode 100644
index 000000000000..1e721aa8ae5b
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/SecondChildTestService.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class SecondChildTestService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java
new file mode 100644
index 000000000000..10d0551a3a6f
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestActivity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.app.Activity;
+
+public class TestActivity extends Activity {
+
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java
new file mode 100644
index 000000000000..59f9f10c6efe
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class TestProvider extends ContentProvider {
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java
new file mode 100644
index 000000000000..21f6263a38bc
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestReceiver.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class TestReceiver extends ContentProvider {
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java
new file mode 100644
index 000000000000..b330e75308f9
--- /dev/null
+++ b/core/tests/coretests/apks/install_multi_package/src/com/android/frameworks/coretests/TestService.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 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.frameworks.coretests;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class TestService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/core/tests/coretests/assets/fonts/underlineTestFont.ttf b/core/tests/coretests/assets/fonts/underlineTestFont.ttf
new file mode 100644
index 000000000000..a46a38e0b397
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/underlineTestFont.ttf
Binary files differ
diff --git a/core/tests/coretests/assets/fonts/underlineTestFont.ttx b/core/tests/coretests/assets/fonts/underlineTestFont.ttx
new file mode 100644
index 000000000000..d7376b06703e
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/underlineTestFont.ttx
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.9">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="a" width="500" lsb="93"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_4 platformID="3" platEncID="10" language="0">
+ <map code="0x61" name="a"/><!-- LATIN SMALL LETTER A -->
+ </cmap_format_4>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="a"/><!-- contains no outline data -->
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-200"/>
+ <underlineThickness value="300"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index b9bd193ad48c..73c153f2754a 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -19,14 +19,27 @@ package android.content.pm;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import android.content.Context;
+import android.content.pm.PackageParser.Component;
+import android.content.pm.PackageParser.Package;
+import android.content.pm.PackageParser.Permission;
import android.os.Build;
+import android.os.FileUtils;
+import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import com.android.frameworks.coretests.R;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.File;
+import java.io.InputStream;
+import java.util.Arrays;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class PackageParserTest {
@@ -257,4 +270,117 @@ public class PackageParserTest {
PackageParser.getActivityConfigChanges(configChanges, recreateOnConfigChanges);
assertEquals(0x0083, finalConfigChanges); // Should be 10000011.
}
+
+ /**
+ * Attempts to parse a package.
+ *
+ * APKs are put into coretests/apks/packageparser_*.
+ *
+ * @param apkName temporary file name to store apk extracted from resources
+ * @param apkResourceId identifier of the apk as a resource
+ */
+ Package parsePackage(String apkFileName, int apkResourceId) throws Exception {
+ // Copy the resource to a file.
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ File outFile = new File(context.getFilesDir(), apkFileName);
+ try {
+ InputStream is = context.getResources().openRawResource(apkResourceId);
+ assertTrue(FileUtils.copyToFile(is, outFile));
+ return new PackageParser().parsePackage(outFile, 0 /* flags */);
+ } finally {
+ outFile.delete();
+ }
+ }
+
+ /**
+ * Asserts basic properties about a component.
+ */
+ private void assertComponent(String className, String packageName, int numIntents,
+ Component<?> component) {
+ assertEquals(className, component.className);
+ assertEquals(packageName, component.owner.packageName);
+ assertEquals(numIntents, component.intents.size());
+ }
+
+ /**
+ * Asserts four regularly-named components of each type: one Activity, one Service, one
+ * Provider, and one Receiver.
+ * @param template templated string with %s subbed with Activity, Service, Provider, Receiver
+ */
+ private void assertOneComponentOfEachType(String template, Package p) {
+ String packageName = p.packageName;
+
+ assertEquals(1, p.activities.size());
+ assertComponent(String.format(template, "Activity"),
+ packageName, 0 /* intents */, p.activities.get(0));
+ assertEquals(1, p.services.size());
+ assertComponent(String.format(template, "Service"),
+ packageName, 0 /* intents */, p.services.get(0));
+ assertEquals(1, p.providers.size());
+ assertComponent(String.format(template, "Provider"),
+ packageName, 0 /* intents */, p.providers.get(0));
+ assertEquals(1, p.receivers.size());
+ assertComponent(String.format(template, "Receiver"),
+ packageName, 0 /* intents */, p.receivers.get(0));
+ }
+
+ private void assertPermission(String name, String packageName, int protectionLevel,
+ Permission permission) {
+ assertEquals(packageName, permission.owner.packageName);
+ assertEquals(name, permission.info.name);
+ assertEquals(protectionLevel, permission.info.protectionLevel);
+ }
+
+ @Test
+ public void testPackageWithComponents() throws Exception {
+ Package p = parsePackage(
+ "install_complete_package_info.apk", R.raw.install_complete_package_info);
+ String packageName = "com.android.frameworks.coretests.install_complete_package_info";
+
+ assertEquals(packageName, p.packageName);
+ assertEquals(1, p.permissions.size());
+ assertPermission(
+ "com.android.frameworks.coretests.install_complete_package_info.test_permission",
+ packageName, PermissionInfo.PROTECTION_NORMAL, p.permissions.get(0));
+
+ assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p);
+ }
+
+ @Test
+ public void testMultiPackageComponents() throws Exception {
+ String parentName = "com.android.frameworks.coretests.install_multi_package";
+ String firstChildName =
+ "com.android.frameworks.coretests.install_multi_package.first_child";
+ String secondChildName = // NOTE: intentionally inconsistent!
+ "com.android.frameworks.coretests.blah.second_child";
+
+ Package parent = parsePackage("install_multi_package.apk", R.raw.install_multi_package);
+ assertEquals(parentName, parent.packageName);
+ assertEquals(2, parent.childPackages.size());
+ assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", parent);
+ assertEquals(1, parent.permissions.size());
+ assertPermission(parentName + ".test_permission", parentName,
+ PermissionInfo.PROTECTION_NORMAL, parent.permissions.get(0));
+ assertEquals(Arrays.asList("android.permission.INTERNET"),
+ parent.requestedPermissions);
+
+ Package firstChild = parent.childPackages.get(0);
+ assertEquals(firstChildName, firstChild.packageName);
+ assertOneComponentOfEachType(
+ "com.android.frameworks.coretests.FirstChildTest%s", firstChild);
+ assertEquals(0, firstChild.permissions.size()); // Child APKs cannot declare permissions.
+ assertEquals(Arrays.asList("android.permission.NFC"),
+ firstChild.requestedPermissions);
+
+ Package secondChild = parent.childPackages.get(1);
+ assertEquals(secondChildName, secondChild.packageName);
+ assertOneComponentOfEachType(
+ "com.android.frameworks.coretests.SecondChildTest%s", secondChild);
+ assertEquals(0, secondChild.permissions.size()); // Child APKs cannot declare permissions.
+ assertEquals(
+ Arrays.asList(
+ "android.permission.ACCESS_NETWORK_STATE",
+ "android.permission.READ_CONTACTS"),
+ secondChild.requestedPermissions);
+ }
}
diff --git a/core/tests/coretests/src/android/graphics/PaintTest.java b/core/tests/coretests/src/android/graphics/PaintTest.java
index 5811ca0fd266..2f28606790cf 100644
--- a/core/tests/coretests/src/android/graphics/PaintTest.java
+++ b/core/tests/coretests/src/android/graphics/PaintTest.java
@@ -16,6 +16,8 @@
package android.graphics;
+import static org.junit.Assert.assertNotEquals;
+
import android.graphics.Paint;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -148,7 +150,10 @@ public class PaintTest extends InstrumentationTestCase {
" U+" + Integer.toHexString(vs) + ")";
final String testString =
codePointsToString(new int[] {testCase.mBaseCodepoint, vs});
- if (testCase.mVariationSelectors.contains(vs)) {
+ if (vs == 0xFE0E // U+FE0E is the text presentation emoji. hasGlyph is expected to
+ // return true for that variation selector if the font has the base
+ // glyph.
+ || testCase.mVariationSelectors.contains(vs)) {
assertTrue(signature + " is expected to be true", p.hasGlyph(testString));
} else {
assertFalse(signature + " is expected to be false", p.hasGlyph(testString));
@@ -365,4 +370,31 @@ public class PaintTest extends InstrumentationTestCase {
p.setWordSpacing(-2.0f);
assertEquals(-2.0f, p.getWordSpacing());
}
+
+ public void testGetUnderlinePositionAndThickness() {
+ final Typeface fontTypeface = Typeface.createFromAsset(
+ getInstrumentation().getContext().getAssets(), "fonts/underlineTestFont.ttf");
+ final Paint p = new Paint();
+ final int textSize = 100;
+ p.setTextSize(textSize);
+
+ final float origPosition = p.getUnderlinePosition();
+ final float origThickness = p.getUnderlineThickness();
+
+ p.setTypeface(fontTypeface);
+ assertNotEquals(origPosition, p.getUnderlinePosition());
+ assertNotEquals(origThickness, p.getUnderlineThickness());
+
+ // -200 (underlinePosition in 'post' table, negative means below the baseline)
+ // ÷ 1000 (unitsPerEm in 'head' table)
+ // × 100 (text size)
+ // × -1 (negated, since we consider below the baseline positive)
+ // = 20
+ assertEquals(20.0f, p.getUnderlinePosition(), 0.5f);
+ // 300 (underlineThickness in 'post' table)
+ // ÷ 1000 (unitsPerEm in 'head' table)
+ // × 100 (text size)
+ // = 30
+ assertEquals(30.0f, p.getUnderlineThickness(), 0.5f);
+ }
}
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index 312c4fb4b23f..4cc648def549 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -20,26 +20,28 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import android.support.test.runner.AndroidJUnit4;
-import com.google.android.collect.Lists;
-
import android.os.Parcel;
import android.support.test.filters.LargeTest;
import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.test.MoreAsserts;
import android.text.style.StyleSpan;
import android.text.util.Rfc822Token;
import android.text.util.Rfc822Tokenizer;
import android.view.View;
+import com.google.android.collect.Lists;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-import org.junit.Test;
-import org.junit.runner.RunWith;
/**
* TextUtilsTest tests {@link TextUtils}.
@@ -580,4 +582,84 @@ public class TextUtilsTest {
assertEquals(View.LAYOUT_DIRECTION_RTL,
TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("tr-Arab")));
}
+
+ @Test
+ public void testToUpperCase() {
+ {
+ final CharSequence result = TextUtils.toUpperCase(null, "abc", false);
+ assertEquals(StringBuilder.class, result.getClass());
+ assertEquals("ABC", result.toString());
+ }
+ {
+ final SpannableString str = new SpannableString("abc");
+ Object span = new Object();
+ str.setSpan(span, 1, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+
+ final CharSequence result = TextUtils.toUpperCase(null, str, true /* copySpans */);
+ assertEquals(SpannableStringBuilder.class, result.getClass());
+ assertEquals("ABC", result.toString());
+ final Spanned spanned = (Spanned) result;
+ final Object[] resultSpans = spanned.getSpans(0, result.length(), Object.class);
+ assertEquals(1, resultSpans.length);
+ assertSame(span, resultSpans[0]);
+ assertEquals(1, spanned.getSpanStart(span));
+ assertEquals(2, spanned.getSpanEnd(span));
+ assertEquals(Spanned.SPAN_INCLUSIVE_INCLUSIVE, spanned.getSpanFlags(span));
+ }
+ {
+ final Locale turkish = new Locale("tr", "TR");
+ final CharSequence result = TextUtils.toUpperCase(turkish, "i", false);
+ assertEquals(StringBuilder.class, result.getClass());
+ assertEquals("İ", result.toString());
+ }
+ {
+ final String str = "ABC";
+ assertSame(str, TextUtils.toUpperCase(null, str, false));
+ }
+ {
+ final SpannableString str = new SpannableString("ABC");
+ str.setSpan(new Object(), 1, 2, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ assertSame(str, TextUtils.toUpperCase(null, str, true /* copySpans */));
+ }
+ }
+
+ // Copied from cts/tests/tests/widget/src/android/widget/cts/TextViewTest.java and modified
+ // for the TextUtils.toUpperCase method.
+ @Test
+ public void testToUpperCase_SpansArePreserved() {
+ final Locale greek = new Locale("el", "GR");
+ final String lowerString = "ι\u0301ριδα"; // ίριδα with first letter decomposed
+ final String upperString = "ΙΡΙΔΑ"; // uppercased
+ // expected lowercase to uppercase index map
+ final int[] indexMap = {0, 1, 1, 2, 3, 4, 5};
+ final int flags = Spanned.SPAN_INCLUSIVE_INCLUSIVE;
+
+ final Spannable source = new SpannableString(lowerString);
+ source.setSpan(new Object(), 0, 1, flags);
+ source.setSpan(new Object(), 1, 2, flags);
+ source.setSpan(new Object(), 2, 3, flags);
+ source.setSpan(new Object(), 3, 4, flags);
+ source.setSpan(new Object(), 4, 5, flags);
+ source.setSpan(new Object(), 5, 6, flags);
+ source.setSpan(new Object(), 0, 2, flags);
+ source.setSpan(new Object(), 1, 3, flags);
+ source.setSpan(new Object(), 2, 4, flags);
+ source.setSpan(new Object(), 0, 6, flags);
+ final Object[] sourceSpans = source.getSpans(0, source.length(), Object.class);
+
+ final CharSequence uppercase = TextUtils.toUpperCase(greek, source, true /* copySpans */);
+ assertEquals(SpannableStringBuilder.class, uppercase.getClass());
+ final Spanned result = (Spanned) uppercase;
+
+ assertEquals(upperString, result.toString());
+ final Object[] resultSpans = result.getSpans(0, result.length(), Object.class);
+ assertEquals(sourceSpans.length, resultSpans.length);
+ for (int i = 0; i < sourceSpans.length; i++) {
+ assertSame(sourceSpans[i], resultSpans[i]);
+ final Object span = sourceSpans[i];
+ assertEquals(indexMap[source.getSpanStart(span)], result.getSpanStart(span));
+ assertEquals(indexMap[source.getSpanEnd(span)], result.getSpanEnd(span));
+ assertEquals(source.getSpanFlags(span), result.getSpanFlags(span));
+ }
+ }
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index e1eb69a27e33..1fd56974783e 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -822,18 +822,14 @@ public class Paint {
* @hide
*/
public float getUnderlinePosition() {
- // kStdUnderline_Offset = 1/9, defined in SkTextFormatParams.h
- // TODO: replace with position from post and MVAR tables (b/62353930).
- return (1.0f / 9.0f) * getTextSize();
+ return nGetUnderlinePosition(mNativePaint, mNativeTypeface);
}
/**
* @hide
*/
public float getUnderlineThickness() {
- // kStdUnderline_Thickness = 1/18, defined in SkTextFormatParams.h
- // TODO: replace with thickness from post and MVAR tables (b/62353930).
- return (1.0f / 18.0f) * getTextSize();
+ return nGetUnderlineThickness(mNativePaint, mNativeTypeface);
}
/**
@@ -2997,5 +2993,9 @@ public class Paint {
@CriticalNative
private static native float nDescent(long paintPtr, long typefacePtr);
@CriticalNative
+ private static native float nGetUnderlinePosition(long paintPtr, long typefacePtr);
+ @CriticalNative
+ private static native float nGetUnderlineThickness(long paintPtr, long typefacePtr);
+ @CriticalNative
private static native void nSetTextSize(long paintPtr, float textSize);
}
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 679cb5021e27..4507c5018c26 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -46,23 +46,31 @@ void Canvas::drawTextDecorations(float x, float y, float length, const SkPaint&
flags = paint.getFlags();
}
if (flags & (SkPaint::kUnderlineText_ReserveFlag | SkPaint::kStrikeThruText_ReserveFlag)) {
- // Same values used by Skia
- const float kStdStrikeThru_Offset = (-6.0f / 21.0f);
- const float kStdUnderline_Offset = (1.0f / 9.0f);
- const float kStdUnderline_Thickness = (1.0f / 18.0f);
-
- SkScalar left = x;
- SkScalar right = x + length;
- float textSize = paint.getTextSize();
- float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f);
+
+ const SkScalar left = x;
+ const SkScalar right = x + length;
if (flags & SkPaint::kUnderlineText_ReserveFlag) {
- SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth;
- SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth;
+ Paint::FontMetrics metrics;
+ paint.getFontMetrics(&metrics);
+ SkScalar position;
+ if (!metrics.hasUnderlinePosition(&position)) {
+ position = paint.getTextSize() * Paint::kStdUnderline_Top;
+ }
+ SkScalar thickness;
+ if (!metrics.hasUnderlineThickness(&thickness)) {
+ thickness = paint.getTextSize() * Paint::kStdUnderline_Thickness;
+ }
+ const float strokeWidth = fmax(thickness, 1.0f);
+ const SkScalar top = y + position;
+ const SkScalar bottom = top + strokeWidth;
drawRect(left, top, right, bottom, paint);
}
if (flags & SkPaint::kStrikeThruText_ReserveFlag) {
- SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth;
- SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth;
+ const float textSize = paint.getTextSize();
+ const float position = textSize * Paint::kStdStrikeThru_Offset;
+ const float strokeWidth = fmax(textSize * Paint::kStdUnderline_Thickness, 1.0f);
+ const SkScalar top = y + position - 0.5f * strokeWidth;
+ const SkScalar bottom = y + position + 0.5f * strokeWidth;
drawRect(left, top, right, bottom, paint);
}
}
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index c9b5f0031a7b..4305025272b2 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -28,6 +28,15 @@ namespace android {
class ANDROID_API Paint : public SkPaint {
public:
+ // Default values for underlined and strikethrough text,
+ // as defined by Skia in SkTextFormatParams.h.
+ constexpr static float kStdStrikeThru_Offset = (-6.0f / 21.0f);
+ constexpr static float kStdUnderline_Offset = (1.0f / 9.0f);
+ constexpr static float kStdUnderline_Thickness = (1.0f / 18.0f);
+
+ constexpr static float kStdUnderline_Top =
+ kStdUnderline_Offset - 0.5f * kStdUnderline_Thickness;
+
Paint();
Paint(const Paint& paint);
Paint(const SkPaint& paint); // NOLINT(implicit)
diff --git a/lowpan/java/android/net/lowpan/LowpanBeaconInfo.java b/lowpan/java/android/net/lowpan/LowpanBeaconInfo.java
index b344527e4be5..e18abd5bf23f 100644
--- a/lowpan/java/android/net/lowpan/LowpanBeaconInfo.java
+++ b/lowpan/java/android/net/lowpan/LowpanBeaconInfo.java
@@ -26,7 +26,7 @@ import java.util.TreeSet;
*
* @hide
*/
-//@SystemApi
+// @SystemApi
public class LowpanBeaconInfo extends LowpanIdentity {
private int mRssi = UNKNOWN;
@@ -104,7 +104,7 @@ public class LowpanBeaconInfo extends LowpanIdentity {
}
public Collection<Integer> getFlags() {
- return mFlags.clone();
+ return (Collection<Integer>) mFlags.clone();
}
public boolean isFlagSet(int flag) {
diff --git a/lowpan/java/android/net/lowpan/LowpanChannelInfo.java b/lowpan/java/android/net/lowpan/LowpanChannelInfo.java
index 50afe6d3a4c0..621affee6d06 100644
--- a/lowpan/java/android/net/lowpan/LowpanChannelInfo.java
+++ b/lowpan/java/android/net/lowpan/LowpanChannelInfo.java
@@ -16,14 +16,12 @@
package android.net.lowpan;
-
/** Provides detailed information about a given channel. */
-//@SystemApi
+// @SystemApi
public class LowpanChannelInfo {
public static final int UNKNOWN_POWER = Integer.MAX_VALUE;
- //////////////////////////////////////////////////////////////////////////
// Instance Variables
private String mName = null;
@@ -33,7 +31,6 @@ public class LowpanChannelInfo {
private float mSpectrumBandwidth = 0.0f;
private int mMaxTransmitPower = UNKNOWN_POWER;
- //////////////////////////////////////////////////////////////////////////
// Public Getters and Setters
public String getName() {
diff --git a/lowpan/java/android/net/lowpan/LowpanCommissioningSession.java b/lowpan/java/android/net/lowpan/LowpanCommissioningSession.java
index 9cad00c3415a..1da085ddb294 100644
--- a/lowpan/java/android/net/lowpan/LowpanCommissioningSession.java
+++ b/lowpan/java/android/net/lowpan/LowpanCommissioningSession.java
@@ -30,7 +30,7 @@ import java.net.InetSocketAddress;
*
* @hide
*/
-//@SystemApi
+// @SystemApi
public abstract class LowpanCommissioningSession {
public LowpanCommissioningSession() {}
@@ -39,7 +39,7 @@ public abstract class LowpanCommissioningSession {
*
* @hide
*/
- //@SystemApi
+ // @SystemApi
public class Callback {
public void onReceiveFromCommissioner(@NonNull byte[] packet) {};
diff --git a/lowpan/java/android/net/lowpan/LowpanCredential.java b/lowpan/java/android/net/lowpan/LowpanCredential.java
index dea4d7888884..ca8602151515 100644
--- a/lowpan/java/android/net/lowpan/LowpanCredential.java
+++ b/lowpan/java/android/net/lowpan/LowpanCredential.java
@@ -16,7 +16,6 @@
package android.net.lowpan;
-
import java.util.Map;
/**
@@ -24,7 +23,7 @@ import java.util.Map;
*
* @hide
*/
-//@SystemApi
+// @SystemApi
public class LowpanCredential {
public static final int UNSPECIFIED_KEY_INDEX = 0;
@@ -84,8 +83,7 @@ public class LowpanCredential {
void addToMap(Map<String, Object> parameters) throws LowpanException {
if (isMasterKey()) {
LowpanProperties.KEY_NETWORK_MASTER_KEY.putInMap(parameters, getMasterKey());
- LowpanProperties.KEY_NETWORK_MASTER_KEY_INDEX.putInMap(
- parameters, getMasterKeyIndex());
+ LowpanProperties.KEY_NETWORK_MASTER_KEY_INDEX.putInMap(parameters, getMasterKeyIndex());
} else {
throw new LowpanException("Unsupported Network Credential");
}
diff --git a/lowpan/java/android/net/lowpan/LowpanEnergyScanResult.java b/lowpan/java/android/net/lowpan/LowpanEnergyScanResult.java
index c680687d0e09..91ed19c488eb 100644
--- a/lowpan/java/android/net/lowpan/LowpanEnergyScanResult.java
+++ b/lowpan/java/android/net/lowpan/LowpanEnergyScanResult.java
@@ -16,13 +16,12 @@
package android.net.lowpan;
-
/**
* Describes the result from one channel of an energy scan.
*
* @hide
*/
-//@SystemApi
+// @SystemApi
public class LowpanEnergyScanResult {
public static final int UNKNOWN = Integer.MAX_VALUE;
diff --git a/lowpan/java/android/net/lowpan/LowpanException.java b/lowpan/java/android/net/lowpan/LowpanException.java
index 8ff37f926899..b43b2fe087e1 100644
--- a/lowpan/java/android/net/lowpan/LowpanException.java
+++ b/lowpan/java/android/net/lowpan/LowpanException.java
@@ -28,7 +28,7 @@ import android.util.AndroidException;
* @see LowpanInterface
* @hide
*/
-//@SystemApi
+// @SystemApi
public class LowpanException extends AndroidException {
// Make the eclipse warning about serializable exceptions go away
private static final long serialVersionUID = 0x31863cbe562b0e11l; // randomly generated
diff --git a/lowpan/java/android/net/lowpan/LowpanIdentity.java b/lowpan/java/android/net/lowpan/LowpanIdentity.java
index 2e7b560fda5e..9be45ef14b98 100644
--- a/lowpan/java/android/net/lowpan/LowpanIdentity.java
+++ b/lowpan/java/android/net/lowpan/LowpanIdentity.java
@@ -24,10 +24,9 @@ import java.util.Map;
*
* @hide
*/
-//@SystemApi
+// @SystemApi
public class LowpanIdentity {
- //////////////////////////////////////////////////////////////////////////
// Constants
/** @hide */
@@ -41,11 +40,10 @@ public class LowpanIdentity {
public static final int UNKNOWN = Integer.MAX_VALUE;
- //////////////////////////////////////////////////////////////////////////
// Builder
/** @hide */
- //@SystemApi
+ // @SystemApi
public static class Builder {
private final LowpanIdentity identity = new LowpanIdentity();
@@ -102,7 +100,6 @@ public class LowpanIdentity {
LowpanIdentity() {}
- //////////////////////////////////////////////////////////////////////////
// Instance Variables
private String mName = null;
@@ -111,7 +108,6 @@ public class LowpanIdentity {
private int mPanid = UNKNOWN;
private int mChannel = UNKNOWN;
- //////////////////////////////////////////////////////////////////////////
// Public Getters and Setters
public String getName() {
@@ -140,12 +136,10 @@ public class LowpanIdentity {
LowpanProperties.KEY_NETWORK_NAME.putInMap(parameters, networkInfo.getName());
}
if (networkInfo.getPanid() != LowpanIdentity.UNKNOWN) {
- LowpanProperties.KEY_NETWORK_PANID.putInMap(
- parameters, networkInfo.getPanid());
+ LowpanProperties.KEY_NETWORK_PANID.putInMap(parameters, networkInfo.getPanid());
}
if (networkInfo.getChannel() != LowpanIdentity.UNKNOWN) {
- LowpanProperties.KEY_CHANNEL.putInMap(
- parameters, networkInfo.getChannel());
+ LowpanProperties.KEY_CHANNEL.putInMap(parameters, networkInfo.getChannel());
}
if (networkInfo.getXpanid() != null) {
LowpanProperties.KEY_NETWORK_XPANID.putInMap(parameters, networkInfo.getXpanid());
diff --git a/lowpan/java/android/net/lowpan/LowpanInterface.java b/lowpan/java/android/net/lowpan/LowpanInterface.java
index cd548190fa17..2bb4ecd380f2 100644
--- a/lowpan/java/android/net/lowpan/LowpanInterface.java
+++ b/lowpan/java/android/net/lowpan/LowpanInterface.java
@@ -33,7 +33,7 @@ import java.util.Set;
*
* @hide
*/
-//@SystemApi
+// @SystemApi
public class LowpanInterface {
private static final String TAG = LowpanInterface.class.getSimpleName();
@@ -170,7 +170,7 @@ public class LowpanInterface {
*
* @hide
*/
- //@SystemApi
+ // @SystemApi
public abstract static class Callback {
public void onConnectedChanged(boolean value) {}
@@ -244,7 +244,6 @@ public class LowpanInterface {
LowpanException.throwAsPublicException(t);
}
- //////////////////////////////////////////////////////////////////////////
// Private Property Helpers
void setProperties(Map properties) throws LowpanException {
@@ -311,10 +310,9 @@ public class LowpanInterface {
boolean getPropertyAsBoolean(LowpanProperty<Boolean> key) throws LowpanException {
Boolean value = getProperty(key);
- return (value != null) ? value : 0;
+ return (value != null) ? value : false;
}
- //////////////////////////////////////////////////////////////////////////
// Public Actions
/**
@@ -424,7 +422,6 @@ public class LowpanInterface {
}
}
- //////////////////////////////////////////////////////////////////////////
// Public Getters and Setters
/**
@@ -448,13 +445,13 @@ public class LowpanInterface {
return "";
}
- /**
- * Indicates if the interface is enabled or disabled.
- *
- * @see #setEnabled
- * @see android.net.lowpan.LowpanException#LOWPAN_DISABLED
- */
- public boolean isEnabled() {
+ /**
+ * Indicates if the interface is enabled or disabled.
+ *
+ * @see #setEnabled
+ * @see android.net.lowpan.LowpanException#LOWPAN_DISABLED
+ */
+ public boolean isEnabled() {
try {
return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_ENABLED);
} catch (LowpanException x) {
@@ -462,16 +459,16 @@ public class LowpanInterface {
}
}
- /**
- * Enables or disables the LoWPAN interface. When disabled, the interface is put into a low-power
- * state and all commands that require the NCP to be queried will fail with {@link
- * android.net.lowpan.LowpanException#LOWPAN_DISABLED}.
- *
- * @see #isEnabled
- * @see android.net.lowpan.LowpanException#LOWPAN_DISABLED
- * @hide
- */
- public void setEnabled(boolean enabled) throws LowpanException {
+ /**
+ * Enables or disables the LoWPAN interface. When disabled, the interface is put into a
+ * low-power state and all commands that require the NCP to be queried will fail with {@link
+ * android.net.lowpan.LowpanException#LOWPAN_DISABLED}.
+ *
+ * @see #isEnabled
+ * @see android.net.lowpan.LowpanException#LOWPAN_DISABLED
+ * @hide
+ */
+ public void setEnabled(boolean enabled) throws LowpanException {
setProperty(LowpanProperties.KEY_INTERFACE_ENABLED, enabled);
}
@@ -628,7 +625,6 @@ public class LowpanInterface {
setProperties(map);
}
- //////////////////////////////////////////////////////////////////////////
// Listener Support
/**
@@ -644,7 +640,7 @@ public class LowpanInterface {
public void registerCallback(@NonNull Callback cb, @Nullable Handler handler) {
ILowpanInterfaceListener.Stub listenerBinder =
new ILowpanInterfaceListener.Stub() {
- public void onPropertiesChanged(Map<String, Object> properties) {
+ public void onPropertiesChanged(Map properties) {
Runnable runnable =
new Runnable() {
@Override
@@ -724,36 +720,35 @@ public class LowpanInterface {
*/
public void unregisterCallback(Callback cb) {
int hashCode = System.identityHashCode(cb);
- ILowpanInterfaceListener listenerBinder = mListenerMap.get(hashCode);
+ synchronized (mListenerMap) {
+ ILowpanInterfaceListener listenerBinder = mListenerMap.get(hashCode);
- if (listenerBinder != null) {
- synchronized (mListenerMap) {
+ if (listenerBinder != null) {
mListenerMap.remove(hashCode);
- }
- try {
- mBinder.removeListener(listenerBinder);
- } catch (RemoteException x) {
- // Catch and ignore all binder exceptions
- Log.e(TAG, x.toString());
+
+ try {
+ mBinder.removeListener(listenerBinder);
+ } catch (RemoteException x) {
+ // Catch and ignore all binder exceptions
+ Log.e(TAG, x.toString());
+ }
}
}
}
- //////////////////////////////////////////////////////////////////////////
- // Active and Passive Scanning
+ // Active and Passive Scanning
- /**
- * Creates a new {@link android.net.lowpan.LowpanScanner} object for this interface.
- *
- * <p>This method allocates a new unique object for each call.
- *
- * @see android.net.lowpan.LowpanScanner
- */
- public @NonNull LowpanScanner createScanner() {
+ /**
+ * Creates a new {@link android.net.lowpan.LowpanScanner} object for this interface.
+ *
+ * <p>This method allocates a new unique object for each call.
+ *
+ * @see android.net.lowpan.LowpanScanner
+ */
+ public @NonNull LowpanScanner createScanner() {
return new LowpanScanner(mBinder);
}
- //////////////////////////////////////////////////////////////////////////
// Route Management
/**
diff --git a/lowpan/java/android/net/lowpan/LowpanManager.java b/lowpan/java/android/net/lowpan/LowpanManager.java
index b58608da7c21..ecdda49f718a 100644
--- a/lowpan/java/android/net/lowpan/LowpanManager.java
+++ b/lowpan/java/android/net/lowpan/LowpanManager.java
@@ -33,32 +33,24 @@ import java.util.HashMap;
*
* @hide
*/
-//@SystemApi
+// @SystemApi
public class LowpanManager {
private static final String TAG = LowpanManager.class.getSimpleName();
- //////////////////////////////////////////////////////////////////////////
- // Public Classes
-
/** @hide */
- //@SystemApi
+ // @SystemApi
public abstract static class Callback {
- public void onInterfaceAdded(LowpanInterface lowpan_interface) {}
+ public void onInterfaceAdded(LowpanInterface lowpanInterface) {}
- public void onInterfaceRemoved(LowpanInterface lowpan_interface) {}
+ public void onInterfaceRemoved(LowpanInterface lowpanInterface) {}
}
- //////////////////////////////////////////////////////////////////////////
- // Instance Variables
-
+ private Context mContext;
private ILowpanManager mManager;
private HashMap<Integer, ILowpanManagerListener> mListenerMap = new HashMap<>();
- //////////////////////////////////////////////////////////////////////////
-
private static LowpanManager sSingletonInstance;
- //////////////////////////////////////////////////////////////////////////
// Static Methods
/** Returns a reference to the LowpanManager object, allocating it if necessary. */
@@ -75,7 +67,6 @@ public class LowpanManager {
return sSingletonInstance;
}
- //////////////////////////////////////////////////////////////////////////
// Constructors
/**
@@ -84,28 +75,34 @@ public class LowpanManager {
*/
private LowpanManager() {}
- //////////////////////////////////////////////////////////////////////////
// Private Methods
/**
* Returns a reference to the ILowpanManager interface, provided by the LoWPAN Manager Service.
*/
@Nullable
- private ILowpanManager getILowpanManager() {
+ private synchronized ILowpanManager getILowpanManager() {
+ // Use a local reference of this object for thread safety.
ILowpanManager manager = mManager;
+
if (manager == null) {
IBinder serviceBinder =
new ServiceManager().getService(ILowpanManager.LOWPAN_SERVICE_NAME);
- mManager = manager = ILowpanManager.Stub.asInterface(serviceBinder);
+
+ manager = ILowpanManager.Stub.asInterface(serviceBinder);
+
+ mManager = manager;
// Add any listeners
synchronized (mListenerMap) {
- for (Integer hashObj : mListenerMap.keySet()) {
+ for (ILowpanManagerListener listener : mListenerMap.values()) {
try {
- manager.addListener(mListenerMap.get(hashObj));
+ manager.addListener(listener);
+
} catch (RemoteException x) {
// Consider any failure here as implying the manager is defunct
- mManager = manager = null;
+ mManager = null;
+ manager = null;
}
}
}
@@ -113,7 +110,6 @@ public class LowpanManager {
return manager;
}
- //////////////////////////////////////////////////////////////////////////
// Public Methods
/**
@@ -141,6 +137,7 @@ public class LowpanManager {
manager = getILowpanManager();
}
}
+
return ret;
}
@@ -151,7 +148,7 @@ public class LowpanManager {
@Nullable
public LowpanInterface getInterface() {
String[] ifaceList = getInterfaceList();
- if (ifaceList != null && ifaceList.length > 0) {
+ if (ifaceList.length > 0) {
return getInterface(ifaceList[0]);
}
return null;
@@ -165,24 +162,16 @@ public class LowpanManager {
public String[] getInterfaceList() {
ILowpanManager manager = getILowpanManager();
- if (manager != null) {
+ // Maximum number of tries is two. We should only try
+ // more than once if our manager has died or there
+ // was some sort of AIDL buffer full event.
+ for (int i = 0; i < 2 && manager != null; i++) {
try {
return manager.getInterfaceList();
-
} catch (RemoteException x) {
// In all of the cases when we get this exception, we reconnect and try again
mManager = null;
- try {
- manager = getILowpanManager();
- if (manager != null) {
- return manager.getInterfaceList();
- }
- } catch (RemoteException ex) {
- // Something weird is going on, so we log it
- // and fall back thru to returning an empty array.
- Log.e(TAG, ex.toString());
- mManager = null;
- }
+ manager = getILowpanManager();
}
}
@@ -200,14 +189,14 @@ public class LowpanManager {
throws LowpanException {
ILowpanManagerListener.Stub listenerBinder =
new ILowpanManagerListener.Stub() {
- public void onInterfaceAdded(ILowpanInterface lowpan_interface) {
+ public void onInterfaceAdded(ILowpanInterface lowpanInterface) {
Runnable runnable =
new Runnable() {
@Override
public void run() {
cb.onInterfaceAdded(
LowpanInterface.getInterfaceFromBinder(
- lowpan_interface.asBinder()));
+ lowpanInterface.asBinder()));
}
};
@@ -218,14 +207,14 @@ public class LowpanManager {
}
}
- public void onInterfaceRemoved(ILowpanInterface lowpan_interface) {
+ public void onInterfaceRemoved(ILowpanInterface lowpanInterface) {
Runnable runnable =
new Runnable() {
@Override
public void run() {
cb.onInterfaceRemoved(
LowpanInterface.getInterfaceFromBinder(
- lowpan_interface.asBinder()));
+ lowpanInterface.asBinder()));
}
};
diff --git a/lowpan/java/android/net/lowpan/LowpanProvision.java b/lowpan/java/android/net/lowpan/LowpanProvision.java
index ace1f9c05c4d..7028807679a1 100644
--- a/lowpan/java/android/net/lowpan/LowpanProvision.java
+++ b/lowpan/java/android/net/lowpan/LowpanProvision.java
@@ -25,14 +25,13 @@ import java.util.Map;
*
* @hide
*/
-//@SystemApi
+// @SystemApi
public class LowpanProvision {
- //////////////////////////////////////////////////////////////////////////
// Builder
/** @hide */
- //@SystemApi
+ // @SystemApi
public static class Builder {
private final LowpanProvision provision = new LowpanProvision();
@@ -53,13 +52,11 @@ public class LowpanProvision {
private LowpanProvision() {}
- //////////////////////////////////////////////////////////////////////////
// Instance Variables
private LowpanIdentity mIdentity = new LowpanIdentity();
private LowpanCredential mCredential = null;
- //////////////////////////////////////////////////////////////////////////
// Public Getters and Setters
@NonNull
@@ -72,7 +69,6 @@ public class LowpanProvision {
return mCredential;
}
- //////////////////////////////////////////////////////////////////////////
// LoWPAN-Internal Methods
static void addToMap(Map<String, Object> parameters, LowpanProvision provision)
diff --git a/lowpan/java/android/net/lowpan/LowpanScanner.java b/lowpan/java/android/net/lowpan/LowpanScanner.java
index 754f72e3cb84..e0df55d9af3f 100644
--- a/lowpan/java/android/net/lowpan/LowpanScanner.java
+++ b/lowpan/java/android/net/lowpan/LowpanScanner.java
@@ -25,7 +25,6 @@ import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
/**
@@ -36,11 +35,10 @@ import java.util.Map;
* @see LowpanInterface
* @hide
*/
-//@SystemApi
+// @SystemApi
public class LowpanScanner {
private static final String TAG = LowpanInterface.class.getSimpleName();
- //////////////////////////////////////////////////////////////////////////
// Public Classes
/**
@@ -48,7 +46,7 @@ public class LowpanScanner {
*
* @hide
*/
- //@SystemApi
+ // @SystemApi
public abstract static class Callback {
public void onNetScanBeacon(LowpanBeaconInfo beacon) {}
@@ -57,16 +55,14 @@ public class LowpanScanner {
public void onScanFinished() {}
}
- //////////////////////////////////////////////////////////////////////////
// Instance Variables
private ILowpanInterface mBinder;
private Callback mCallback = null;
private Handler mHandler = null;
- private List<Integer> mChannelMask = null;
+ private ArrayList<Integer> mChannelMask = null;
private int mTxPower = Integer.MAX_VALUE;
- //////////////////////////////////////////////////////////////////////////
// Constructors/Accessors and Exception Glue
LowpanScanner(@NonNull ILowpanInterface binder) {
@@ -74,7 +70,7 @@ public class LowpanScanner {
}
/** Sets an instance of {@link LowpanScanner.Callback} to receive events. */
- public void setCallback(@Nullable Callback cb, @Nullable Handler handler) {
+ public synchronized void setCallback(@Nullable Callback cb, @Nullable Handler handler) {
mCallback = cb;
mHandler = handler;
}
@@ -110,7 +106,7 @@ public class LowpanScanner {
* @return the current channel mask, or <code>null</code> if no channel mask is currently set.
*/
public @Nullable Collection<Integer> getChannelMask() {
- return mChannelMask.clone();
+ return (Collection<Integer>) mChannelMask.clone();
}
/**
@@ -179,17 +175,24 @@ public class LowpanScanner {
ILowpanNetScanCallback binderListener =
new ILowpanNetScanCallback.Stub() {
public void onNetScanBeacon(Map parameters) {
- Callback callback = mCallback;
- Handler handler = mHandler;
+ Callback callback;
+ Handler handler;
+
+ synchronized (LowpanScanner.this) {
+ callback = mCallback;
+ handler = mHandler;
+ }
if (callback == null) {
return;
}
- Runnable runnable = () -> callback.onNetScanBeacon(
- new LowpanBeaconInfo.Builder()
- .updateFromMap(parameters)
- .build());
+ Runnable runnable =
+ () ->
+ callback.onNetScanBeacon(
+ new LowpanBeaconInfo.Builder()
+ .updateFromMap(parameters)
+ .build());
if (handler != null) {
handler.post(runnable);
@@ -199,8 +202,13 @@ public class LowpanScanner {
}
public void onNetScanFinished() {
- Callback callback = mCallback;
- Handler handler = mHandler;
+ Callback callback;
+ Handler handler;
+
+ synchronized (LowpanScanner.this) {
+ callback = mCallback;
+ handler = mHandler;
+ }
if (callback == null) {
return;
@@ -218,7 +226,7 @@ public class LowpanScanner {
try {
mBinder.startNetScan(map, binderListener);
- } catch (ServiceSpecificException|RemoteException x) {
+ } catch (ServiceSpecificException | RemoteException x) {
LowpanException.throwAsPublicException(x);
}
}
@@ -257,7 +265,8 @@ public class LowpanScanner {
return;
}
- Runnable runnable = () -> {
+ Runnable runnable =
+ () -> {
if (callback != null) {
LowpanEnergyScanResult result =
new LowpanEnergyScanResult();
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 2703fbf00a50..20b12b4823ac 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -47,6 +47,9 @@ import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
@@ -63,7 +66,14 @@ public class CaptivePortalLoginActivity extends Activity {
private static final int SOCKET_TIMEOUT_MS = 10000;
- private enum Result { DISMISSED, UNWANTED, WANTED_AS_IS };
+ private enum Result {
+ DISMISSED(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_DISMISSED),
+ UNWANTED(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_UNWANTED),
+ WANTED_AS_IS(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_WANTED_AS_IS);
+
+ final int metricsEvent;
+ Result(int metricsEvent) { this.metricsEvent = metricsEvent; }
+ };
private URL mUrl;
private String mUserAgent;
@@ -77,6 +87,9 @@ public class CaptivePortalLoginActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+
+ logMetricsEvent(MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY);
+
mCm = ConnectivityManager.from(this);
mNetwork = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_NETWORK);
mCaptivePortal = getIntent().getParcelableExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL);
@@ -173,6 +186,7 @@ public class CaptivePortalLoginActivity extends Activity {
mCm.unregisterNetworkCallback(mNetworkCallback);
mNetworkCallback = null;
}
+ logMetricsEvent(result.metricsEvent);
switch (result) {
case DISMISSED:
mCaptivePortal.reportCaptivePortalDismissed();
@@ -381,6 +395,7 @@ public class CaptivePortalLoginActivity extends Activity {
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+ logMetricsEvent(MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR);
Log.w(TAG, "SSL error (error: " + error.getPrimaryError() + " host: " +
// Only show host to avoid leaking private info.
Uri.parse(error.getUrl()).getHost() + " certificate: " +
@@ -492,4 +507,8 @@ public class CaptivePortalLoginActivity extends Activity {
}
return url.getHost();
}
+
+ private void logMetricsEvent(int event) {
+ MetricsLogger.action(this, event, getPackageName());
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 533c52b20f4e..96f51c16796f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -16,6 +16,7 @@
package com.android.providers.settings;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.backup.BackupAgentHelper;
import android.app.backup.BackupDataInput;
@@ -30,7 +31,6 @@ import android.net.NetworkPolicyManager;
import android.net.Uri;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
-import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.provider.Settings;
@@ -590,14 +590,18 @@ public class SettingsBackupAgent extends BackupAgentHelper {
Log.i(TAG, "restoreSettings: " + contentUri);
}
- // Figure out the white list and redirects to the global table.
+ // Figure out the white list and redirects to the global table. We restore anything
+ // in either the backup whitelist or the legacy-restore whitelist for this table.
final String[] whitelist;
if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
- whitelist = Settings.Secure.SETTINGS_TO_BACKUP;
+ whitelist = concat(Settings.Secure.SETTINGS_TO_BACKUP,
+ Settings.Secure.LEGACY_RESTORE_SETTINGS);
} else if (contentUri.equals(Settings.System.CONTENT_URI)) {
- whitelist = Settings.System.SETTINGS_TO_BACKUP;
+ whitelist = concat(Settings.System.SETTINGS_TO_BACKUP,
+ Settings.System.LEGACY_RESTORE_SETTINGS);
} else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
- whitelist = Settings.Global.SETTINGS_TO_BACKUP;
+ whitelist = concat(Settings.Global.SETTINGS_TO_BACKUP,
+ Settings.Global.LEGACY_RESTORE_SETTINGS);
} else {
throw new IllegalArgumentException("Unknown URI: " + contentUri);
}
@@ -648,6 +652,18 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
}
+ private final String[] concat(String[] first, @Nullable String[] second) {
+ if (second == null || second.length == 0) {
+ return first;
+ }
+ final int firstLen = first.length;
+ final int secondLen = second.length;
+ String[] both = new String[firstLen + secondLen];
+ System.arraycopy(first, 0, both, 0, firstLen);
+ System.arraycopy(second, 0, both, firstLen, secondLen);
+ return both;
+ }
+
/**
* Restores the owner info enabled and other settings in LockSettings.
*
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index f5d7dd8d9acd..1df2c807f64f 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2895,7 +2895,7 @@ public class SettingsProvider extends ContentProvider {
}
private final class UpgradeController {
- private static final int SETTINGS_VERSION = 145;
+ private static final int SETTINGS_VERSION = 146;
private final int mUserId;
@@ -3478,22 +3478,25 @@ public class SettingsProvider extends ContentProvider {
}
if (currentVersion == 144) {
- // Version 145: Set the default value for WIFI_WAKEUP_AVAILABLE.
+ // Version 145: Removed
+ currentVersion = 145;
+ }
+
+ if (currentVersion == 145) {
+ // Version 146: Set the default value for WIFI_WAKEUP_AVAILABLE.
if (userId == UserHandle.USER_SYSTEM) {
final SettingsState globalSettings = getGlobalSettingsLocked();
final Setting currentSetting = globalSettings.getSettingLocked(
Settings.Global.WIFI_WAKEUP_AVAILABLE);
- if (currentSetting.isNull()) {
- final int defaultValue = getContext().getResources().getInteger(
- com.android.internal.R.integer.config_wifi_wakeup_available);
- globalSettings.insertSettingLocked(
- Settings.Global.WIFI_WAKEUP_AVAILABLE,
- String.valueOf(defaultValue),
- null, true, SettingsState.SYSTEM_PACKAGE_NAME);
- }
+ final int defaultValue = getContext().getResources().getInteger(
+ com.android.internal.R.integer.config_wifi_wakeup_available);
+ globalSettings.insertSettingLocked(
+ Settings.Global.WIFI_WAKEUP_AVAILABLE,
+ String.valueOf(defaultValue),
+ null, true, SettingsState.SYSTEM_PACKAGE_NAME);
}
- currentVersion = 145;
+ currentVersion = 146;
}
// vXXX: Add new settings above this point.
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d3cbe4aa578f..81ca23082367 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -262,6 +262,9 @@
<!-- Doze: alpha to apply to small icons when dozing -->
<integer name="doze_small_icon_alpha">222</integer><!-- 87% of 0xff -->
+ <!-- Doze: whether the double tap sensor reports 2D touch coordinates -->
+ <bool name="doze_double_tap_reports_touch_coordinates">false</bool>
+
<!-- Hotspot tile: number of days to show after feature is used. -->
<integer name="days_to_show_hotspot_tile">30</integer>
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 3e424d05373a..5aaa6c78f5fd 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -38,6 +38,8 @@ public interface DozeHost {
void setAnimateWakeup(boolean animateWakeup);
+ void onDoubleTap(float x, float y);
+
interface Callback {
default void onNotificationHeadsUp() {}
default void onPowerSaveChanged(boolean active) {}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 73f522244a60..23da716706d3 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -81,17 +81,18 @@ public class DozeSensors {
mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION),
null /* setting */,
dozeParameters.getPulseOnSigMotion(),
- DozeLog.PULSE_REASON_SENSOR_SIGMOTION),
+ DozeLog.PULSE_REASON_SENSOR_SIGMOTION, false /* touchCoords */),
mPickupSensor = new TriggerSensor(
mSensorManager.getDefaultSensor(Sensor.TYPE_PICK_UP_GESTURE),
Settings.Secure.DOZE_PULSE_ON_PICK_UP,
config.pulseOnPickupAvailable(),
- DozeLog.PULSE_REASON_SENSOR_PICKUP),
+ DozeLog.PULSE_REASON_SENSOR_PICKUP, false /* touchCoords */),
new TriggerSensor(
findSensorWithType(config.doubleTapSensorType()),
Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP,
true /* configured */,
- DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP)
+ DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP,
+ dozeParameters.doubleTapReportsTouchCoordinates())
};
mProxSensor = new ProxSensor();
@@ -207,16 +208,19 @@ public class DozeSensors {
final boolean mConfigured;
final int mPulseReason;
final String mSetting;
+ final boolean mReportsTouchCoordinates;
private boolean mRequested;
private boolean mRegistered;
private boolean mDisabled;
- public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason) {
+ public TriggerSensor(Sensor sensor, String setting, boolean configured, int pulseReason,
+ boolean reportsTouchCoordinates) {
mSensor = sensor;
mSetting = setting;
mConfigured = configured;
mPulseReason = pulseReason;
+ mReportsTouchCoordinates = reportsTouchCoordinates;
}
public void setListening(boolean listen) {
@@ -276,7 +280,13 @@ public class DozeSensors {
}
mRegistered = false;
- mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck);
+ float screenX = -1;
+ float screenY = -1;
+ if (mReportsTouchCoordinates && event.values.length >= 2) {
+ screenX = event.values[0];
+ screenY = event.values[1];
+ }
+ mCallback.onSensorPulse(mPulseReason, sensorPerformsProxCheck, screenX, screenY);
updateListener(); // reregister, this sensor only fires once
}));
}
@@ -309,7 +319,12 @@ public class DozeSensors {
* Called when a sensor requests a pulse
* @param pulseReason Requesting sensor, e.g. {@link DozeLog#PULSE_REASON_SENSOR_PICKUP}
* @param sensorPerformedProxCheck true if the sensor already checked for FAR proximity.
+ * @param screenX the location on the screen where the sensor fired or -1
+ * if the sensor doesn't support reporting screen locations.
+ * @param screenY the location on the screen where the sensor fired or -1
+ * if the sensor doesn't support reporting screen locations.
*/
- void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck);
+ void onSensorPulse(int pulseReason, boolean sensorPerformedProxCheck,
+ float screenX, float screenY);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 693a690d7f59..ae936db7b0e2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -98,12 +98,14 @@ public class DozeTriggers implements DozeMachine.Part {
requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */);
}
- private void onSensor(int pulseReason, boolean sensorPerformedProxCheck) {
+ private void onSensor(int pulseReason, boolean sensorPerformedProxCheck,
+ float screenX, float screenY) {
boolean isDoubleTap = pulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
boolean isPickup = pulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP;
if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
if (isDoubleTap) {
+ mDozeHost.onDoubleTap(screenX, screenY);
mMachine.wakeUp();
} else {
mDozeHost.extendPulse();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 76177a310a06..4a6bafc50e52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -51,7 +51,14 @@ import com.android.systemui.statusbar.phone.NavigationBarView;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
-
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.classifier.FalsingLog;
+import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.Prefs;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Map;
/**
* A status bar (and navigation bar) tailored for the automotive use case.
*/
@@ -71,6 +78,7 @@ public class CarStatusBar extends StatusBar implements
private ConnectedDeviceSignalController mConnectedDeviceSignalController;
private CarNavigationBarView mNavigationBarView;
+ private final Object mQueueLock = new Object();
@Override
public void start() {
super.start();
@@ -170,6 +178,43 @@ public class CarStatusBar extends StatusBar implements
}
@Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ //When executing dump() funciton simultaneously, we need to serialize them
+ //to get mStackScroller's position correctly.
+ synchronized (mQueueLock) {
+ pw.println(" mStackScroller: " + viewInfo(mStackScroller));
+ pw.println(" mStackScroller: " + viewInfo(mStackScroller)
+ + " scroll " + mStackScroller.getScrollX()
+ + "," + mStackScroller.getScrollY());
+ }
+
+ pw.print(" mTaskStackListener="); pw.println(mTaskStackListener);
+ pw.print(" mController=");
+ pw.println(mController);
+ pw.print(" mFullscreenUserSwitcher="); pw.println(mFullscreenUserSwitcher);
+ pw.print(" mCarBatteryController=");
+ pw.println(mCarBatteryController);
+ pw.print(" mBatteryMeterView=");
+ pw.println(mBatteryMeterView);
+ pw.print(" mConnectedDeviceSignalController=");
+ pw.println(mConnectedDeviceSignalController);
+ pw.print(" mNavigationBarView=");
+ pw.println(mNavigationBarView);
+
+ if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
+ KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
+ }
+
+ FalsingManager.getInstance(mContext).dump(pw);
+ FalsingLog.dump(pw);
+
+ pw.println("SharedPreferences:");
+ for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
+ pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
+ }
+ }
+
+ @Override
public NavigationBarView getNavigationBarView() {
return mNavigationBarView;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index d7e7abe4fd9c..6b7397b3f8ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -157,6 +157,10 @@ public class DozeParameters {
return 2 * getPulseVisibleDuration();
}
+ public boolean doubleTapReportsTouchCoordinates() {
+ return mContext.getResources().getBoolean(R.bool.doze_double_tap_reports_touch_coordinates);
+ }
+
/**
* Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 021e11acbcf5..3937dd3eea2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -517,14 +517,14 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout {
mAnimationsEnabled = enabled;
}
- public void setReplacingIcons(ArrayMap<String, ArrayList<StatusBarIcon>> replacingIcons) {
- mReplacingIcons = replacingIcons;
- }
-
public void setDarkOffsetX(int offsetX) {
mDarkOffsetX = offsetX;
}
+ public void setReplacingIcons(ArrayMap<String, ArrayList<StatusBarIcon>> replacingIcons) {
+ mReplacingIcons = replacingIcons;
+ }
+
public class IconState extends ViewState {
public float iconAppearAmount = 1.0f;
public float clampedAppearAmount = 1.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index e8b6e079e261..0ac221f7f088 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -32,7 +32,6 @@ import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSLUCE
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
import static com.android.systemui.statusbar.phone.BarTransitions.MODE_WARNING;
-import android.R.style;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.NonNull;
@@ -5325,6 +5324,37 @@ public class StatusBar extends SystemUI implements DemoMode,
mAnimateWakeup = animateWakeup;
}
+ @Override
+ public void onDoubleTap(float screenX, float screenY) {
+ if (screenX > 0 && screenY > 0 && mAmbientIndicationContainer != null
+ && mAmbientIndicationContainer.getVisibility() == View.VISIBLE) {
+ mAmbientIndicationContainer.getLocationOnScreen(mTmpInt2);
+ float viewX = screenX - mTmpInt2[0];
+ float viewY = screenY - mTmpInt2[1];
+ if (0 <= viewX && viewX <= mAmbientIndicationContainer.getWidth()
+ && 0 <= viewY && viewY <= mAmbientIndicationContainer.getHeight()) {
+ dispatchDoubleTap(viewX, viewY);
+ }
+ }
+ }
+
+ public void dispatchDoubleTap(float viewX, float viewY) {
+ dispatchTap(mAmbientIndicationContainer, viewX, viewY);
+ dispatchTap(mAmbientIndicationContainer, viewX, viewY);
+ }
+
+ private void dispatchTap(View view, float x, float y) {
+ long now = SystemClock.elapsedRealtime();
+ dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_DOWN);
+ dispatchTouchEvent(view, x, y, now, MotionEvent.ACTION_UP);
+ }
+
+ private void dispatchTouchEvent(View view, float x, float y, long now, int action) {
+ MotionEvent ev = MotionEvent.obtain(now, now, action, x, y, 0 /* meta */);
+ view.dispatchTouchEvent(ev);
+ ev.recycle();
+ }
+
private boolean shouldAnimateWakeup() {
return mAnimateWakeup;
}
@@ -6866,7 +6896,8 @@ public class StatusBar extends SystemUI implements DemoMode,
// If mAlwaysExpandNonGroupedNotification is false, then only expand the
// very first notification and if it's not a child of grouped notifications.
row.setSystemExpanded(mAlwaysExpandNonGroupedNotification
- || (visibleNotifications == 0 && !isChildNotification));
+ || (visibleNotifications == 0 && !isChildNotification
+ && !row.isLowPriority()));
}
entry.row.setShowAmbient(isDozing());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
index 56c07f905446..23451106a20c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -28,6 +28,8 @@ class DozeHostFake implements DozeHost {
boolean pulseExtended;
boolean animateWakeup;
boolean dozing;
+ float doubleTapX;
+ float doubleTapY;
@Override
public void addCallback(@NonNull Callback callback) {
@@ -88,4 +90,10 @@ class DozeHostFake implements DozeHost {
public void setAnimateWakeup(boolean animateWakeup) {
this.animateWakeup = animateWakeup;
}
+
+ @Override
+ public void onDoubleTap(float x, float y) {
+ doubleTapX = y;
+ doubleTapY = y;
+ }
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 11ea841a10f5..fa2b1ee83419 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4090,6 +4090,11 @@ message MetricsEvent {
// OS: O DR
SETTINGS_ASSIST_GESTURE_FIRST_TIME = 1012;
+ // CaptivePortalLoginActivity displays SSL error page
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: O DR
+ CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR = 1013;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 25a0772efd7f..1afde550f027 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -1218,6 +1218,12 @@ public final class TvInputManagerService extends SystemService {
@Override
public void setMainSession(IBinder sessionToken, int userId) {
+ if (mContext.checkCallingPermission(
+ android.Manifest.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "The caller does not have CHANGE_HDMI_CEC_ACTIVE_SOURCE permission");
+ }
if (DEBUG) {
Slog.d(TAG, "setMainSession(sessionToken=" + sessionToken + ")");
}
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java
index 3282f5f31960..765c73beedf4 100644
--- a/telephony/java/android/telephony/Telephony.java
+++ b/telephony/java/android/telephony/Telephony.java
@@ -1176,6 +1176,29 @@ public final class Telephony {
}
/**
+ * Base column for the table that contain Carrier Public key.
+ * @hide
+ */
+ public interface CarrierColumns extends BaseColumns {
+
+ public static final String MCC = "mcc";
+ public static final String MNC = "mnc";
+ public static final String KEY_TYPE = "key_type";
+ public static final String MVNO_TYPE = "mvno_type";
+ public static final String MVNO_MATCH_DATA = "mvno_match_data";
+ public static final String PUBLIC_KEY = "public_key";
+ public static final String KEY_IDENTIFIER = "key_identifier";
+ public static final String EXPIRATION_TIME = "expiration_time";
+ public static final String LAST_MODIFIED = "last_modified";
+
+ /**
+ * The {@code content://} style URL for this table.
+ * @hide
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://carrier_information/carrier");
+ }
+
+ /**
* Base columns for tables that contain MMSs.
*/
public interface BaseMmsColumns extends BaseColumns {
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 1d2e3a4f2df0..5978cdd154b9 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -27,7 +27,7 @@ namespace aapt {
static const char* sMajorVersion = "2";
// Update minor version whenever a feature or flag is added.
-static const char* sMinorVersion = "16";
+static const char* sMinorVersion = "17";
int PrintVersion() {
std::cerr << "Android Asset Packaging Tool (aapt) " << sMajorVersion << "."
diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md
index 0290e30dfced..49cb8d4ca827 100644
--- a/tools/aapt2/readme.md
+++ b/tools/aapt2/readme.md
@@ -1,9 +1,19 @@
# Android Asset Packaging Tool 2.0 (AAPT2) release notes
## Version 2.17
-### `aapt2 compile ...`
-- Fixed an issue where symlinks would not be followed when compiling PNGs. (bug 62144459)
+### `aapt2 ...`
+- Fixed issue where symlinks would not be followed when compiling PNGs. (bug 62144459)
- Fixed issue where overlays that declared `<add-resource>` did not compile. (bug 38355988)
+- Fixed issue where `%n` in a string resource was interpreted as a format argument. (bug 37132275)
+- Allow empty resources to compile, giving them a value of `""` or `@null`, depending on the
+ accepted formats. (bug 38425050)
+- Resources declared via `<item>` with no format attribute were changed to accept all
+ resource types. (bug 62260121)
+- Allow `<layout>` element under `<activity>` in AndroidManifest.xml. (bug 62189611)
+- Fix issue where `--no-version-vector` did not apply to `pathInterpolator` and `objectAnimator`.
+ (bug 62211148)
+- Fix issue where overlaid `<style>` would not be merged, and would replace the original resource
+ instead. This fix brings behavior in-line with AAPT. (bug 38355988)
## Version 2.16
### `aapt2 link ...`