Merge "Keyguard: Clean up security message display"
diff --git a/Android.mk b/Android.mk
index e352bc7..4fea0d4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -288,7 +288,6 @@
core/java/android/view/accessibility/IAccessibilityManagerClient.aidl \
core/java/android/view/IApplicationToken.aidl \
core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl \
- core/java/android/view/IAssetAtlas.aidl \
core/java/android/view/IDockedStackListener.aidl \
core/java/android/view/IGraphicsStats.aidl \
core/java/android/view/IInputFilter.aidl \
@@ -860,6 +859,7 @@
-since $(SRC_API_DIR)/22.txt 22 \
-since $(SRC_API_DIR)/23.txt 23 \
-since $(SRC_API_DIR)/24.txt 24 \
+ -since $(SRC_API_DIR)/25.txt 25 \
-werror -hide 111 -hide 113 \
-overview $(LOCAL_PATH)/core/java/overview.html
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..f5bd945
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,7 @@
+[Hook Scripts]
+checkstyle_hook = ../../development/tools/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
+ -fw core/java/android/animation/
+ core/java/android/text/
+ core/java/android/view/
+ core/java/android/transition/
+ core/java/android/widget/
diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk
index eb07c05..5fe2f02 100644
--- a/apct-tests/perftests/core/Android.mk
+++ b/apct-tests/perftests/core/Android.mk
@@ -12,5 +12,8 @@
LOCAL_PACKAGE_NAME := CorePerfTests
+# Use google-fonts/dancing-script for the performance metrics
+LOCAL_ASSET_DIR := $(TOP)/external/google-fonts/dancing-script
+
include $(BUILD_PACKAGE)
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
new file mode 100644
index 0000000..519d1f4
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.perftests;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Bitmap.Config;
+import android.graphics.Paint;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.filters.LargeTest;
+import android.view.DisplayListCanvas;
+import android.view.RenderNode;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+@LargeTest
+public class CanvasPerfTest {
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void testBasicViewGroupDraw() {
+ // This test is a clone of BM_DisplayListCanvas_basicViewGroupDraw
+
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ RenderNode node = RenderNode.create("benchmark", null);
+ RenderNode child = RenderNode.create("child", null);
+ child.setLeftTopRightBottom(50, 50, 100, 100);
+
+ DisplayListCanvas canvas = node.start(100, 100);
+ node.end(canvas);
+ canvas = child.start(50, 50);
+ canvas.drawColor(Color.WHITE);
+ child.end(canvas);
+
+ while (state.keepRunning()) {
+ canvas = node.start(200, 200);
+ canvas.setHighContrastText(false);
+ int save = canvas.save();
+ canvas.clipRect(1, 1, 199, 199);
+ canvas.insertReorderBarrier();
+ for (int i = 0; i < 5; i++) {
+ canvas.drawRenderNode(child);
+ }
+ canvas.insertInorderBarrier();
+ canvas.restoreToCount(save);
+ node.end(canvas);
+ }
+ }
+
+ @Test
+ public void testRecordSimpleBitmapView() {
+ // This test is a clone of BM_DisplayListCanvas_record_simpleBitmapView
+
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ RenderNode node = RenderNode.create("benchmark", null);
+
+ DisplayListCanvas canvas = node.start(100, 100);
+ node.end(canvas);
+ Bitmap bitmap = Bitmap.createBitmap(80, 80, Config.ARGB_8888);
+ Paint paint = new Paint();
+ paint.setColor(Color.BLACK);
+
+ while (state.keepRunning()) {
+ canvas = node.start(100, 100);
+ {
+ canvas.save();
+ canvas.drawRect(0, 0, 100, 100, paint);
+ canvas.restore();
+ }
+ {
+ canvas.save();
+ canvas.translate(10, 10);
+ canvas.drawBitmap(bitmap, 0, 0, null);
+ canvas.restore();
+ }
+ node.end(canvas);
+ }
+ }
+}
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
new file mode 100644
index 0000000..11ee599
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceCreatePerfTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.perftests;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.graphics.Typeface;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TypefaceCreatePerfTest {
+ // A font file name in asset directory.
+ private static final String TEST_FONT_NAME = "DancingScript-Regular.ttf";
+
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ @Test
+ public void testCreate_fromFamily() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ Typeface face = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);
+ }
+ }
+
+ @Test
+ public void testCreate_fromFamilyName() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+ while (state.keepRunning()) {
+ Typeface face = Typeface.create("monospace", Typeface.NORMAL);
+ }
+ }
+
+ @Test
+ public void testCreate_fromAsset() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final Context context = InstrumentationRegistry.getContext();
+ final AssetManager am = context.getAssets();
+
+ while (state.keepRunning()) {
+ Typeface face = Typeface.createFromAsset(am, TEST_FONT_NAME);
+ }
+ }
+
+ @Test
+ public void testCreate_fromFile() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final Context context = InstrumentationRegistry.getContext();
+ final AssetManager am = context.getAssets();
+
+ File outFile = null;
+ try {
+ outFile = File.createTempFile("example", "ttf", context.getCacheDir());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ try (InputStream in = am.open(TEST_FONT_NAME);
+ OutputStream out = new FileOutputStream(outFile)) {
+ byte[] buf = new byte[1024];
+ int n = 0;
+ while ((n = in.read(buf)) != -1) {
+ out.write(buf, 0, n);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ while (state.keepRunning()) {
+ Typeface face = Typeface.createFromFile(outFile);
+ }
+
+ outFile.delete();
+ }
+}
diff --git a/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java b/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
index 6a49c03..80ce22e 100644
--- a/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
+++ b/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
@@ -37,4 +37,10 @@
System.nanoTime();
}
}
+
+ @Test
+ public void testBenchmarkOverhead() {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {}
+ }
}
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
index cdbca63..88cb8e6 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
@@ -57,8 +57,6 @@
@LargeTest
@RunWith(AndroidJUnit4.class)
public class UserLifecycleTest {
- private final int MIN_REPEAT_TIMES = 4;
-
private final int TIMEOUT_REMOVE_USER_MS = 4 * 1000; // 4 sec
private final int CHECK_USER_REMOVED_INTERVAL_MS = 200; // 0.2 sec
@@ -90,7 +88,6 @@
mAm = context.getSystemService(ActivityManager.class);
mIam = ActivityManagerNative.getDefault();
mState = mPerfStatusReporter.getBenchmarkState();
- mState.setMinRepeatTimes(MIN_REPEAT_TIMES);
mUsersToRemove = new ArrayList<>();
}
@@ -300,4 +297,4 @@
mUsersToRemove.add(userId);
}
}
-}
\ No newline at end of file
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
index b27d71b..bf04f6d 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
@@ -23,6 +23,7 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.concurrent.TimeUnit;
/**
* Provides a benchmark framework.
@@ -41,39 +42,47 @@
* System.out.println(state.summaryLine());
* }
*/
-public class BenchmarkState {
+public final class BenchmarkState {
private static final String TAG = "BenchmarkState";
- private static final int NOT_STARTED = 1; // The benchmark has not started yet.
+ private static final int NOT_STARTED = 0; // The benchmark has not started yet.
+ private static final int WARMUP = 1; // The benchmark is warming up.
private static final int RUNNING = 2; // The benchmark is running.
private static final int RUNNING_PAUSED = 3; // The benchmark is temporary paused.
private static final int FINISHED = 4; // The benchmark has stopped.
private int mState = NOT_STARTED; // Current benchmark state.
- private long mNanoPreviousTime = 0; // Previously captured System.nanoTime().
- private long mNanoFinishTime = 0; // Finish if System.nanoTime() returns after than this value.
- private long mNanoPausedTime = 0; // The System.nanoTime() when the pauseTiming() is called.
- private long mNanoPausedDuration = 0; // The duration of paused state in nano sec.
- private long mNanoTimeLimit = 1 * 1000 * 1000 * 1000; // 1 sec. Default time limit.
+ private static final long WARMUP_DURATION_NS = ms2ns(250); // warm-up for at least 250ms
+ private static final int WARMUP_MIN_ITERATIONS = 16; // minimum iterations to warm-up for
+
+ // TODO: Tune these values.
+ private static final long TARGET_TEST_DURATION_NS = ms2ns(500); // target testing for 500 ms
+ private static final int MAX_TEST_ITERATIONS = 1000000;
+ private static final int MIN_TEST_ITERATIONS = 100;
+ private static final int REPEAT_COUNT = 5;
+
+ private long mStartTimeNs = 0; // Previously captured System.nanoTime().
+ private long mPausedTimeNs = 0; // The System.nanoTime() when the pauseTiming() is called.
+ private long mPausedDurationNs = 0; // The duration of paused state in nano sec.
+
+ private int mIteration = 0;
+ private int mMaxIterations = 0;
+
+ private int mRepeatCount = 0;
// Statistics. These values will be filled when the benchmark has finished.
// The computation needs double precision, but long int is fine for final reporting.
private long mMedian = 0;
private double mMean = 0.0;
private double mStandardDeviation = 0.0;
-
- // Number of iterations needed for calculating the stats.
- private int mMinRepeatTimes = 16;
+ private long mMin = 0;
// Individual duration in nano seconds.
private ArrayList<Long> mResults = new ArrayList<>();
- /**
- * Sets the number of iterations needed for calculating the stats. Default is 16.
- */
- public void setMinRepeatTimes(int minRepeatTimes) {
- mMinRepeatTimes = minRepeatTimes;
+ private static final long ms2ns(long ms) {
+ return TimeUnit.MILLISECONDS.toNanos(ms);
}
/**
@@ -89,8 +98,13 @@
mMedian = size % 2 == 0 ? (mResults.get(size / 2) + mResults.get(size / 2 + 1)) / 2 :
mResults.get(size / 2);
+ mMin = mResults.get(0);
for (int i = 0; i < size; ++i) {
- mMean += mResults.get(i);
+ long result = mResults.get(i);
+ mMean += result;
+ if (result < mMin) {
+ mMin = result;
+ }
}
mMean /= (double) size;
@@ -108,7 +122,7 @@
throw new IllegalStateException(
"Unable to pause the benchmark. The benchmark has already paused.");
}
- mNanoPausedTime = System.nanoTime();
+ mPausedTimeNs = System.nanoTime();
mState = RUNNING_PAUSED;
}
@@ -119,11 +133,43 @@
throw new IllegalStateException(
"Unable to resume the benchmark. The benchmark is already running.");
}
- mNanoPausedDuration += System.nanoTime() - mNanoPausedTime;
- mNanoPausedTime = 0;
+ mPausedDurationNs += System.nanoTime() - mPausedTimeNs;
+ mPausedTimeNs = 0;
mState = RUNNING;
}
+ private void beginWarmup() {
+ mStartTimeNs = System.nanoTime();
+ mIteration = 0;
+ mState = WARMUP;
+ }
+
+ private void beginBenchmark(long warmupDuration, int iterations) {
+ mMaxIterations = (int) (TARGET_TEST_DURATION_NS / (warmupDuration / iterations));
+ mMaxIterations = Math.min(MAX_TEST_ITERATIONS,
+ Math.max(mMaxIterations, MIN_TEST_ITERATIONS));
+ mPausedDurationNs = 0;
+ mIteration = 0;
+ mRepeatCount = 0;
+ mState = RUNNING;
+ mStartTimeNs = System.nanoTime();
+ }
+
+ private boolean startNextTestRun() {
+ final long currentTime = System.nanoTime();
+ mResults.add((currentTime - mStartTimeNs - mPausedDurationNs) / mMaxIterations);
+ mRepeatCount++;
+ if (mRepeatCount >= REPEAT_COUNT) {
+ calculateSatistics();
+ mState = FINISHED;
+ return false;
+ }
+ mPausedDurationNs = 0;
+ mIteration = 0;
+ mStartTimeNs = System.nanoTime();
+ return true;
+ }
+
/**
* Judges whether the benchmark needs more samples.
*
@@ -132,23 +178,22 @@
public boolean keepRunning() {
switch (mState) {
case NOT_STARTED:
- mNanoPreviousTime = System.nanoTime();
- mNanoFinishTime = mNanoPreviousTime + mNanoTimeLimit;
- mState = RUNNING;
+ beginWarmup();
+ return true;
+ case WARMUP:
+ mIteration++;
+ // Only check nanoTime on every iteration in WARMUP since we
+ // don't yet have a target iteration count.
+ final long duration = System.nanoTime() - mStartTimeNs;
+ if (mIteration >= WARMUP_MIN_ITERATIONS && duration >= WARMUP_DURATION_NS) {
+ beginBenchmark(duration, mIteration);
+ }
return true;
case RUNNING:
- final long currentTime = System.nanoTime();
- mResults.add(currentTime - mNanoPreviousTime - mNanoPausedDuration);
- mNanoPausedDuration = 0;
-
- // To calculate statistics, needs two or more samples.
- if (mResults.size() > mMinRepeatTimes && currentTime > mNanoFinishTime) {
- calculateSatistics();
- mState = FINISHED;
- return false;
+ mIteration++;
+ if (mIteration >= mMaxIterations) {
+ return startNextTestRun();
}
-
- mNanoPreviousTime = currentTime;
return true;
case RUNNING_PAUSED:
throw new IllegalStateException(
@@ -161,21 +206,28 @@
}
}
- public long mean() {
+ private long mean() {
if (mState != FINISHED) {
throw new IllegalStateException("The benchmark hasn't finished");
}
return (long) mMean;
}
- public long median() {
+ private long median() {
if (mState != FINISHED) {
throw new IllegalStateException("The benchmark hasn't finished");
}
return mMedian;
}
- public long standardDeviation() {
+ private long min() {
+ if (mState != FINISHED) {
+ throw new IllegalStateException("The benchmark hasn't finished");
+ }
+ return mMin;
+ }
+
+ private long standardDeviation() {
if (mState != FINISHED) {
throw new IllegalStateException("The benchmark hasn't finished");
}
@@ -187,10 +239,11 @@
sb.append("Summary: ");
sb.append("median=").append(median()).append("ns, ");
sb.append("mean=").append(mean()).append("ns, ");
+ sb.append("min=").append(min()).append("ns, ");
sb.append("sigma=").append(standardDeviation()).append(", ");
sb.append("iteration=").append(mResults.size()).append(", ");
// print out the first few iterations' number for double checking.
- int sampleNumber = Math.min(mResults.size(), mMinRepeatTimes);
+ int sampleNumber = Math.min(mResults.size(), 16);
for (int i = 0; i < sampleNumber; i++) {
sb.append("No ").append(i).append(" result is ").append(mResults.get(i)).append(", ");
}
@@ -202,6 +255,7 @@
Bundle status = new Bundle();
status.putLong(key + "_median", median());
status.putLong(key + "_mean", mean());
+ status.putLong(key + "_min", min());
status.putLong(key + "_standardDeviation", standardDeviation());
instrumentation.sendStatus(Activity.RESULT_OK, status);
}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java b/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java
index 3933b57..64b0bf5 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/PerfStatusReporter.java
@@ -18,8 +18,9 @@
import android.support.test.InstrumentationRegistry;
-import org.junit.rules.TestWatcher;
+import org.junit.rules.TestRule;
import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -47,7 +48,7 @@
* name when using parameterization.
*/
-public class PerfStatusReporter extends TestWatcher {
+public class PerfStatusReporter implements TestRule {
private final BenchmarkState mState = new BenchmarkState();
public BenchmarkState getBenchmarkState() {
@@ -55,33 +56,39 @@
}
@Override
- protected void succeeded(Description description) {
- String invokeMethodName = description.getMethodName();
- // validate and simplify the function name.
- // First, remove the "test" prefix which normally comes from CTS test.
- // Then make sure the [subTestName] is valid, not just numbers like [0].
- if (invokeMethodName.startsWith("test")) {
- assertTrue("The test name " + invokeMethodName + " is too short",
- invokeMethodName.length() > 5);
- invokeMethodName = invokeMethodName.substring(4, 5).toLowerCase()
- + invokeMethodName.substring(5);
- }
-
- int index = invokeMethodName.lastIndexOf('[');
- if (index > 0) {
- boolean allDigits = true;
- for (int i = index + 1; i < invokeMethodName.length() - 1; i++) {
- if (!Character.isDigit(invokeMethodName.charAt(i))) {
- allDigits = false;
- break;
+ public Statement apply(Statement base, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ String invokeMethodName = description.getMethodName();
+ // validate and simplify the function name.
+ // First, remove the "test" prefix which normally comes from CTS test.
+ // Then make sure the [subTestName] is valid, not just numbers like [0].
+ if (invokeMethodName.startsWith("test")) {
+ assertTrue("The test name " + invokeMethodName + " is too short",
+ invokeMethodName.length() > 5);
+ invokeMethodName = invokeMethodName.substring(4, 5).toLowerCase()
+ + invokeMethodName.substring(5);
}
+
+ int index = invokeMethodName.lastIndexOf('[');
+ if (index > 0) {
+ boolean allDigits = true;
+ for (int i = index + 1; i < invokeMethodName.length() - 1; i++) {
+ if (!Character.isDigit(invokeMethodName.charAt(i))) {
+ allDigits = false;
+ break;
+ }
+ }
+ assertFalse("The name in [] can't contain only digits for " + invokeMethodName,
+ allDigits);
+ }
+
+ base.evaluate();
+
+ mState.sendFullStatusReport(InstrumentationRegistry.getInstrumentation(),
+ invokeMethodName);
}
- assertFalse("The name in [] can't contain only digits for " + invokeMethodName,
- allDigits);
- }
-
- mState.sendFullStatusReport(InstrumentationRegistry.getInstrumentation(),
- invokeMethodName);
+ };
}
-
}
diff --git a/api/current.txt b/api/current.txt
index 1cba3bc..a051efd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -855,6 +855,7 @@
field public static final int mediaRouteTypes = 16843694; // 0x10103ae
field public static final int menuCategory = 16843230; // 0x10101de
field public static final int mimeType = 16842790; // 0x1010026
+ field public static final int min = 16843367; // 0x1010267
field public static final int minDate = 16843583; // 0x101033f
field public static final int minEms = 16843098; // 0x101015a
field public static final int minHeight = 16843072; // 0x1010140
@@ -3265,6 +3266,7 @@
public class ValueAnimator extends android.animation.Animator {
ctor public ValueAnimator();
method public void addUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener);
+ method public static boolean areAnimatorsEnabled();
method public float getAnimatedFraction();
method public java.lang.Object getAnimatedValue();
method public java.lang.Object getAnimatedValue(java.lang.String);
@@ -21462,6 +21464,7 @@
field public static final int AMR_NB = 3; // 0x3
field public static final int AMR_WB = 4; // 0x4
field public static final int DEFAULT = 0; // 0x0
+ field public static final int MPEG_2_TS = 8; // 0x8
field public static final int MPEG_4 = 2; // 0x2
field public static final deprecated int RAW_AMR = 3; // 0x3
field public static final int THREE_GPP = 1; // 0x1
@@ -30306,6 +30309,8 @@
public final class PrintJobInfo implements android.os.Parcelable {
method public int describeContents();
+ method public int getAdvancedIntOption(java.lang.String);
+ method public java.lang.String getAdvancedStringOption(java.lang.String);
method public android.print.PrintAttributes getAttributes();
method public int getCopies();
method public long getCreationTime();
@@ -30314,6 +30319,7 @@
method public android.print.PageRange[] getPages();
method public android.print.PrinterId getPrinterId();
method public int getState();
+ method public boolean hasAdvancedOption(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
field public static final int STATE_BLOCKED = 4; // 0x4
@@ -31677,6 +31683,7 @@
method public static void notifyDirectoryChange(android.content.ContentResolver);
field public static final java.lang.String ACCOUNT_NAME = "accountName";
field public static final java.lang.String ACCOUNT_TYPE = "accountType";
+ field public static final java.lang.String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_directory";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact_directories";
field public static final android.net.Uri CONTENT_URI;
@@ -32571,7 +32578,7 @@
field public static final java.lang.String RADIO_CELL = "cell";
field public static final java.lang.String RADIO_NFC = "nfc";
field public static final java.lang.String RADIO_WIFI = "wifi";
- field public static final java.lang.String SHOW_PROCESSES = "show_processes";
+ field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
@@ -34847,6 +34854,7 @@
method public static void requestRebind(android.content.ComponentName);
method public final void requestUnbind();
method public final void setNotificationsShown(java.lang.String[]);
+ method public final void snoozeNotification(java.lang.String, long);
field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
@@ -36893,6 +36901,7 @@
field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
+ field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
@@ -45836,6 +45845,7 @@
method public deprecated void freeMemory();
method public android.net.http.SslCertificate getCertificate();
method public int getContentHeight();
+ method public static android.content.pm.PackageInfo getCurrentWebViewPackage();
method public android.graphics.Bitmap getFavicon();
method public android.webkit.WebView.HitTestResult getHitTestResult();
method public deprecated java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
@@ -45845,6 +45855,8 @@
method public android.webkit.WebSettings getSettings();
method public java.lang.String getTitle();
method public java.lang.String getUrl();
+ method public android.webkit.WebChromeClient getWebChromeClient();
+ method public android.webkit.WebViewClient getWebViewClient();
method public void goBack();
method public void goBackOrForward(int);
method public void goForward();
@@ -47467,6 +47479,7 @@
method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
method public android.view.animation.Interpolator getInterpolator();
method public synchronized int getMax();
+ method public synchronized int getMin();
method public synchronized int getProgress();
method public android.content.res.ColorStateList getProgressBackgroundTintList();
method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
@@ -47489,6 +47502,7 @@
method public void setInterpolator(android.content.Context, int);
method public void setInterpolator(android.view.animation.Interpolator);
method public synchronized void setMax(int);
+ method public synchronized void setMin(int);
method public synchronized void setProgress(int);
method public void setProgress(int, boolean);
method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
@@ -52072,6 +52086,8 @@
enum_constant public static final java.lang.annotation.ElementType PACKAGE;
enum_constant public static final java.lang.annotation.ElementType PARAMETER;
enum_constant public static final java.lang.annotation.ElementType TYPE;
+ enum_constant public static final java.lang.annotation.ElementType TYPE_PARAMETER;
+ enum_constant public static final java.lang.annotation.ElementType TYPE_USE;
}
public class IncompleteAnnotationException extends java.lang.RuntimeException {
@@ -52153,7 +52169,7 @@
method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
method public abstract java.lang.annotation.Annotation[] getAnnotations();
method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
- method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
+ method public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(java.lang.Class<T>);
method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
@@ -53278,8 +53294,6 @@
method public java.net.URLConnection openConnection(java.net.Proxy) throws java.io.IOException;
method public final java.io.InputStream openStream() throws java.io.IOException;
method public boolean sameFile(java.net.URL);
- method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String);
- method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
method public static void setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory);
method public java.lang.String toExternalForm();
method public java.net.URI toURI() throws java.net.URISyntaxException;
@@ -59422,8 +59436,10 @@
method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
method public java.lang.String getUnicodeLocaleType(java.lang.String);
method public java.lang.String getVariant();
+ method public boolean hasExtensions();
method public static synchronized void setDefault(java.util.Locale);
method public static synchronized void setDefault(java.util.Locale.Category, java.util.Locale);
+ method public java.util.Locale stripExtensions();
method public java.lang.String toLanguageTag();
method public final java.lang.String toString();
field public static final java.util.Locale CANADA;
diff --git a/api/system-current.txt b/api/system-current.txt
index fda07ae..ae0095d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -962,6 +962,7 @@
field public static final int mediaRouteTypes = 16843694; // 0x10103ae
field public static final int menuCategory = 16843230; // 0x10101de
field public static final int mimeType = 16842790; // 0x1010026
+ field public static final int min = 16843367; // 0x1010267
field public static final int minDate = 16843583; // 0x101033f
field public static final int minEms = 16843098; // 0x101015a
field public static final int minHeight = 16843072; // 0x1010140
@@ -3380,6 +3381,7 @@
public class ValueAnimator extends android.animation.Animator {
ctor public ValueAnimator();
method public void addUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener);
+ method public static boolean areAnimatorsEnabled();
method public float getAnimatedFraction();
method public java.lang.Object getAnimatedValue();
method public java.lang.Object getAnimatedValue(java.lang.String);
@@ -22994,6 +22996,7 @@
field public static final int AMR_NB = 3; // 0x3
field public static final int AMR_WB = 4; // 0x4
field public static final int DEFAULT = 0; // 0x0
+ field public static final int MPEG_2_TS = 8; // 0x8
field public static final int MPEG_4 = 2; // 0x2
field public static final deprecated int RAW_AMR = 3; // 0x3
field public static final int THREE_GPP = 1; // 0x1
@@ -32906,6 +32909,8 @@
public final class PrintJobInfo implements android.os.Parcelable {
method public int describeContents();
+ method public int getAdvancedIntOption(java.lang.String);
+ method public java.lang.String getAdvancedStringOption(java.lang.String);
method public android.print.PrintAttributes getAttributes();
method public int getCopies();
method public long getCreationTime();
@@ -32914,6 +32919,7 @@
method public android.print.PageRange[] getPages();
method public android.print.PrinterId getPrinterId();
method public int getState();
+ method public boolean hasAdvancedOption(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
field public static final int STATE_BLOCKED = 4; // 0x4
@@ -34301,6 +34307,7 @@
method public static void notifyDirectoryChange(android.content.ContentResolver);
field public static final java.lang.String ACCOUNT_NAME = "accountName";
field public static final java.lang.String ACCOUNT_TYPE = "accountType";
+ field public static final java.lang.String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_directory";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact_directories";
field public static final android.net.Uri CONTENT_URI;
@@ -35328,7 +35335,7 @@
field public static final java.lang.String RADIO_CELL = "cell";
field public static final java.lang.String RADIO_NFC = "nfc";
field public static final java.lang.String RADIO_WIFI = "wifi";
- field public static final java.lang.String SHOW_PROCESSES = "show_processes";
+ field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on";
field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
@@ -37627,6 +37634,7 @@
method public final void requestUnbind();
method public final void setNotificationsShown(java.lang.String[]);
method public final void setOnNotificationPostedTrim(int);
+ method public final void snoozeNotification(java.lang.String, long);
method public void unregisterAsSystemService() throws android.os.RemoteException;
field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
@@ -37688,6 +37696,7 @@
field public static final int REASON_PACKAGE_CHANGED = 5; // 0x5
field public static final int REASON_PACKAGE_SUSPENDED = 14; // 0xe
field public static final int REASON_PROFILE_TURNED_OFF = 15; // 0xf
+ field public static final int REASON_SNOOZED = 18; // 0x12
field public static final int REASON_UNAUTOBUNDLED = 16; // 0x10
field public static final int REASON_USER_STOPPED = 6; // 0x6
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationRankerService";
@@ -39984,6 +39993,7 @@
field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
+ field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
@@ -49112,6 +49122,7 @@
method public deprecated void freeMemory();
method public android.net.http.SslCertificate getCertificate();
method public int getContentHeight();
+ method public static android.content.pm.PackageInfo getCurrentWebViewPackage();
method public android.graphics.Bitmap getFavicon();
method public android.webkit.WebView.HitTestResult getHitTestResult();
method public deprecated java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
@@ -49121,6 +49132,8 @@
method public android.webkit.WebSettings getSettings();
method public java.lang.String getTitle();
method public java.lang.String getUrl();
+ method public android.webkit.WebChromeClient getWebChromeClient();
+ method public android.webkit.WebViewClient getWebViewClient();
method public android.webkit.WebViewProvider getWebViewProvider();
method public void goBack();
method public void goBackOrForward(int);
@@ -49401,6 +49414,8 @@
method public abstract java.lang.String getUrl();
method public abstract android.webkit.WebViewProvider.ViewDelegate getViewDelegate();
method public abstract int getVisibleTitleHeight();
+ method public abstract android.webkit.WebChromeClient getWebChromeClient();
+ method public abstract android.webkit.WebViewClient getWebViewClient();
method public abstract android.view.View getZoomControls();
method public abstract void goBack();
method public abstract void goBackOrForward(int);
@@ -51004,6 +51019,7 @@
method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
method public android.view.animation.Interpolator getInterpolator();
method public synchronized int getMax();
+ method public synchronized int getMin();
method public synchronized int getProgress();
method public android.content.res.ColorStateList getProgressBackgroundTintList();
method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
@@ -51026,6 +51042,7 @@
method public void setInterpolator(android.content.Context, int);
method public void setInterpolator(android.view.animation.Interpolator);
method public synchronized void setMax(int);
+ method public synchronized void setMin(int);
method public synchronized void setProgress(int);
method public void setProgress(int, boolean);
method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
@@ -55609,6 +55626,8 @@
enum_constant public static final java.lang.annotation.ElementType PACKAGE;
enum_constant public static final java.lang.annotation.ElementType PARAMETER;
enum_constant public static final java.lang.annotation.ElementType TYPE;
+ enum_constant public static final java.lang.annotation.ElementType TYPE_PARAMETER;
+ enum_constant public static final java.lang.annotation.ElementType TYPE_USE;
}
public class IncompleteAnnotationException extends java.lang.RuntimeException {
@@ -55690,7 +55709,7 @@
method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
method public abstract java.lang.annotation.Annotation[] getAnnotations();
method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
- method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
+ method public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(java.lang.Class<T>);
method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
@@ -56815,8 +56834,6 @@
method public java.net.URLConnection openConnection(java.net.Proxy) throws java.io.IOException;
method public final java.io.InputStream openStream() throws java.io.IOException;
method public boolean sameFile(java.net.URL);
- method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String);
- method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
method public static void setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory);
method public java.lang.String toExternalForm();
method public java.net.URI toURI() throws java.net.URISyntaxException;
@@ -62959,8 +62976,10 @@
method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
method public java.lang.String getUnicodeLocaleType(java.lang.String);
method public java.lang.String getVariant();
+ method public boolean hasExtensions();
method public static synchronized void setDefault(java.util.Locale);
method public static synchronized void setDefault(java.util.Locale.Category, java.util.Locale);
+ method public java.util.Locale stripExtensions();
method public java.lang.String toLanguageTag();
method public final java.lang.String toString();
field public static final java.util.Locale CANADA;
diff --git a/api/test-current.txt b/api/test-current.txt
index 9d07feb..4a65a7f 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -855,6 +855,7 @@
field public static final int mediaRouteTypes = 16843694; // 0x10103ae
field public static final int menuCategory = 16843230; // 0x10101de
field public static final int mimeType = 16842790; // 0x1010026
+ field public static final int min = 16843367; // 0x1010267
field public static final int minDate = 16843583; // 0x101033f
field public static final int minEms = 16843098; // 0x101015a
field public static final int minHeight = 16843072; // 0x1010140
@@ -3265,6 +3266,7 @@
public class ValueAnimator extends android.animation.Animator {
ctor public ValueAnimator();
method public void addUpdateListener(android.animation.ValueAnimator.AnimatorUpdateListener);
+ method public static boolean areAnimatorsEnabled();
method public float getAnimatedFraction();
method public java.lang.Object getAnimatedValue();
method public java.lang.Object getAnimatedValue(java.lang.String);
@@ -21535,6 +21537,7 @@
field public static final int AMR_NB = 3; // 0x3
field public static final int AMR_WB = 4; // 0x4
field public static final int DEFAULT = 0; // 0x0
+ field public static final int MPEG_2_TS = 8; // 0x8
field public static final int MPEG_4 = 2; // 0x2
field public static final deprecated int RAW_AMR = 3; // 0x3
field public static final int THREE_GPP = 1; // 0x1
@@ -30381,6 +30384,8 @@
public final class PrintJobInfo implements android.os.Parcelable {
method public int describeContents();
+ method public int getAdvancedIntOption(java.lang.String);
+ method public java.lang.String getAdvancedStringOption(java.lang.String);
method public android.print.PrintAttributes getAttributes();
method public int getCopies();
method public long getCreationTime();
@@ -30391,6 +30396,7 @@
method public float getProgress();
method public int getState();
method public java.lang.CharSequence getStatus(android.content.pm.PackageManager);
+ method public boolean hasAdvancedOption(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR;
field public static final int STATE_BLOCKED = 4; // 0x4
@@ -31755,6 +31761,7 @@
method public static void notifyDirectoryChange(android.content.ContentResolver);
field public static final java.lang.String ACCOUNT_NAME = "accountName";
field public static final java.lang.String ACCOUNT_TYPE = "accountType";
+ field public static final java.lang.String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_directory";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact_directories";
field public static final android.net.Uri CONTENT_URI;
@@ -32649,7 +32656,7 @@
field public static final java.lang.String RADIO_CELL = "cell";
field public static final java.lang.String RADIO_NFC = "nfc";
field public static final java.lang.String RADIO_WIFI = "wifi";
- field public static final java.lang.String SHOW_PROCESSES = "show_processes";
+ field public static final deprecated java.lang.String SHOW_PROCESSES = "show_processes";
field public static final java.lang.String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
field public static final java.lang.String TRANSITION_ANIMATION_SCALE = "transition_animation_scale";
field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
@@ -34928,6 +34935,7 @@
method public static void requestRebind(android.content.ComponentName);
method public final void requestUnbind();
method public final void setNotificationsShown(java.lang.String[]);
+ method public final void snoozeNotification(java.lang.String, long);
field public static final int HINT_HOST_DISABLE_CALL_EFFECTS = 4; // 0x4
field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
field public static final int HINT_HOST_DISABLE_NOTIFICATION_EFFECTS = 2; // 0x2
@@ -36974,6 +36982,7 @@
field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
+ field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
@@ -41018,6 +41027,156 @@
}
+package android.util.proto {
+
+ public final class EncodedBuffer {
+ ctor public EncodedBuffer();
+ ctor public EncodedBuffer(int);
+ method public void dumpBuffers(java.lang.String);
+ method public static void dumpByteString(java.lang.String, java.lang.String, byte[]);
+ method public void editRawFixed32(int, int);
+ method public byte[] getBytes(int);
+ method public int getChunkCount();
+ method public java.lang.String getDebugString();
+ method public int getRawFixed32At(int);
+ method public static int getRawVarint32Size(int);
+ method public static int getRawVarint64Size(long);
+ method public static int getRawZigZag32Size(int);
+ method public static int getRawZigZag64Size(long);
+ method public int getReadPos();
+ method public int getReadableSize();
+ method public int getWriteBufIndex();
+ method public int getWriteIndex();
+ method public int getWritePos();
+ method public byte readRawByte();
+ method public int readRawFixed32();
+ method public long readRawUnsigned();
+ method public void rewindRead();
+ method public void rewindWriteTo(int);
+ method public void skipRead(int);
+ method public void startEditing();
+ method public void writeFromThisBuffer(int, int);
+ method public void writeRawBuffer(byte[]);
+ method public void writeRawBuffer(byte[], int, int);
+ method public void writeRawByte(byte);
+ method public void writeRawFixed32(int);
+ method public void writeRawFixed64(long);
+ method public void writeRawVarint32(int);
+ method public void writeRawVarint64(long);
+ method public void writeRawZigZag32(int);
+ method public void writeRawZigZag64(long);
+ }
+
+ public final class ProtoOutputStream {
+ ctor public ProtoOutputStream();
+ ctor public ProtoOutputStream(int);
+ method public static int checkFieldId(long, long);
+ method public static int convertObjectIdToOrdinal(int);
+ method public void dump(java.lang.String);
+ method public void endObject(long);
+ method public void endRepeatedObject(long);
+ method public byte[] getBytes();
+ method public static int getDepthFromToken(long);
+ method public static int getObjectIdFromToken(long);
+ method public static boolean getRepeatedFromToken(long);
+ method public static int getSizePosFromToken(long);
+ method public static int getTagSizeFromToken(long);
+ method public static long makeFieldId(int, long);
+ method public static long makeToken(int, boolean, int, int, int);
+ method public long startObject(long);
+ method public long startRepeatedObject(long);
+ method public static java.lang.String token2String(long);
+ method public void writeBool(long, boolean);
+ method public void writeBytes(long, byte[]);
+ method public void writeDouble(long, double);
+ method public void writeEnum(long, int);
+ method public void writeFixed32(long, int);
+ method public void writeFixed64(long, long);
+ method public void writeFloat(long, float);
+ method public void writeInt32(long, int);
+ method public void writeInt64(long, long);
+ method public void writePackedBool(long, boolean[]);
+ method public void writePackedDouble(long, double[]);
+ method public void writePackedEnum(long, int[]);
+ method public void writePackedFixed32(long, int[]);
+ method public void writePackedFixed64(long, long[]);
+ method public void writePackedFloat(long, float[]);
+ method public void writePackedInt32(long, int[]);
+ method public void writePackedInt64(long, long[]);
+ method public void writePackedSFixed32(long, int[]);
+ method public void writePackedSFixed64(long, long[]);
+ method public void writePackedSInt32(long, int[]);
+ method public void writePackedSInt64(long, long[]);
+ method public void writePackedUInt32(long, int[]);
+ method public void writePackedUInt64(long, long[]);
+ method public void writeRepeatedBool(long, boolean);
+ method public void writeRepeatedBytes(long, byte[]);
+ method public void writeRepeatedDouble(long, double);
+ method public void writeRepeatedEnum(long, int);
+ method public void writeRepeatedFixed32(long, int);
+ method public void writeRepeatedFixed64(long, long);
+ method public void writeRepeatedFloat(long, float);
+ method public void writeRepeatedInt32(long, int);
+ method public void writeRepeatedInt64(long, long);
+ method public void writeRepeatedSFixed32(long, int);
+ method public void writeRepeatedSFixed64(long, long);
+ method public void writeRepeatedSInt32(long, int);
+ method public void writeRepeatedSInt64(long, long);
+ method public void writeRepeatedString(long, java.lang.String);
+ method public void writeRepeatedUInt32(long, int);
+ method public void writeRepeatedUInt64(long, long);
+ method public void writeSFixed32(long, int);
+ method public void writeSFixed64(long, long);
+ method public void writeSInt32(long, int);
+ method public void writeSInt64(long, long);
+ method public void writeString(long, java.lang.String);
+ method public void writeTag(int, int);
+ method public void writeUInt32(long, int);
+ method public void writeUInt64(long, long);
+ field public static final long FIELD_COUNT_MASK = 16492674416640L; // 0xf0000000000L
+ field public static final long FIELD_COUNT_PACKED = 5497558138880L; // 0x50000000000L
+ field public static final long FIELD_COUNT_REPEATED = 2199023255552L; // 0x20000000000L
+ field public static final int FIELD_COUNT_SHIFT = 40; // 0x28
+ field public static final long FIELD_COUNT_SINGLE = 1099511627776L; // 0x10000000000L
+ field public static final long FIELD_COUNT_UNKNOWN = 0L; // 0x0L
+ field public static final int FIELD_ID_MASK = -8; // 0xfffffff8
+ field public static final int FIELD_ID_SHIFT = 3; // 0x3
+ field public static final long FIELD_TYPE_BOOL = 55834574848L; // 0xd00000000L
+ field public static final long FIELD_TYPE_BYTES = 64424509440L; // 0xf00000000L
+ field public static final long FIELD_TYPE_DOUBLE = 4294967296L; // 0x100000000L
+ field public static final long FIELD_TYPE_ENUM = 68719476736L; // 0x1000000000L
+ field public static final long FIELD_TYPE_FIXED32 = 38654705664L; // 0x900000000L
+ field public static final long FIELD_TYPE_FIXED64 = 42949672960L; // 0xa00000000L
+ field public static final long FIELD_TYPE_FLOAT = 8589934592L; // 0x200000000L
+ field public static final long FIELD_TYPE_INT32 = 12884901888L; // 0x300000000L
+ field public static final long FIELD_TYPE_INT64 = 17179869184L; // 0x400000000L
+ field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
+ field public static final long FIELD_TYPE_OBJECT = 73014444032L; // 0x1100000000L
+ field public static final long FIELD_TYPE_SFIXED32 = 47244640256L; // 0xb00000000L
+ field public static final long FIELD_TYPE_SFIXED64 = 51539607552L; // 0xc00000000L
+ field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
+ field public static final long FIELD_TYPE_SINT32 = 30064771072L; // 0x700000000L
+ field public static final long FIELD_TYPE_SINT64 = 34359738368L; // 0x800000000L
+ field public static final long FIELD_TYPE_STRING = 60129542144L; // 0xe00000000L
+ field public static final long FIELD_TYPE_UINT32 = 21474836480L; // 0x500000000L
+ field public static final long FIELD_TYPE_UINT64 = 25769803776L; // 0x600000000L
+ field public static final long FIELD_TYPE_UNKNOWN = 0L; // 0x0L
+ field public static final java.lang.String TAG = "ProtoOutputStream";
+ field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4
+ field public static final int WIRE_TYPE_FIXED32 = 5; // 0x5
+ field public static final int WIRE_TYPE_FIXED64 = 1; // 0x1
+ field public static final int WIRE_TYPE_LENGTH_DELIMITED = 2; // 0x2
+ field public static final int WIRE_TYPE_MASK = 7; // 0x7
+ field public static final int WIRE_TYPE_START_GROUP = 3; // 0x3
+ field public static final int WIRE_TYPE_VARINT = 0; // 0x0
+ }
+
+ public class ProtoParseException extends java.lang.RuntimeException {
+ ctor public ProtoParseException(java.lang.String);
+ }
+
+}
+
package android.view {
public abstract class AbsSavedState implements android.os.Parcelable {
@@ -45924,6 +46083,7 @@
method public deprecated void freeMemory();
method public android.net.http.SslCertificate getCertificate();
method public int getContentHeight();
+ method public static android.content.pm.PackageInfo getCurrentWebViewPackage();
method public android.graphics.Bitmap getFavicon();
method public android.webkit.WebView.HitTestResult getHitTestResult();
method public deprecated java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
@@ -45933,6 +46093,8 @@
method public android.webkit.WebSettings getSettings();
method public java.lang.String getTitle();
method public java.lang.String getUrl();
+ method public android.webkit.WebChromeClient getWebChromeClient();
+ method public android.webkit.WebViewClient getWebViewClient();
method public void goBack();
method public void goBackOrForward(int);
method public void goForward();
@@ -47560,6 +47722,7 @@
method public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
method public android.view.animation.Interpolator getInterpolator();
method public synchronized int getMax();
+ method public synchronized int getMin();
method public synchronized int getProgress();
method public android.content.res.ColorStateList getProgressBackgroundTintList();
method public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
@@ -47582,6 +47745,7 @@
method public void setInterpolator(android.content.Context, int);
method public void setInterpolator(android.view.animation.Interpolator);
method public synchronized void setMax(int);
+ method public synchronized void setMin(int);
method public synchronized void setProgress(int);
method public void setProgress(int, boolean);
method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
@@ -52174,6 +52338,8 @@
enum_constant public static final java.lang.annotation.ElementType PACKAGE;
enum_constant public static final java.lang.annotation.ElementType PARAMETER;
enum_constant public static final java.lang.annotation.ElementType TYPE;
+ enum_constant public static final java.lang.annotation.ElementType TYPE_PARAMETER;
+ enum_constant public static final java.lang.annotation.ElementType TYPE_USE;
}
public class IncompleteAnnotationException extends java.lang.RuntimeException {
@@ -52255,7 +52421,7 @@
method public abstract <T extends java.lang.annotation.Annotation> T getAnnotation(java.lang.Class<T>);
method public abstract java.lang.annotation.Annotation[] getAnnotations();
method public default <T extends java.lang.annotation.Annotation> T[] getAnnotationsByType(java.lang.Class<T>);
- method public default <T extends java.lang.annotation.Annotation> java.lang.annotation.Annotation getDeclaredAnnotation(java.lang.Class<T>);
+ method public default <T extends java.lang.annotation.Annotation> T getDeclaredAnnotation(java.lang.Class<T>);
method public abstract java.lang.annotation.Annotation[] getDeclaredAnnotations();
method public default <T extends java.lang.annotation.Annotation> T[] getDeclaredAnnotationsByType(java.lang.Class<T>);
method public default boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
@@ -53380,8 +53546,6 @@
method public java.net.URLConnection openConnection(java.net.Proxy) throws java.io.IOException;
method public final java.io.InputStream openStream() throws java.io.IOException;
method public boolean sameFile(java.net.URL);
- method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String);
- method protected void set(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
method public static void setURLStreamHandlerFactory(java.net.URLStreamHandlerFactory);
method public java.lang.String toExternalForm();
method public java.net.URI toURI() throws java.net.URISyntaxException;
@@ -59524,8 +59688,10 @@
method public java.util.Set<java.lang.String> getUnicodeLocaleKeys();
method public java.lang.String getUnicodeLocaleType(java.lang.String);
method public java.lang.String getVariant();
+ method public boolean hasExtensions();
method public static synchronized void setDefault(java.util.Locale);
method public static synchronized void setDefault(java.util.Locale.Category, java.util.Locale);
+ method public java.util.Locale stripExtensions();
method public java.lang.String toLanguageTag();
method public final java.lang.String toString();
field public static final java.util.Locale CANADA;
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 3759de2..e197bfc 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -63,6 +63,7 @@
import android.text.TextUtils;
import android.util.AndroidException;
import android.util.ArrayMap;
+import android.util.Log;
import android.view.IWindowManager;
import com.android.internal.os.BaseCommand;
@@ -385,78 +386,12 @@
String op = nextArgRequired();
- if (op.equals("start")) {
- runAmCmd(getRawArgs());
- } else if (op.equals("startservice")) {
- runStartService();
- } else if (op.equals("stopservice")) {
- runStopService();
- } else if (op.equals("force-stop") || op.equals("kill") || op.equals("kill-all")) {
- runAmCmd(getRawArgs());
+ if (op.equals("broadcast")) {
+ sendBroadcast();
} else if (op.equals("instrument")) {
runInstrument();
- } else if (op.equals("trace-ipc")) {
- runTraceIpc();
- } else if (op.equals("broadcast")) {
- sendBroadcast();
- } else if (op.equals("profile")) {
- runProfile();
- } else if (op.equals("dumpheap")) {
- runDumpHeap();
- } else if (op.equals("set-debug-app")) {
- runSetDebugApp();
- } else if (op.equals("clear-debug-app")) {
- runClearDebugApp();
- } else if (op.equals("set-watch-heap")) {
- runSetWatchHeap();
- } else if (op.equals("clear-watch-heap")) {
- runClearWatchHeap();
- } else if (op.equals("bug-report")) {
- runBugReport();
- } else if (op.equals("monitor")) {
- runMonitor();
- } else if (op.equals("hang")) {
- runHang();
- } else if (op.equals("restart")) {
- runRestart();
- } else if (op.equals("idle-maintenance")) {
- runIdleMaintenance();
- } else if (op.equals("screen-compat")) {
- runScreenCompat();
- } else if (op.equals("package-importance")) {
- runPackageImportance();
- } else if (op.equals("to-uri")) {
- runToUri(0);
- } else if (op.equals("to-intent-uri")) {
- runToUri(Intent.URI_INTENT_SCHEME);
- } else if (op.equals("to-app-uri")) {
- runToUri(Intent.URI_ANDROID_APP_SCHEME);
- } else if (op.equals("switch-user")) {
- runSwitchUser();
- } else if (op.equals("start-user")) {
- runStartUserInBackground();
- } else if (op.equals("unlock-user")) {
- runUnlockUser();
- } else if (op.equals("stop-user")) {
- runStopUser();
- } else if (op.equals("stack")) {
- runStack();
- } else if (op.equals("task")) {
- runTask();
- } else if (op.equals("get-config")) {
- runGetConfig();
- } else if (op.equals("suppress-resize-config-changes")) {
- runSuppressResizeConfigChanges();
- } else if (op.equals("set-inactive")) {
- runSetInactive();
- } else if (op.equals("get-inactive")) {
- runGetInactive();
- } else if (op.equals("send-trim-memory")) {
- runSendTrimMemory();
- } else if (op.equals("get-current-user")) {
- runGetCurrentUser();
} else {
- showError("Error: unknown command '" + op + "'");
+ runAmCmd(getRawArgs());
}
}
@@ -473,7 +408,13 @@
}
static final class MyShellCallback extends ShellCallback {
+ boolean mActive = true;
+
@Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {
+ if (!mActive) {
+ System.err.println("Open attempt after active for: " + path);
+ return null;
+ }
File file = new File(path);
//System.err.println("Opening file: " + file.getAbsolutePath());
//Log.i("Am", "Opening file: " + file.getAbsolutePath());
@@ -506,12 +447,15 @@
}
void runAmCmd(String[] args) throws AndroidException {
+ final MyShellCallback cb = new MyShellCallback();
try {
mAm.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
- args, new MyShellCallback(), new ResultReceiver(null) { });
+ args, cb, new ResultReceiver(null) { });
} catch (RemoteException e) {
System.err.println(NO_SYSTEM_ERROR_CODE);
throw new AndroidException("Can't call activity manager; is the system running?");
+ } finally {
+ cb.mActive = false;
}
}
@@ -550,7 +494,7 @@
} else if (opt.equals("--track-allocation")) {
mStartFlags |= ActivityManager.START_FLAG_TRACK_ALLOCATION;
} else if (opt.equals("--user")) {
- mUserId = parseUserArg(nextArgRequired());
+ mUserId = UserHandle.parseUserArg(nextArgRequired());
} else if (opt.equals("--receiver-permission")) {
mReceiverPermission = nextArgRequired();
} else if (opt.equals("--stack")) {
@@ -563,38 +507,28 @@
});
}
- private void runStartService() throws Exception {
- Intent intent = makeIntent(UserHandle.USER_CURRENT);
- if (mUserId == UserHandle.USER_ALL) {
- System.err.println("Error: Can't start activity with user 'all'");
- return;
- }
- System.out.println("Starting service: " + intent);
- ComponentName cn = mAm.startService(null, intent, intent.getType(),
- SHELL_PACKAGE_NAME, mUserId);
- if (cn == null) {
- System.err.println("Error: Not found; no service started.");
- } else if (cn.getPackageName().equals("!")) {
- System.err.println("Error: Requires permission " + cn.getClassName());
- } else if (cn.getPackageName().equals("!!")) {
- System.err.println("Error: " + cn.getClassName());
- }
- }
+ private class IntentReceiver extends IIntentReceiver.Stub {
+ private boolean mFinished = false;
- private void runStopService() throws Exception {
- Intent intent = makeIntent(UserHandle.USER_CURRENT);
- if (mUserId == UserHandle.USER_ALL) {
- System.err.println("Error: Can't stop activity with user 'all'");
- return;
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
+ boolean ordered, boolean sticky, int sendingUser) {
+ String line = "Broadcast completed: result=" + resultCode;
+ if (data != null) line = line + ", data=\"" + data + "\"";
+ if (extras != null) line = line + ", extras: " + extras;
+ System.out.println(line);
+ synchronized (this) {
+ mFinished = true;
+ notifyAll();
+ }
}
- System.out.println("Stopping service: " + intent);
- int result = mAm.stopService(null, intent, intent.getType(), mUserId);
- if (result == 0) {
- System.err.println("Service not stopped: was not running.");
- } else if (result == 1) {
- System.err.println("Service stopped");
- } else if (result == -1) {
- System.err.println("Error stopping service");
+
+ public synchronized void waitForFinish() {
+ try {
+ while (!mFinished) wait();
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
}
}
@@ -736,773 +670,6 @@
}
}
- private void runTraceIpc() throws Exception {
- String op = nextArgRequired();
- if (op.equals("start")) {
- runTraceIpcStart();
- } else if (op.equals("stop")) {
- runTraceIpcStop();
- } else {
- showError("Error: unknown command '" + op + "'");
- return;
- }
- }
-
- private void runTraceIpcStart() throws Exception {
- System.out.println("Starting IPC tracing.");
- mAm.startBinderTracking();
- }
-
- private void runTraceIpcStop() throws Exception {
- String opt;
- String filename = null;
- while ((opt=nextOption()) != null) {
- if (opt.equals("--dump-file")) {
- filename = nextArgRequired();
- } else {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
- }
- if (filename == null) {
- System.err.println("Error: Specify filename to dump logs to.");
- return;
- }
-
- ParcelFileDescriptor fd = null;
-
- try {
- File file = new File(filename);
- file.delete();
- fd = openForSystemServer(file,
- ParcelFileDescriptor.MODE_CREATE |
- ParcelFileDescriptor.MODE_TRUNCATE |
- ParcelFileDescriptor.MODE_WRITE_ONLY);
- } catch (FileNotFoundException e) {
- System.err.println("Error: Unable to open file: " + filename);
- System.err.println("Consider using a file under /data/local/tmp/");
- return;
- }
-
- ;
- if (!mAm.stopBinderTrackingAndDump(fd)) {
- throw new AndroidException("STOP TRACE FAILED.");
- }
-
- System.out.println("Stopped IPC tracing. Dumping logs to: " + filename);
- }
-
- static void removeWallOption() {
- String props = SystemProperties.get("dalvik.vm.extra-opts");
- if (props != null && props.contains("-Xprofile:wallclock")) {
- props = props.replace("-Xprofile:wallclock", "");
- props = props.trim();
- SystemProperties.set("dalvik.vm.extra-opts", props);
- }
- }
-
- private void runProfile() throws Exception {
- String profileFile = null;
- boolean start = false;
- boolean wall = false;
- int userId = UserHandle.USER_CURRENT;
- int profileType = 0;
- mSamplingInterval = 0;
-
- String process = null;
-
- String cmd = nextArgRequired();
-
- if ("start".equals(cmd)) {
- start = true;
- String opt;
- while ((opt=nextOption()) != null) {
- if (opt.equals("--user")) {
- userId = parseUserArg(nextArgRequired());
- } else if (opt.equals("--wall")) {
- wall = true;
- } else if (opt.equals("--sampling")) {
- mSamplingInterval = Integer.parseInt(nextArgRequired());
- } else {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
- }
- process = nextArgRequired();
- } else if ("stop".equals(cmd)) {
- String opt;
- while ((opt=nextOption()) != null) {
- if (opt.equals("--user")) {
- userId = parseUserArg(nextArgRequired());
- } else {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
- }
- process = nextArg();
- } else {
- // Compatibility with old syntax: process is specified first.
- process = cmd;
- cmd = nextArgRequired();
- if ("start".equals(cmd)) {
- start = true;
- } else if (!"stop".equals(cmd)) {
- throw new IllegalArgumentException("Profile command " + process + " not valid");
- }
- }
-
- if (userId == UserHandle.USER_ALL) {
- System.err.println("Error: Can't profile with user 'all'");
- return;
- }
-
- ParcelFileDescriptor fd = null;
- ProfilerInfo profilerInfo = null;
-
- if (start) {
- profileFile = nextArgRequired();
- try {
- fd = openForSystemServer(
- new File(profileFile),
- ParcelFileDescriptor.MODE_CREATE |
- ParcelFileDescriptor.MODE_TRUNCATE |
- ParcelFileDescriptor.MODE_WRITE_ONLY);
- } catch (FileNotFoundException e) {
- System.err.println("Error: Unable to open file: " + profileFile);
- System.err.println("Consider using a file under /data/local/tmp/");
- return;
- }
- profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false);
- }
-
- try {
- if (wall) {
- // XXX doesn't work -- this needs to be set before booting.
- String props = SystemProperties.get("dalvik.vm.extra-opts");
- if (props == null || !props.contains("-Xprofile:wallclock")) {
- props = props + " -Xprofile:wallclock";
- //SystemProperties.set("dalvik.vm.extra-opts", props);
- }
- } else if (start) {
- //removeWallOption();
- }
- if (!mAm.profileControl(process, userId, start, profilerInfo, profileType)) {
- wall = false;
- throw new AndroidException("PROFILE FAILED on process " + process);
- }
- } finally {
- if (!wall) {
- //removeWallOption();
- }
- }
- }
-
- private void runDumpHeap() throws Exception {
- boolean managed = true;
- int userId = UserHandle.USER_CURRENT;
-
- String opt;
- while ((opt=nextOption()) != null) {
- if (opt.equals("--user")) {
- userId = parseUserArg(nextArgRequired());
- if (userId == UserHandle.USER_ALL) {
- System.err.println("Error: Can't dump heap with user 'all'");
- return;
- }
- } else if (opt.equals("-n")) {
- managed = false;
- } else {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
- }
- String process = nextArgRequired();
- String heapFile = nextArgRequired();
- ParcelFileDescriptor fd = null;
-
- try {
- File file = new File(heapFile);
- file.delete();
- fd = openForSystemServer(file,
- ParcelFileDescriptor.MODE_CREATE |
- ParcelFileDescriptor.MODE_TRUNCATE |
- ParcelFileDescriptor.MODE_WRITE_ONLY);
- } catch (FileNotFoundException e) {
- System.err.println("Error: Unable to open file: " + heapFile);
- System.err.println("Consider using a file under /data/local/tmp/");
- return;
- }
-
- if (!mAm.dumpHeap(process, userId, managed, heapFile, fd)) {
- throw new AndroidException("HEAP DUMP FAILED on process " + process);
- }
- }
-
- private void runSetDebugApp() throws Exception {
- boolean wait = false;
- boolean persistent = false;
-
- String opt;
- while ((opt=nextOption()) != null) {
- if (opt.equals("-w")) {
- wait = true;
- } else if (opt.equals("--persistent")) {
- persistent = true;
- } else {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
- }
-
- String pkg = nextArgRequired();
- mAm.setDebugApp(pkg, wait, persistent);
- }
-
- private void runClearDebugApp() throws Exception {
- mAm.setDebugApp(null, false, true);
- }
-
- private void runSetWatchHeap() throws Exception {
- String proc = nextArgRequired();
- String limit = nextArgRequired();
- mAm.setDumpHeapDebugLimit(proc, 0, Long.parseLong(limit), null);
- }
-
- private void runClearWatchHeap() throws Exception {
- String proc = nextArgRequired();
- mAm.setDumpHeapDebugLimit(proc, 0, -1, null);
- }
-
- private void runBugReport() throws Exception {
- String opt;
- int bugreportType = ActivityManager.BUGREPORT_OPTION_FULL;
- while ((opt=nextOption()) != null) {
- if (opt.equals("--progress")) {
- bugreportType = ActivityManager.BUGREPORT_OPTION_INTERACTIVE;
- } else {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
- }
- mAm.requestBugReport(bugreportType);
- System.out.println("Your lovely bug report is being created; please be patient.");
- }
-
- private void runSwitchUser() throws Exception {
- String user = nextArgRequired();
- mAm.switchUser(Integer.parseInt(user));
- }
-
- private void runStartUserInBackground() throws Exception {
- String user = nextArgRequired();
- boolean success = mAm.startUserInBackground(Integer.parseInt(user));
- if (success) {
- System.out.println("Success: user started");
- } else {
- System.err.println("Error: could not start user");
- }
- }
-
- private byte[] argToBytes(String arg) {
- if (arg.equals("!")) {
- return null;
- } else {
- return HexDump.hexStringToByteArray(arg);
- }
- }
-
- private void runUnlockUser() throws Exception {
- int userId = Integer.parseInt(nextArgRequired());
- byte[] token = argToBytes(nextArgRequired());
- byte[] secret = argToBytes(nextArgRequired());
- boolean success = mAm.unlockUser(userId, token, secret, null);
- if (success) {
- System.out.println("Success: user unlocked");
- } else {
- System.err.println("Error: could not unlock user");
- }
- }
-
- private static class StopUserCallback extends IStopUserCallback.Stub {
- private boolean mFinished = false;
-
- public synchronized void waitForFinish() {
- try {
- while (!mFinished) wait();
- } catch (InterruptedException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public synchronized void userStopped(int userId) {
- mFinished = true;
- notifyAll();
- }
-
- @Override
- public synchronized void userStopAborted(int userId) {
- mFinished = true;
- notifyAll();
- }
- }
-
- private void runStopUser() throws Exception {
- boolean wait = false;
- boolean force = false;
- String opt;
- while ((opt = nextOption()) != null) {
- if ("-w".equals(opt)) {
- wait = true;
- } else if ("-f".equals(opt)) {
- force = true;
- } else {
- System.err.println("Error: unknown option: " + opt);
- return;
- }
- }
- int user = Integer.parseInt(nextArgRequired());
- StopUserCallback callback = wait ? new StopUserCallback() : null;
-
- int res = mAm.stopUser(user, force, callback);
- if (res != ActivityManager.USER_OP_SUCCESS) {
- String txt = "";
- switch (res) {
- case ActivityManager.USER_OP_IS_CURRENT:
- txt = " (Can't stop current user)";
- break;
- case ActivityManager.USER_OP_UNKNOWN_USER:
- txt = " (Unknown user " + user + ")";
- break;
- case ActivityManager.USER_OP_ERROR_IS_SYSTEM:
- txt = " (System user cannot be stopped)";
- break;
- case ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP:
- txt = " (Can't stop user " + user
- + " - one of its related users can't be stopped)";
- break;
- }
- System.err.println("Switch failed: " + res + txt);
- } else if (callback != null) {
- callback.waitForFinish();
- }
- }
-
- class MyActivityController extends IActivityController.Stub {
- final String mGdbPort;
- final boolean mMonkey;
-
- static final int STATE_NORMAL = 0;
- static final int STATE_CRASHED = 1;
- static final int STATE_EARLY_ANR = 2;
- static final int STATE_ANR = 3;
-
- int mState;
-
- static final int RESULT_DEFAULT = 0;
-
- static final int RESULT_CRASH_DIALOG = 0;
- static final int RESULT_CRASH_KILL = 1;
-
- static final int RESULT_EARLY_ANR_CONTINUE = 0;
- static final int RESULT_EARLY_ANR_KILL = 1;
-
- static final int RESULT_ANR_DIALOG = 0;
- static final int RESULT_ANR_KILL = 1;
- static final int RESULT_ANR_WAIT = 1;
-
- int mResult;
-
- Process mGdbProcess;
- Thread mGdbThread;
- boolean mGotGdbPrint;
-
- MyActivityController(String gdbPort, boolean monkey) {
- mGdbPort = gdbPort;
- mMonkey = monkey;
- }
-
- @Override
- public boolean activityResuming(String pkg) {
- synchronized (this) {
- System.out.println("** Activity resuming: " + pkg);
- }
- return true;
- }
-
- @Override
- public boolean activityStarting(Intent intent, String pkg) {
- synchronized (this) {
- System.out.println("** Activity starting: " + pkg);
- }
- return true;
- }
-
- @Override
- public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg,
- long timeMillis, String stackTrace) {
- synchronized (this) {
- System.out.println("** ERROR: PROCESS CRASHED");
- System.out.println("processName: " + processName);
- System.out.println("processPid: " + pid);
- System.out.println("shortMsg: " + shortMsg);
- System.out.println("longMsg: " + longMsg);
- System.out.println("timeMillis: " + timeMillis);
- System.out.println("stack:");
- System.out.print(stackTrace);
- System.out.println("#");
- int result = waitControllerLocked(pid, STATE_CRASHED);
- return result == RESULT_CRASH_KILL ? false : true;
- }
- }
-
- @Override
- public int appEarlyNotResponding(String processName, int pid, String annotation) {
- synchronized (this) {
- System.out.println("** ERROR: EARLY PROCESS NOT RESPONDING");
- System.out.println("processName: " + processName);
- System.out.println("processPid: " + pid);
- System.out.println("annotation: " + annotation);
- int result = waitControllerLocked(pid, STATE_EARLY_ANR);
- if (result == RESULT_EARLY_ANR_KILL) return -1;
- return 0;
- }
- }
-
- @Override
- public int appNotResponding(String processName, int pid, String processStats) {
- synchronized (this) {
- System.out.println("** ERROR: PROCESS NOT RESPONDING");
- System.out.println("processName: " + processName);
- System.out.println("processPid: " + pid);
- System.out.println("processStats:");
- System.out.print(processStats);
- System.out.println("#");
- int result = waitControllerLocked(pid, STATE_ANR);
- if (result == RESULT_ANR_KILL) return -1;
- if (result == RESULT_ANR_WAIT) return 1;
- return 0;
- }
- }
-
- @Override
- public int systemNotResponding(String message) {
- synchronized (this) {
- System.out.println("** ERROR: PROCESS NOT RESPONDING");
- System.out.println("message: " + message);
- System.out.println("#");
- System.out.println("Allowing system to die.");
- return -1;
- }
- }
-
- void killGdbLocked() {
- mGotGdbPrint = false;
- if (mGdbProcess != null) {
- System.out.println("Stopping gdbserver");
- mGdbProcess.destroy();
- mGdbProcess = null;
- }
- if (mGdbThread != null) {
- mGdbThread.interrupt();
- mGdbThread = null;
- }
- }
-
- int waitControllerLocked(int pid, int state) {
- if (mGdbPort != null) {
- killGdbLocked();
-
- try {
- System.out.println("Starting gdbserver on port " + mGdbPort);
- System.out.println("Do the following:");
- System.out.println(" adb forward tcp:" + mGdbPort + " tcp:" + mGdbPort);
- System.out.println(" gdbclient app_process :" + mGdbPort);
-
- mGdbProcess = Runtime.getRuntime().exec(new String[] {
- "gdbserver", ":" + mGdbPort, "--attach", Integer.toString(pid)
- });
- final InputStreamReader converter = new InputStreamReader(
- mGdbProcess.getInputStream());
- mGdbThread = new Thread() {
- @Override
- public void run() {
- BufferedReader in = new BufferedReader(converter);
- String line;
- int count = 0;
- while (true) {
- synchronized (MyActivityController.this) {
- if (mGdbThread == null) {
- return;
- }
- if (count == 2) {
- mGotGdbPrint = true;
- MyActivityController.this.notifyAll();
- }
- }
- try {
- line = in.readLine();
- if (line == null) {
- return;
- }
- System.out.println("GDB: " + line);
- count++;
- } catch (IOException e) {
- return;
- }
- }
- }
- };
- mGdbThread.start();
-
- // Stupid waiting for .5s. Doesn't matter if we end early.
- try {
- this.wait(500);
- } catch (InterruptedException e) {
- }
-
- } catch (IOException e) {
- System.err.println("Failure starting gdbserver: " + e);
- killGdbLocked();
- }
- }
- mState = state;
- System.out.println("");
- printMessageForState();
-
- while (mState != STATE_NORMAL) {
- try {
- wait();
- } catch (InterruptedException e) {
- }
- }
-
- killGdbLocked();
-
- return mResult;
- }
-
- void resumeController(int result) {
- synchronized (this) {
- mState = STATE_NORMAL;
- mResult = result;
- notifyAll();
- }
- }
-
- void printMessageForState() {
- switch (mState) {
- case STATE_NORMAL:
- System.out.println("Monitoring activity manager... available commands:");
- break;
- case STATE_CRASHED:
- System.out.println("Waiting after crash... available commands:");
- System.out.println("(c)ontinue: show crash dialog");
- System.out.println("(k)ill: immediately kill app");
- break;
- case STATE_EARLY_ANR:
- System.out.println("Waiting after early ANR... available commands:");
- System.out.println("(c)ontinue: standard ANR processing");
- System.out.println("(k)ill: immediately kill app");
- break;
- case STATE_ANR:
- System.out.println("Waiting after ANR... available commands:");
- System.out.println("(c)ontinue: show ANR dialog");
- System.out.println("(k)ill: immediately kill app");
- System.out.println("(w)ait: wait some more");
- break;
- }
- System.out.println("(q)uit: finish monitoring");
- }
-
- void run() throws RemoteException {
- try {
- printMessageForState();
-
- mAm.setActivityController(this, mMonkey);
- mState = STATE_NORMAL;
-
- InputStreamReader converter = new InputStreamReader(System.in);
- BufferedReader in = new BufferedReader(converter);
- String line;
-
- while ((line = in.readLine()) != null) {
- boolean addNewline = true;
- if (line.length() <= 0) {
- addNewline = false;
- } else if ("q".equals(line) || "quit".equals(line)) {
- resumeController(RESULT_DEFAULT);
- break;
- } else if (mState == STATE_CRASHED) {
- if ("c".equals(line) || "continue".equals(line)) {
- resumeController(RESULT_CRASH_DIALOG);
- } else if ("k".equals(line) || "kill".equals(line)) {
- resumeController(RESULT_CRASH_KILL);
- } else {
- System.out.println("Invalid command: " + line);
- }
- } else if (mState == STATE_ANR) {
- if ("c".equals(line) || "continue".equals(line)) {
- resumeController(RESULT_ANR_DIALOG);
- } else if ("k".equals(line) || "kill".equals(line)) {
- resumeController(RESULT_ANR_KILL);
- } else if ("w".equals(line) || "wait".equals(line)) {
- resumeController(RESULT_ANR_WAIT);
- } else {
- System.out.println("Invalid command: " + line);
- }
- } else if (mState == STATE_EARLY_ANR) {
- if ("c".equals(line) || "continue".equals(line)) {
- resumeController(RESULT_EARLY_ANR_CONTINUE);
- } else if ("k".equals(line) || "kill".equals(line)) {
- resumeController(RESULT_EARLY_ANR_KILL);
- } else {
- System.out.println("Invalid command: " + line);
- }
- } else {
- System.out.println("Invalid command: " + line);
- }
-
- synchronized (this) {
- if (addNewline) {
- System.out.println("");
- }
- printMessageForState();
- }
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- mAm.setActivityController(null, mMonkey);
- }
- }
- }
-
- private void runMonitor() throws Exception {
- String opt;
- String gdbPort = null;
- boolean monkey = false;
- while ((opt=nextOption()) != null) {
- if (opt.equals("--gdb")) {
- gdbPort = nextArgRequired();
- } else if (opt.equals("-m")) {
- monkey = true;
- } else {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
- }
-
- MyActivityController controller = new MyActivityController(gdbPort, monkey);
- controller.run();
- }
-
- private void runHang() throws Exception {
- String opt;
- boolean allowRestart = false;
- while ((opt=nextOption()) != null) {
- if (opt.equals("--allow-restart")) {
- allowRestart = true;
- } else {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
- }
-
- System.out.println("Hanging the system...");
- mAm.hang(new Binder(), allowRestart);
- }
-
- private void runRestart() throws Exception {
- String opt;
- while ((opt=nextOption()) != null) {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
-
- System.out.println("Restart the system...");
- mAm.restart();
- }
-
- private void runIdleMaintenance() throws Exception {
- String opt;
- while ((opt=nextOption()) != null) {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
-
- System.out.println("Performing idle maintenance...");
- try {
- mAm.sendIdleJobTrigger();
- } catch (RemoteException e) {
- }
- }
-
- private void runScreenCompat() throws Exception {
- String mode = nextArgRequired();
- boolean enabled;
- if ("on".equals(mode)) {
- enabled = true;
- } else if ("off".equals(mode)) {
- enabled = false;
- } else {
- System.err.println("Error: enabled mode must be 'on' or 'off' at " + mode);
- return;
- }
-
- String packageName = nextArgRequired();
- do {
- try {
- mAm.setPackageScreenCompatMode(packageName, enabled
- ? ActivityManager.COMPAT_MODE_ENABLED
- : ActivityManager.COMPAT_MODE_DISABLED);
- } catch (RemoteException e) {
- }
- packageName = nextArg();
- } while (packageName != null);
- }
-
- private void runPackageImportance() throws Exception {
- String packageName = nextArgRequired();
- try {
- int procState = mAm.getPackageProcessState(packageName, "com.android.shell");
- System.out.println(
- ActivityManager.RunningAppProcessInfo.procStateToImportance(procState));
- } catch (RemoteException e) {
- }
- }
-
- private void runToUri(int flags) throws Exception {
- Intent intent = makeIntent(UserHandle.USER_CURRENT);
- System.out.println(intent.toUri(flags));
- }
-
- private class IntentReceiver extends IIntentReceiver.Stub {
- private boolean mFinished = false;
-
- @Override
- public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
- boolean ordered, boolean sticky, int sendingUser) {
- String line = "Broadcast completed: result=" + resultCode;
- if (data != null) line = line + ", data=\"" + data + "\"";
- if (extras != null) line = line + ", extras: " + extras;
- System.out.println(line);
- synchronized (this) {
- mFinished = true;
- notifyAll();
- }
- }
-
- public synchronized void waitForFinish() {
- try {
- while (!mFinished) wait();
- } catch (InterruptedException e) {
- throw new IllegalStateException(e);
- }
- }
- }
-
private class InstrumentationWatcher extends IInstrumentationWatcher.Stub {
private boolean mFinished = false;
private boolean mRawMode = false;
@@ -1580,833 +747,4 @@
return true;
}
}
-
- private void runStack() throws Exception {
- String op = nextArgRequired();
- switch (op) {
- case "start":
- runStackStart();
- break;
- case "movetask":
- runStackMoveTask();
- break;
- case "resize":
- runStackResize();
- break;
- case "resize-animated":
- runStackResizeAnimated();
- break;
- case "resize-docked-stack":
- runStackResizeDocked();
- break;
- case "positiontask":
- runStackPositionTask();
- break;
- case "list":
- runStackList();
- break;
- case "info":
- runStackInfo();
- break;
- case "move-top-activity-to-pinned-stack":
- runMoveTopActivityToPinnedStack();
- break;
- case "size-docked-stack-test":
- runStackSizeDockedStackTest();
- break;
- case "remove":
- runStackRemove();
- break;
- default:
- showError("Error: unknown command '" + op + "'");
- break;
- }
- }
-
- private void runStackStart() throws Exception {
- String displayIdStr = nextArgRequired();
- int displayId = Integer.parseInt(displayIdStr);
- Intent intent = makeIntent(UserHandle.USER_CURRENT);
-
- try {
- IActivityContainer container = mAm.createStackOnDisplay(displayId);
- if (container != null) {
- container.startActivity(intent);
- }
- } catch (RemoteException e) {
- }
- }
-
- private void runStackMoveTask() throws Exception {
- String taskIdStr = nextArgRequired();
- int taskId = Integer.parseInt(taskIdStr);
- String stackIdStr = nextArgRequired();
- int stackId = Integer.parseInt(stackIdStr);
- String toTopStr = nextArgRequired();
- final boolean toTop;
- if ("true".equals(toTopStr)) {
- toTop = true;
- } else if ("false".equals(toTopStr)) {
- toTop = false;
- } else {
- System.err.println("Error: bad toTop arg: " + toTopStr);
- return;
- }
-
- try {
- mAm.moveTaskToStack(taskId, stackId, toTop);
- } catch (RemoteException e) {
- }
- }
-
- private void runStackResize() throws Exception {
- String stackIdStr = nextArgRequired();
- int stackId = Integer.parseInt(stackIdStr);
- final Rect bounds = getBounds();
- if (bounds == null) {
- System.err.println("Error: invalid input bounds");
- return;
- }
- resizeStack(stackId, bounds, 0);
- }
-
- private void runStackResizeAnimated() throws Exception {
- String stackIdStr = nextArgRequired();
- int stackId = Integer.parseInt(stackIdStr);
- final Rect bounds;
- if ("null".equals(mArgs.peekNextArg())) {
- bounds = null;
- } else {
- bounds = getBounds();
- if (bounds == null) {
- System.err.println("Error: invalid input bounds");
- return;
- }
- }
- resizeStackUnchecked(stackId, bounds, 0, true);
- }
-
- private void resizeStackUnchecked(int stackId, Rect bounds, int delayMs, boolean animate) {
- try {
- mAm.resizeStack(stackId, bounds, false, false, animate, -1);
- Thread.sleep(delayMs);
- } catch (RemoteException e) {
- showError("Error: resizing stack " + e);
- } catch (InterruptedException e) {
- }
- }
-
- private void runStackResizeDocked() throws Exception {
- final Rect bounds = getBounds();
- final Rect taskBounds = getBounds();
- if (bounds == null || taskBounds == null) {
- System.err.println("Error: invalid input bounds");
- return;
- }
- try {
- mAm.resizeDockedStack(bounds, taskBounds, null, null, null);
- } catch (RemoteException e) {
- showError("Error: resizing docked stack " + e);
- }
- }
-
- private void resizeStack(int stackId, Rect bounds, int delayMs)
- throws Exception {
- if (bounds == null) {
- showError("Error: invalid input bounds");
- return;
- }
- resizeStackUnchecked(stackId, bounds, delayMs, false);
- }
-
- private void runStackPositionTask() throws Exception {
- String taskIdStr = nextArgRequired();
- int taskId = Integer.parseInt(taskIdStr);
- String stackIdStr = nextArgRequired();
- int stackId = Integer.parseInt(stackIdStr);
- String positionStr = nextArgRequired();
- int position = Integer.parseInt(positionStr);
-
- try {
- mAm.positionTaskInStack(taskId, stackId, position);
- } catch (RemoteException e) {
- }
- }
-
- private void runStackList() throws Exception {
- try {
- List<StackInfo> stacks = mAm.getAllStackInfos();
- for (StackInfo info : stacks) {
- System.out.println(info);
- }
- } catch (RemoteException e) {
- }
- }
-
- private void runStackInfo() throws Exception {
- try {
- String stackIdStr = nextArgRequired();
- int stackId = Integer.parseInt(stackIdStr);
- StackInfo info = mAm.getStackInfo(stackId);
- System.out.println(info);
- } catch (RemoteException e) {
- }
- }
-
- private void runStackRemove() throws Exception {
- String stackIdStr = nextArgRequired();
- int stackId = Integer.parseInt(stackIdStr);
- mAm.removeStack(stackId);
- }
-
- private void runMoveTopActivityToPinnedStack() throws Exception {
- int stackId = Integer.parseInt(nextArgRequired());
- final Rect bounds = getBounds();
- if (bounds == null) {
- System.err.println("Error: invalid input bounds");
- return;
- }
-
- try {
- if (!mAm.moveTopActivityToPinnedStack(stackId, bounds)) {
- showError("Didn't move top activity to pinned stack.");
- }
- } catch (RemoteException e) {
- showError("Unable to move top activity: " + e);
- return;
- }
- }
-
- private void runStackSizeDockedStackTest() throws Exception {
- final int stepSize = Integer.parseInt(nextArgRequired());
- final String side = nextArgRequired();
- final String delayStr = nextArg();
- final int delayMs = (delayStr != null) ? Integer.parseInt(delayStr) : 0;
-
- Rect bounds;
- try {
- StackInfo info = mAm.getStackInfo(DOCKED_STACK_ID);
- if (info == null) {
- showError("Docked stack doesn't exist");
- return;
- }
- if (info.bounds == null) {
- showError("Docked stack doesn't have a bounds");
- return;
- }
- bounds = info.bounds;
- } catch (RemoteException e) {
- showError("Unable to get docked stack info:" + e);
- return;
- }
-
- final boolean horizontalGrowth = "l".equals(side) || "r".equals(side);
- final int changeSize = (horizontalGrowth ? bounds.width() : bounds.height()) / 2;
- int currentPoint;
- switch (side) {
- case "l":
- currentPoint = bounds.left;
- break;
- case "r":
- currentPoint = bounds.right;
- break;
- case "t":
- currentPoint = bounds.top;
- break;
- case "b":
- currentPoint = bounds.bottom;
- break;
- default:
- showError("Unknown growth side: " + side);
- return;
- }
-
- final int startPoint = currentPoint;
- final int minPoint = currentPoint - changeSize;
- final int maxPoint = currentPoint + changeSize;
-
- int maxChange;
- System.out.println("Shrinking docked stack side=" + side);
- while (currentPoint > minPoint) {
- maxChange = Math.min(stepSize, currentPoint - minPoint);
- currentPoint -= maxChange;
- setBoundsSide(bounds, side, currentPoint);
- resizeStack(DOCKED_STACK_ID, bounds, delayMs);
- }
-
- System.out.println("Growing docked stack side=" + side);
- while (currentPoint < maxPoint) {
- maxChange = Math.min(stepSize, maxPoint - currentPoint);
- currentPoint += maxChange;
- setBoundsSide(bounds, side, currentPoint);
- resizeStack(DOCKED_STACK_ID, bounds, delayMs);
- }
-
- System.out.println("Back to Original size side=" + side);
- while (currentPoint > startPoint) {
- maxChange = Math.min(stepSize, currentPoint - startPoint);
- currentPoint -= maxChange;
- setBoundsSide(bounds, side, currentPoint);
- resizeStack(DOCKED_STACK_ID, bounds, delayMs);
- }
- }
-
- private void setBoundsSide(Rect bounds, String side, int value) {
- switch (side) {
- case "l":
- bounds.left = value;
- break;
- case "r":
- bounds.right = value;
- break;
- case "t":
- bounds.top = value;
- break;
- case "b":
- bounds.bottom = value;
- break;
- default:
- showError("Unknown set side: " + side);
- break;
- }
- }
-
- private void runTask() throws Exception {
- String op = nextArgRequired();
- if (op.equals("lock")) {
- runTaskLock();
- } else if (op.equals("resizeable")) {
- runTaskResizeable();
- } else if (op.equals("resize")) {
- runTaskResize();
- } else if (op.equals("drag-task-test")) {
- runTaskDragTaskTest();
- } else if (op.equals("size-task-test")) {
- runTaskSizeTaskTest();
- } else {
- showError("Error: unknown command '" + op + "'");
- return;
- }
- }
-
- private void runTaskLock() throws Exception {
- String taskIdStr = nextArgRequired();
- try {
- if (taskIdStr.equals("stop")) {
- mAm.stopLockTaskMode();
- } else {
- int taskId = Integer.parseInt(taskIdStr);
- mAm.startLockTaskMode(taskId);
- }
- System.err.println("Activity manager is " + (mAm.isInLockTaskMode() ? "" : "not ") +
- "in lockTaskMode");
- } catch (RemoteException e) {
- }
- }
-
- private void runTaskResizeable() throws Exception {
- final String taskIdStr = nextArgRequired();
- final int taskId = Integer.parseInt(taskIdStr);
- final String resizeableStr = nextArgRequired();
- final int resizeableMode = Integer.parseInt(resizeableStr);
-
- try {
- mAm.setTaskResizeable(taskId, resizeableMode);
- } catch (RemoteException e) {
- }
- }
-
- private void runTaskResize() throws Exception {
- final String taskIdStr = nextArgRequired();
- final int taskId = Integer.parseInt(taskIdStr);
- final Rect bounds = getBounds();
- if (bounds == null) {
- System.err.println("Error: invalid input bounds");
- return;
- }
- taskResize(taskId, bounds, 0, false);
- }
-
- private void taskResize(int taskId, Rect bounds, int delay_ms, boolean pretendUserResize) {
- try {
- final int resizeMode = pretendUserResize ? RESIZE_MODE_USER : RESIZE_MODE_SYSTEM;
- mAm.resizeTask(taskId, bounds, resizeMode);
- Thread.sleep(delay_ms);
- } catch (RemoteException e) {
- System.err.println("Error changing task bounds: " + e);
- } catch (InterruptedException e) {
- }
- }
-
- private void runTaskDragTaskTest() {
- final int taskId = Integer.parseInt(nextArgRequired());
- final int stepSize = Integer.parseInt(nextArgRequired());
- final String delayStr = nextArg();
- final int delay_ms = (delayStr != null) ? Integer.parseInt(delayStr) : 0;
- final StackInfo stackInfo;
- Rect taskBounds;
- try {
- stackInfo = mAm.getStackInfo(mAm.getFocusedStackId());
- taskBounds = mAm.getTaskBounds(taskId);
- } catch (RemoteException e) {
- System.err.println("Error getting focus stack info or task bounds: " + e);
- return;
- }
- final Rect stackBounds = stackInfo.bounds;
- int travelRight = stackBounds.width() - taskBounds.width();
- int travelLeft = -travelRight;
- int travelDown = stackBounds.height() - taskBounds.height();
- int travelUp = -travelDown;
- int passes = 0;
-
- // We do 2 passes to get back to the original location of the task.
- while (passes < 2) {
- // Move right
- System.out.println("Moving right...");
- travelRight = moveTask(taskId, taskBounds, stackBounds, stepSize,
- travelRight, MOVING_FORWARD, MOVING_HORIZONTALLY, delay_ms);
- System.out.println("Still need to travel right by " + travelRight);
-
- // Move down
- System.out.println("Moving down...");
- travelDown = moveTask(taskId, taskBounds, stackBounds, stepSize,
- travelDown, MOVING_FORWARD, !MOVING_HORIZONTALLY, delay_ms);
- System.out.println("Still need to travel down by " + travelDown);
-
- // Move left
- System.out.println("Moving left...");
- travelLeft = moveTask(taskId, taskBounds, stackBounds, stepSize,
- travelLeft, !MOVING_FORWARD, MOVING_HORIZONTALLY, delay_ms);
- System.out.println("Still need to travel left by " + travelLeft);
-
- // Move up
- System.out.println("Moving up...");
- travelUp = moveTask(taskId, taskBounds, stackBounds, stepSize,
- travelUp, !MOVING_FORWARD, !MOVING_HORIZONTALLY, delay_ms);
- System.out.println("Still need to travel up by " + travelUp);
-
- try {
- taskBounds = mAm.getTaskBounds(taskId);
- } catch (RemoteException e) {
- System.err.println("Error getting task bounds: " + e);
- return;
- }
- passes++;
- }
- }
-
- private int moveTask(int taskId, Rect taskRect, Rect stackRect, int stepSize,
- int maxToTravel, boolean movingForward, boolean horizontal, int delay_ms) {
- int maxMove;
- if (movingForward) {
- while (maxToTravel > 0
- && ((horizontal && taskRect.right < stackRect.right)
- ||(!horizontal && taskRect.bottom < stackRect.bottom))) {
- if (horizontal) {
- maxMove = Math.min(stepSize, stackRect.right - taskRect.right);
- maxToTravel -= maxMove;
- taskRect.right += maxMove;
- taskRect.left += maxMove;
- } else {
- maxMove = Math.min(stepSize, stackRect.bottom - taskRect.bottom);
- maxToTravel -= maxMove;
- taskRect.top += maxMove;
- taskRect.bottom += maxMove;
- }
- taskResize(taskId, taskRect, delay_ms, false);
- }
- } else {
- while (maxToTravel < 0
- && ((horizontal && taskRect.left > stackRect.left)
- ||(!horizontal && taskRect.top > stackRect.top))) {
- if (horizontal) {
- maxMove = Math.min(stepSize, taskRect.left - stackRect.left);
- maxToTravel -= maxMove;
- taskRect.right -= maxMove;
- taskRect.left -= maxMove;
- } else {
- maxMove = Math.min(stepSize, taskRect.top - stackRect.top);
- maxToTravel -= maxMove;
- taskRect.top -= maxMove;
- taskRect.bottom -= maxMove;
- }
- taskResize(taskId, taskRect, delay_ms, false);
- }
- }
- // Return the remaining distance we didn't travel because we reached the target location.
- return maxToTravel;
- }
-
- private void runTaskSizeTaskTest() {
- final int taskId = Integer.parseInt(nextArgRequired());
- final int stepSize = Integer.parseInt(nextArgRequired());
- final String delayStr = nextArg();
- final int delay_ms = (delayStr != null) ? Integer.parseInt(delayStr) : 0;
- final StackInfo stackInfo;
- final Rect initialTaskBounds;
- try {
- stackInfo = mAm.getStackInfo(mAm.getFocusedStackId());
- initialTaskBounds = mAm.getTaskBounds(taskId);
- } catch (RemoteException e) {
- System.err.println("Error getting focus stack info or task bounds: " + e);
- return;
- }
- final Rect stackBounds = stackInfo.bounds;
- stackBounds.inset(STACK_BOUNDS_INSET, STACK_BOUNDS_INSET);
- final Rect currentTaskBounds = new Rect(initialTaskBounds);
-
- // Size by top-left
- System.out.println("Growing top-left");
- do {
- currentTaskBounds.top -= getStepSize(
- currentTaskBounds.top, stackBounds.top, stepSize, GREATER_THAN_TARGET);
-
- currentTaskBounds.left -= getStepSize(
- currentTaskBounds.left, stackBounds.left, stepSize, GREATER_THAN_TARGET);
-
- taskResize(taskId, currentTaskBounds, delay_ms, true);
- } while (stackBounds.top < currentTaskBounds.top
- || stackBounds.left < currentTaskBounds.left);
-
- // Back to original size
- System.out.println("Shrinking top-left");
- do {
- currentTaskBounds.top += getStepSize(
- currentTaskBounds.top, initialTaskBounds.top, stepSize, !GREATER_THAN_TARGET);
-
- currentTaskBounds.left += getStepSize(
- currentTaskBounds.left, initialTaskBounds.left, stepSize, !GREATER_THAN_TARGET);
-
- taskResize(taskId, currentTaskBounds, delay_ms, true);
- } while (initialTaskBounds.top > currentTaskBounds.top
- || initialTaskBounds.left > currentTaskBounds.left);
-
- // Size by top-right
- System.out.println("Growing top-right");
- do {
- currentTaskBounds.top -= getStepSize(
- currentTaskBounds.top, stackBounds.top, stepSize, GREATER_THAN_TARGET);
-
- currentTaskBounds.right += getStepSize(
- currentTaskBounds.right, stackBounds.right, stepSize, !GREATER_THAN_TARGET);
-
- taskResize(taskId, currentTaskBounds, delay_ms, true);
- } while (stackBounds.top < currentTaskBounds.top
- || stackBounds.right > currentTaskBounds.right);
-
- // Back to original size
- System.out.println("Shrinking top-right");
- do {
- currentTaskBounds.top += getStepSize(
- currentTaskBounds.top, initialTaskBounds.top, stepSize, !GREATER_THAN_TARGET);
-
- currentTaskBounds.right -= getStepSize(currentTaskBounds.right, initialTaskBounds.right,
- stepSize, GREATER_THAN_TARGET);
-
- taskResize(taskId, currentTaskBounds, delay_ms, true);
- } while (initialTaskBounds.top > currentTaskBounds.top
- || initialTaskBounds.right < currentTaskBounds.right);
-
- // Size by bottom-left
- System.out.println("Growing bottom-left");
- do {
- currentTaskBounds.bottom += getStepSize(
- currentTaskBounds.bottom, stackBounds.bottom, stepSize, !GREATER_THAN_TARGET);
-
- currentTaskBounds.left -= getStepSize(
- currentTaskBounds.left, stackBounds.left, stepSize, GREATER_THAN_TARGET);
-
- taskResize(taskId, currentTaskBounds, delay_ms, true);
- } while (stackBounds.bottom > currentTaskBounds.bottom
- || stackBounds.left < currentTaskBounds.left);
-
- // Back to original size
- System.out.println("Shrinking bottom-left");
- do {
- currentTaskBounds.bottom -= getStepSize(currentTaskBounds.bottom,
- initialTaskBounds.bottom, stepSize, GREATER_THAN_TARGET);
-
- currentTaskBounds.left += getStepSize(
- currentTaskBounds.left, initialTaskBounds.left, stepSize, !GREATER_THAN_TARGET);
-
- taskResize(taskId, currentTaskBounds, delay_ms, true);
- } while (initialTaskBounds.bottom < currentTaskBounds.bottom
- || initialTaskBounds.left > currentTaskBounds.left);
-
- // Size by bottom-right
- System.out.println("Growing bottom-right");
- do {
- currentTaskBounds.bottom += getStepSize(
- currentTaskBounds.bottom, stackBounds.bottom, stepSize, !GREATER_THAN_TARGET);
-
- currentTaskBounds.right += getStepSize(
- currentTaskBounds.right, stackBounds.right, stepSize, !GREATER_THAN_TARGET);
-
- taskResize(taskId, currentTaskBounds, delay_ms, true);
- } while (stackBounds.bottom > currentTaskBounds.bottom
- || stackBounds.right > currentTaskBounds.right);
-
- // Back to original size
- System.out.println("Shrinking bottom-right");
- do {
- currentTaskBounds.bottom -= getStepSize(currentTaskBounds.bottom,
- initialTaskBounds.bottom, stepSize, GREATER_THAN_TARGET);
-
- currentTaskBounds.right -= getStepSize(currentTaskBounds.right, initialTaskBounds.right,
- stepSize, GREATER_THAN_TARGET);
-
- taskResize(taskId, currentTaskBounds, delay_ms, true);
- } while (initialTaskBounds.bottom < currentTaskBounds.bottom
- || initialTaskBounds.right < currentTaskBounds.right);
- }
-
- private int getStepSize(int current, int target, int inStepSize, boolean greaterThanTarget) {
- int stepSize = 0;
- if (greaterThanTarget && target < current) {
- current -= inStepSize;
- stepSize = inStepSize;
- if (target > current) {
- stepSize -= (target - current);
- }
- }
- if (!greaterThanTarget && target > current) {
- current += inStepSize;
- stepSize = inStepSize;
- if (target < current) {
- stepSize += (current - target);
- }
- }
- return stepSize;
- }
-
- private List<Configuration> getRecentConfigurations(int days) {
- IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
- Context.USAGE_STATS_SERVICE));
- final long now = System.currentTimeMillis();
- final long nDaysAgo = now - (days * 24 * 60 * 60 * 1000);
- try {
- @SuppressWarnings("unchecked")
- ParceledListSlice<ConfigurationStats> configStatsSlice = usm.queryConfigurationStats(
- UsageStatsManager.INTERVAL_BEST, nDaysAgo, now, "com.android.shell");
- if (configStatsSlice == null) {
- return Collections.emptyList();
- }
-
- final ArrayMap<Configuration, Integer> recentConfigs = new ArrayMap<>();
- final List<ConfigurationStats> configStatsList = configStatsSlice.getList();
- final int configStatsListSize = configStatsList.size();
- for (int i = 0; i < configStatsListSize; i++) {
- final ConfigurationStats stats = configStatsList.get(i);
- final int indexOfKey = recentConfigs.indexOfKey(stats.getConfiguration());
- if (indexOfKey < 0) {
- recentConfigs.put(stats.getConfiguration(), stats.getActivationCount());
- } else {
- recentConfigs.setValueAt(indexOfKey,
- recentConfigs.valueAt(indexOfKey) + stats.getActivationCount());
- }
- }
-
- final Comparator<Configuration> comparator = new Comparator<Configuration>() {
- @Override
- public int compare(Configuration a, Configuration b) {
- return recentConfigs.get(b).compareTo(recentConfigs.get(a));
- }
- };
-
- ArrayList<Configuration> configs = new ArrayList<>(recentConfigs.size());
- configs.addAll(recentConfigs.keySet());
- Collections.sort(configs, comparator);
- return configs;
-
- } catch (RemoteException e) {
- return Collections.emptyList();
- }
- }
-
- private void runGetConfig() throws Exception {
- int days = 14;
- String option = nextOption();
- if (option != null) {
- if (!option.equals("--days")) {
- throw new IllegalArgumentException("unrecognized option " + option);
- }
-
- days = Integer.parseInt(nextArgRequired());
- if (days <= 0) {
- throw new IllegalArgumentException("--days must be a positive integer");
- }
- }
-
- try {
- Configuration config = mAm.getConfiguration();
- if (config == null) {
- System.err.println("Activity manager has no configuration");
- return;
- }
-
- System.out.println("config: " + Configuration.resourceQualifierString(config));
- System.out.println("abi: " + TextUtils.join(",", Build.SUPPORTED_ABIS));
-
- final List<Configuration> recentConfigs = getRecentConfigurations(days);
- final int recentConfigSize = recentConfigs.size();
- if (recentConfigSize > 0) {
- System.out.println("recentConfigs:");
- }
-
- for (int i = 0; i < recentConfigSize; i++) {
- System.out.println(" config: " + Configuration.resourceQualifierString(
- recentConfigs.get(i)));
- }
-
- } catch (RemoteException e) {
- }
- }
-
- private void runSuppressResizeConfigChanges() throws Exception {
- boolean suppress = Boolean.valueOf(nextArgRequired());
-
- try {
- mAm.suppressResizeConfigChanges(suppress);
- } catch (RemoteException e) {
- System.err.println("Error suppressing resize config changes: " + e);
- }
- }
-
- private void runSetInactive() throws Exception {
- int userId = UserHandle.USER_CURRENT;
-
- String opt;
- while ((opt=nextOption()) != null) {
- if (opt.equals("--user")) {
- userId = parseUserArg(nextArgRequired());
- } else {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
- }
- String packageName = nextArgRequired();
- String value = nextArgRequired();
-
- IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
- Context.USAGE_STATS_SERVICE));
- usm.setAppInactive(packageName, Boolean.parseBoolean(value), userId);
- }
-
- private void runGetInactive() throws Exception {
- int userId = UserHandle.USER_CURRENT;
-
- String opt;
- while ((opt=nextOption()) != null) {
- if (opt.equals("--user")) {
- userId = parseUserArg(nextArgRequired());
- } else {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
- }
- String packageName = nextArgRequired();
-
- IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
- Context.USAGE_STATS_SERVICE));
- boolean isIdle = usm.isAppInactive(packageName, userId);
- System.out.println("Idle=" + isIdle);
- }
-
- private void runSendTrimMemory() throws Exception {
- int userId = UserHandle.USER_CURRENT;
- String opt;
- while ((opt = nextOption()) != null) {
- if (opt.equals("--user")) {
- userId = parseUserArg(nextArgRequired());
- if (userId == UserHandle.USER_ALL) {
- System.err.println("Error: Can't use user 'all'");
- return;
- }
- } else {
- System.err.println("Error: Unknown option: " + opt);
- return;
- }
- }
-
- String proc = nextArgRequired();
- String levelArg = nextArgRequired();
- int level;
- switch (levelArg) {
- case "HIDDEN":
- level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
- break;
- case "RUNNING_MODERATE":
- level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
- break;
- case "BACKGROUND":
- level = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
- break;
- case "RUNNING_LOW":
- level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
- break;
- case "MODERATE":
- level = ComponentCallbacks2.TRIM_MEMORY_MODERATE;
- break;
- case "RUNNING_CRITICAL":
- level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
- break;
- case "COMPLETE":
- level = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
- break;
- default:
- System.err.println("Error: Unknown level option: " + levelArg);
- return;
- }
- if (!mAm.setProcessMemoryTrimLevel(proc, userId, level)) {
- System.err.println("Unknown error: failed to set trim level");
- }
- }
-
- private void runGetCurrentUser() throws Exception {
- UserInfo currentUser = Preconditions.checkNotNull(mAm.getCurrentUser(),
- "Current user not set");
- System.out.println(currentUser.id);
- }
-
- /**
- * Open the given file for sending into the system process. This verifies
- * with SELinux that the system will have access to the file.
- */
- private static ParcelFileDescriptor openForSystemServer(File file, int mode)
- throws FileNotFoundException {
- final ParcelFileDescriptor fd = ParcelFileDescriptor.open(file, mode);
- final String tcon = SELinux.getFileContext(file.getAbsolutePath());
- if (!SELinux.checkSELinuxAccess("u:r:system_server:s0", tcon, "file", "read")) {
- throw new FileNotFoundException("System server has no access to file context " + tcon);
- }
- return fd;
- }
-
- private Rect getBounds() {
- String leftStr = nextArgRequired();
- int left = Integer.parseInt(leftStr);
- String topStr = nextArgRequired();
- int top = Integer.parseInt(topStr);
- String rightStr = nextArgRequired();
- int right = Integer.parseInt(rightStr);
- String bottomStr = nextArgRequired();
- int bottom = Integer.parseInt(bottomStr);
- if (left < 0) {
- System.err.println("Error: bad left arg: " + leftStr);
- return null;
- }
- if (top < 0) {
- System.err.println("Error: bad top arg: " + topStr);
- return null;
- }
- if (right <= 0) {
- System.err.println("Error: bad right arg: " + rightStr);
- return null;
- }
- if (bottom <= 0) {
- System.err.println("Error: bad bottom arg: " + bottomStr);
- return null;
- }
- return new Rect(left, top, right, bottom);
- }
}
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
index e530184..b5f1c2a 100644
--- a/cmds/app_process/Android.mk
+++ b/cmds/app_process/Android.mk
@@ -62,7 +62,6 @@
LOCAL_LDFLAGS := -ldl
LOCAL_LDFLAGS_32 := -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
LOCAL_LDFLAGS_64 := -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
-LOCAL_CPPFLAGS := -std=c++11
LOCAL_MODULE := app_process__asan
LOCAL_MULTILIB := both
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index 6d30f0d..ab6adfb 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -1,5 +1,6 @@
#include <dirent.h>
#include <inttypes.h>
+#include <sys/file.h>
#include <sys/stat.h>
#include "idmap.h"
@@ -35,16 +36,31 @@
bool writePackagesList(const char *filename, const SortedVector<Overlay>& overlayVector)
{
- FILE* fout = fopen(filename, "w");
+ // the file is opened for appending so that it doesn't get truncated
+ // before we can guarantee mutual exclusion via the flock
+ FILE* fout = fopen(filename, "a");
if (fout == NULL) {
return false;
}
+ if (TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_EX)) != 0) {
+ fclose(fout);
+ return false;
+ }
+
+ if (TEMP_FAILURE_RETRY(ftruncate(fileno(fout), 0)) != 0) {
+ TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
+ fclose(fout);
+ return false;
+ }
+
for (size_t i = 0; i < overlayVector.size(); ++i) {
const Overlay& overlay = overlayVector[i];
fprintf(fout, "%s %s\n", overlay.apk_path.string(), overlay.idmap_path.string());
}
+ TEMP_FAILURE_RETRY(fflush(fout));
+ TEMP_FAILURE_RETRY(flock(fileno(fout), LOCK_UN));
fclose(fout);
// Make file world readable since Zygote (running as root) will read
@@ -171,9 +187,6 @@
{
String8 filename = String8(idmap_dir);
filename.appendPath("overlays.list");
- if (unlink(filename.string()) != 0 && errno != ENOENT) {
- return EXIT_FAILURE;
- }
SortedVector<Overlay> overlayVector;
const size_t N = overlay_dirs->size();
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index ace4e32..aba53dc 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -41,6 +41,10 @@
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.ApkLite;
+import android.content.pm.PackageParser.PackageLite;
+import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Binder;
@@ -398,11 +402,27 @@
*/
private int runInstall() throws RemoteException {
final InstallParams params = makeInstallParams();
+ final String inPath = nextArg();
+ if (params.sessionParams.sizeBytes < 0 && inPath != null) {
+ File file = new File(inPath);
+ if (file.isFile()) {
+ try {
+ ApkLite baseApk = PackageParser.parseApkLite(file, 0);
+ PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null);
+ params.sessionParams.setSize(
+ PackageHelper.calculateInstalledSize(pkgLite, false,
+ params.sessionParams.abiOverride));
+ } catch (PackageParserException | IOException e) {
+ System.err.println("Error: Failed to parse APK file : " + e);
+ return 1;
+ }
+ }
+ }
+
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
try {
- final String inPath = nextArg();
if (inPath == null && params.sessionParams.sizeBytes == 0) {
System.err.println("Error: must either specify a package size or an APK file");
return 1;
@@ -981,7 +1001,7 @@
} else if (userId < 0) {
info = mUm.createUser(name, flags);
} else {
- info = mUm.createProfileForUser(name, flags, userId);
+ info = mUm.createProfileForUser(name, flags, userId, null);
}
if (info != null) {
diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
index a6ef25f..4dcb05e 100644
--- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
@@ -50,7 +50,7 @@
IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService(
Context.USB_SERVICE));
try {
- usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null));
+ usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null), false);
} catch (RemoteException e) {
System.err.println("Error communicating with UsbManager: " + e);
}
diff --git a/compiled-classes-phone b/compiled-classes-phone
index 221d687..6214306 100644
--- a/compiled-classes-phone
+++ b/compiled-classes-phone
@@ -1168,14 +1168,6 @@
android.drm.DrmManagerClient$OnInfoListener
android.drm.DrmOutputStream
android.drm.DrmSupportInfo
-android.graphics.Atlas
-android.graphics.Atlas$Entry
-android.graphics.Atlas$Policy
-android.graphics.Atlas$SlicePolicy
-android.graphics.Atlas$SlicePolicy$Cell
-android.graphics.Atlas$SlicePolicy$MinAreaSplitDecision
-android.graphics.Atlas$SlicePolicy$SplitDecision
-android.graphics.Atlas$Type
android.graphics.Bitmap
android.graphics.Bitmap$1
android.graphics.Bitmap$CompressFormat
@@ -4264,9 +4256,6 @@
android.view.IAppTransitionAnimationSpecsFuture$Stub$Proxy
android.view.IApplicationToken
android.view.IApplicationToken$Stub
-android.view.IAssetAtlas
-android.view.IAssetAtlas$Stub
-android.view.IAssetAtlas$Stub$Proxy
android.view.IDockedStackListener
android.view.IDockedStackListener$Stub
android.view.IDockedStackListener$Stub$Proxy
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index fd0bf0b..116d063 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -16,15 +16,15 @@
package android.animation;
-import java.util.Arrays;
-import java.util.List;
-
-import android.animation.Keyframe.IntKeyframe;
import android.animation.Keyframe.FloatKeyframe;
+import android.animation.Keyframe.IntKeyframe;
import android.animation.Keyframe.ObjectKeyframe;
import android.graphics.Path;
import android.util.Log;
+import java.util.Arrays;
+import java.util.List;
+
/**
* This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
* values between those keyframes for a given animation. The class internal to the animation
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index a09c920..ed7e89d 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -276,6 +276,23 @@
}
/**
+ * Returns whether animators are currently enabled, system-wide. By default, all
+ * animators are enabled. This can change if either the user sets a Developer Option
+ * to set the animator duration scale to 0 or by Battery Savery mode being enabled
+ * (which disables all animations).
+ *
+ * <p>Developers should not typically need to call this method, but should an app wish
+ * to show a different experience when animators are disabled, this return value
+ * can be used as a decider of which experience to offer.
+ *
+ * @return boolean Whether animators are currently enabled. The default value is
+ * <code>true</code>.
+ */
+ public static boolean areAnimatorsEnabled() {
+ return !(sDurationScale == 0);
+ }
+
+ /**
* Creates a new ValueAnimator object. This default constructor is primarily for
* use internally; the factory methods which take parameters are more generally
* useful.
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f798512..d91472b 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1229,8 +1229,9 @@
case UPDATE_CONFIGURATION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
Configuration config = Configuration.CREATOR.createFromParcel(data);
- updateConfiguration(config);
+ final boolean updated = updateConfiguration(config);
reply.writeNoException();
+ reply.writeInt(updated ? 1 : 0);
return true;
}
@@ -4593,7 +4594,7 @@
data.recycle();
return res;
}
- public void updateConfiguration(Configuration values) throws RemoteException
+ public boolean updateConfiguration(Configuration values) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -4601,8 +4602,10 @@
values.writeToParcel(data, 0);
mRemote.transact(UPDATE_CONFIGURATION_TRANSACTION, data, reply, 0);
reply.readException();
+ boolean updated = reply.readInt() == 1;
data.recycle();
reply.recycle();
+ return updated;
}
public void setRequestedOrientation(IBinder token, int requestedOrientation)
throws RemoteException {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 85a0403..6e2c464 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -32,6 +32,7 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.content.DialogInterface;
+import android.content.res.Configuration;
import android.content.pm.ApplicationInfo;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -288,9 +289,14 @@
}
mCanceled = false;
-
+
if (!mCreated) {
dispatchOnCreate(null);
+ } else {
+ // Fill the DecorView in on any configuration changes that
+ // may have occured while it was removed from the WindowManager.
+ final Configuration config = mContext.getResources().getConfiguration();
+ mWindow.getDecorView().dispatchConfigurationChanged(config);
}
onStart();
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 096f0cb..c9d3682 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -276,8 +276,9 @@
* Updates global configuration and applies changes to the entire system.
* @param values Update values for global configuration.
* @throws RemoteException
+ * @return Returns true if the configuration was updated.
*/
- public void updateConfiguration(Configuration values) throws RemoteException;
+ public boolean updateConfiguration(Configuration values) throws RemoteException;
public void setRequestedOrientation(IBinder token,
int requestedOrientation) throws RemoteException;
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 28224e8..c87eef9 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -78,6 +78,8 @@
void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
void cancelNotificationsFromListener(in INotificationListener token, in String[] keys);
+ void snoozeNotificationFromListener(in INotificationListener token, String key, long until);
+
void requestBindListener(in ComponentName component);
void requestUnbindListener(in INotificationListener token);
void requestBindProvider(in ComponentName component);
diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java
index f33af39..e4a22c4 100644
--- a/core/java/android/app/IntentService.java
+++ b/core/java/android/app/IntentService.java
@@ -46,7 +46,8 @@
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For a detailed discussion about how to create services, read the
- * <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> developer guide.</p>
+ * <a href="{@docRoot}guide/components/services.html">Services</a> developer
+ * guide.</p>
* </div>
*
* @see android.os.AsyncTask
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 680e518..bdb2685 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -19,6 +19,7 @@
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
@@ -1052,6 +1053,7 @@
this(Icon.createWithResource("", icon), title, intent, new Bundle(), null, false);
}
+ /** Keep in sync with {@link Notification.Action.Builder#Builder(Action)}! */
private Action(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
RemoteInput[] remoteInputs, boolean allowGeneratedReplies) {
this.mIcon = icon;
@@ -1118,7 +1120,7 @@
*/
@Deprecated
public Builder(int icon, CharSequence title, PendingIntent intent) {
- this(Icon.createWithResource("", icon), title, intent, new Bundle(), null);
+ this(Icon.createWithResource("", icon), title, intent);
}
/**
@@ -1128,7 +1130,7 @@
* @param intent the {@link PendingIntent} to fire when users trigger this action
*/
public Builder(Icon icon, CharSequence title, PendingIntent intent) {
- this(icon, title, intent, new Bundle(), null);
+ this(icon, title, intent, new Bundle(), null, false);
}
/**
@@ -1137,12 +1139,13 @@
* @param action the action to read fields from.
*/
public Builder(Action action) {
- this(action.getIcon(), action.title, action.actionIntent, new Bundle(action.mExtras),
- action.getRemoteInputs());
+ this(action.getIcon(), action.title, action.actionIntent,
+ new Bundle(action.mExtras), action.getRemoteInputs(),
+ action.getAllowGeneratedReplies());
}
private Builder(Icon icon, CharSequence title, PendingIntent intent, Bundle extras,
- RemoteInput[] remoteInputs) {
+ RemoteInput[] remoteInputs, boolean allowGeneratedReplies) {
mIcon = icon;
mTitle = title;
mIntent = intent;
@@ -1151,6 +1154,7 @@
mRemoteInputs = new ArrayList<RemoteInput>(remoteInputs.length);
Collections.addAll(mRemoteInputs, remoteInputs);
}
+ mAllowGeneratedReplies = allowGeneratedReplies;
}
/**
@@ -4683,12 +4687,12 @@
}
/**
- * @param userDisplayName the name to be displayed for any replies sent by the user before the
- * posting app reposts the notification with those messages after they've been actually
- * sent and in previous messages sent by the user added in
+ * @param userDisplayName Required - the name to be displayed for any replies sent by the
+ * user before the posting app reposts the notification with those messages after they've
+ * been actually sent and in previous messages sent by the user added in
* {@link #addMessage(Notification.MessagingStyle.Message)}
*/
- public MessagingStyle(CharSequence userDisplayName) {
+ public MessagingStyle(@NonNull CharSequence userDisplayName) {
mUserDisplayName = userDisplayName;
}
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index c88cea0..c171a14 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -839,19 +839,19 @@
tmpConfig = new Configuration();
}
tmpConfig.setTo(config);
- if (!isDefaultDisplay) {
- // Get new DisplayMetrics based on the DisplayAdjustments given
- // to the ResourcesImpl. Udate a copy if the CompatibilityInfo
- // changed, because the ResourcesImpl object will handle the
- // update internally.
- DisplayAdjustments daj = r.getDisplayAdjustments();
- if (compat != null) {
- daj = new DisplayAdjustments(daj);
- daj.setCompatibilityInfo(compat);
- }
- dm = getDisplayMetrics(displayId, daj);
- applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
+
+ // Get new DisplayMetrics based on the DisplayAdjustments given
+ // to the ResourcesImpl. Update a copy if the CompatibilityInfo
+ // changed, because the ResourcesImpl object will handle the
+ // update internally.
+ DisplayAdjustments daj = r.getDisplayAdjustments();
+ if (compat != null) {
+ daj = new DisplayAdjustments(daj);
+ daj.setCompatibilityInfo(compat);
}
+ dm = getDisplayMetrics(displayId, daj);
+ applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
+
if (hasOverrideConfiguration) {
tmpConfig.updateFrom(key.mOverrideConfiguration);
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a207a52..4ddcfe5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2352,18 +2352,23 @@
* <p>The calling device admin must be a device or profile owner. If it is not,
* a {@link SecurityException} will be thrown.
*
+ * <p>The calling device admin can verify the value it has set by calling
+ * {@link #getRequiredStrongAuthTimeout(ComponentName)} and passing in its instance.
+ *
* <p>This method can be called on the {@link DevicePolicyManager} instance returned by
* {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent
* profile.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param timeoutMs The new timeout, after which the user will have to unlock with strong
- * authentication method. If the timeout is lower than 1 hour (minimum) or higher than
- * 72 hours (default and maximum) an {@link IllegalArgumentException} is thrown.
+ * authentication method. A value of 0 means the admin is not participating in
+ * controlling the timeout.
+ * The minimum and maximum timeouts are platform-defined and are typically 1 hour and
+ * 72 hours, respectively. Though discouraged, the admin may choose to require strong
+ * auth at all times using {@link #KEYGUARD_DISABLE_FINGERPRINT} and/or
+ * {@link #KEYGUARD_DISABLE_TRUST_AGENTS}.
*
* @throws SecurityException if {@code admin} is not a device or profile owner.
- * @throws IllegalArgumentException if the timeout is lower than 1 hour (minimum) or higher than
- * 72 hours (default and maximum)
*
* @hide
*/
@@ -2389,7 +2394,7 @@
*
* @param admin The name of the admin component to check, or {@code null} to aggregate
* accross all participating admins.
- * @return The timeout or default timeout if not configured
+ * @return The timeout or 0 if not configured for the provided admin.
*
* @hide
*/
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index bc82806..bad6325 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -35,6 +35,8 @@
import android.util.ArraySet;
import android.util.Log;
+import libcore.io.IoUtils;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
@@ -647,10 +649,11 @@
File file = scanQueue.remove(0);
String filePath;
try {
- // Ignore symlinks outright
+ // Ignore things that aren't "real" files or dirs
StructStat stat = Os.lstat(file.getPath());
- if (OsConstants.S_ISLNK(stat.st_mode)) {
- if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
+ if (!OsConstants.S_ISREG(stat.st_mode)
+ && !OsConstants.S_ISDIR(stat.st_mode)) {
+ if (DEBUG) Log.i(TAG, "Not a file/dir (skipping)!: " + file);
continue;
}
@@ -921,6 +924,13 @@
} catch (RemoteException e) {
// we'll time out anyway, so we're safe
}
+
+ // Don't close the fd out from under the system service if this was local
+ if (Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(oldState);
+ IoUtils.closeQuietly(data);
+ IoUtils.closeQuietly(newState);
+ }
}
}
@@ -951,6 +961,11 @@
} catch (RemoteException e) {
// we'll time out anyway, so we're safe
}
+
+ if (Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(data);
+ IoUtils.closeQuietly(newState);
+ }
}
}
@@ -994,6 +1009,10 @@
} catch (RemoteException e) {
// we'll time out anyway, so we're safe
}
+
+ if (Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(data);
+ }
}
}
@@ -1041,6 +1060,10 @@
} catch (RemoteException e) {
// we'll time out anyway, so we're safe
}
+
+ if (Binder.getCallingPid() != Process.myPid()) {
+ IoUtils.closeQuietly(data);
+ }
}
}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index cd5eff2..5c9e2ee 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -895,6 +895,14 @@
return false;
}
+ /** @hide */
+ public boolean isBondingInitiatedLocally() {
+ try {
+ return sService.isBondingInitiatedLocally(this);
+ } catch (RemoteException e) {Log.e(TAG, "", e);}
+ return false;
+ }
+
/**
* Set the Out Of Band data for a remote device to be used later
* in the pairing mechanism. Users can obtain this data through other
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index a420539..8c98536 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -62,6 +62,7 @@
boolean cancelBondProcess(in BluetoothDevice device);
boolean removeBond(in BluetoothDevice device);
int getBondState(in BluetoothDevice device);
+ boolean isBondingInitiatedLocally(in BluetoothDevice device);
int getConnectionState(in BluetoothDevice device);
String getRemoteName(in BluetoothDevice device);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 74f48c6..e031275 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3037,6 +3037,18 @@
"android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
/**
+ * Broadcast sent to the system user when the 'device locked' state changes for any user.
+ * Carries an extra {@link #EXTRA_USER_HANDLE} that specifies the ID of the user for which
+ * the device was locked or unlocked.
+ *
+ * This is only sent to registered receivers.
+ *
+ * @hide
+ */
+ public static final String ACTION_DEVICE_LOCKED_CHANGED =
+ "android.intent.action.DEVICE_LOCKED_CHANGED";
+
+ /**
* Sent when the user taps on the clock widget in the system's "quick settings" area.
*/
public static final String ACTION_QUICK_CLOCK =
@@ -4184,6 +4196,16 @@
"android.intent.extra.MEDIA_RESOURCE_TYPE";
/**
+ * Used as a boolean extra field in {@link #ACTION_CHOOSER} intents to specify
+ * whether to show the chooser or not when there is only one application available
+ * to choose from.
+ *
+ * @hide
+ */
+ public static final String EXTRA_AUTO_LAUNCH_SINGLE_CHOICE =
+ "android.intent.extra.AUTO_LAUNCH_SINGLE_CHOICE";
+
+ /**
* Used as an int value for {@link #EXTRA_MEDIA_RESOURCE_TYPE}
* to represent that a video codec is allowed to use.
*
@@ -6574,7 +6596,7 @@
*/
public void removeUnsafeExtras() {
if (mExtras != null) {
- mExtras.filterValues();
+ mExtras = mExtras.filterValues();
}
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 5d2c6cd..4cbff5f 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -163,13 +163,14 @@
*/
public static final int RESIZE_MODE_UNRESIZEABLE = 0;
/**
- * Activity can not be resized and always occupies the fullscreen area with all windows cropped
- * to either the task or stack bounds.
+ * Activity didn't explicitly request to be resizeable, but we are making it resizeable because
+ * of the SDK version it targets. Only affects apps with target SDK >= N where the app is
+ * implied to be resizeable if it doesn't explicitly set the attribute to any value.
* @hide
*/
- public static final int RESIZE_MODE_CROP_WINDOWS = 1;
+ public static final int RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION = 1;
/**
- * Activity is resizeable.
+ * Activity explicitly requested to be resizeable.
* @hide
*/
public static final int RESIZE_MODE_RESIZEABLE = 2;
@@ -179,7 +180,8 @@
*/
public static final int RESIZE_MODE_RESIZEABLE_AND_PIPABLE = 3;
/**
- * Activity is does not support resizing, but we are forcing it to be resizeable.
+ * Activity is does not support resizing, but we are forcing it to be resizeable. Only affects
+ * certain pre-N apps where we force them to be resizeable.
* @hide
*/
public static final int RESIZE_MODE_FORCE_RESIZEABLE = 4;
@@ -862,7 +864,8 @@
public static boolean isResizeableMode(int mode) {
return mode == RESIZE_MODE_RESIZEABLE
|| mode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE
- || mode == RESIZE_MODE_FORCE_RESIZEABLE;
+ || mode == RESIZE_MODE_FORCE_RESIZEABLE
+ || mode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
}
/** @hide */
@@ -870,8 +873,8 @@
switch (mode) {
case RESIZE_MODE_UNRESIZEABLE:
return "RESIZE_MODE_UNRESIZEABLE";
- case RESIZE_MODE_CROP_WINDOWS:
- return "RESIZE_MODE_CROP_WINDOWS";
+ case RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION:
+ return "RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION";
case RESIZE_MODE_RESIZEABLE:
return "RESIZE_MODE_RESIZEABLE";
case RESIZE_MODE_RESIZEABLE_AND_PIPABLE:
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index b7364e2..ecfc00f 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -520,12 +520,26 @@
public static final int PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER = 1 << 10;
/**
- * When set, the activities associated with this application are resizeable by default.
+ * When set, the application explicitly requested that its activities by resizeable by default.
* @see android.R.styleable#AndroidManifestActivity_resizeableActivity
*
* @hide
*/
- public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES = 1 << 11;
+ public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET = 1 << 11;
+
+ /**
+ * The application isn't requesting explicitly requesting for its activities to be resizeable or
+ * non-resizeable by default. So, we are making it activities resizeable by default based on the
+ * target SDK version of the app.
+ * @see android.R.styleable#AndroidManifestActivity_resizeableActivity
+ *
+ * NOTE: This only affects apps with target SDK >= N where the resizeableActivity attribute was
+ * introduced. It shouldn't be confused with {@link ActivityInfo#RESIZE_MODE_FORCE_RESIZEABLE}
+ * where certain pre-N apps are forced to the resizeable.
+ *
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION = 1 << 12;
/**
* Value for {@link #privateFlags}: {@code true} means the OS should go ahead and
@@ -533,7 +547,7 @@
* foreground-equivalent run state. Defaults to {@code false} if unspecified.
* @hide
*/
- public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 12;
+ public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 13;
/**
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index f5bcf64..da4eb2d 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -168,4 +168,25 @@
* @return Whether was launched.
*/
public abstract boolean wasPackageEverLaunched(String packageName, int userId);
+
+ /**
+ * Grants a runtime permission
+ * @param packageName The package name.
+ * @param name The name of the permission.
+ * @param userId The userId for which to grant the permission.
+ * @param overridePolicy If true, grant this permission even if it is fixed by policy.
+ */
+ public abstract void grantRuntimePermission(String packageName, String name, int userId,
+ boolean overridePolicy);
+
+ /**
+ * Revokes a runtime permission
+ * @param packageName The package name.
+ * @param name The name of the permission.
+ * @param userId The userId for which to revoke the permission.
+ * @param overridePolicy If true, revoke this permission even if it is fixed by policy.
+ */
+ public abstract void revokeRuntimePermission(String packageName, String name, int userId,
+ boolean overridePolicy);
+
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 201ada1..12e8d487 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -83,10 +83,12 @@
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
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_RESIZEABLE_ACTIVITIES;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION;
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;
@@ -2940,9 +2942,12 @@
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
}
- if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity,
- owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N)) {
- ai.privateFlags |= PRIVATE_FLAG_RESIZEABLE_ACTIVITIES;
+ if (sa.hasValueOrEmpty(R.styleable.AndroidManifestApplication_resizeableActivity)) {
+ if (sa.getBoolean(R.styleable.AndroidManifestApplication_resizeableActivity, true)) {
+ ai.privateFlags |= PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET;
+ }
+ } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
+ ai.privateFlags |= PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION;
}
ai.networkSecurityConfigRes = sa.getResourceId(
@@ -3548,31 +3553,7 @@
R.styleable.AndroidManifestActivity_screenOrientation,
SCREEN_ORIENTATION_UNSPECIFIED);
- a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
- final boolean appDefault = (owner.applicationInfo.privateFlags
- & PRIVATE_FLAG_RESIZEABLE_ACTIVITIES) != 0;
- // This flag is used to workaround the issue with ignored resizeableActivity param when
- // either targetSdkVersion is not set at all or <uses-sdk> tag is below <application>
- // tag in AndroidManifest. If this param was explicitly set to 'false' we need to set
- // corresponding resizeMode regardless of targetSdkVersion value at this point in time.
- final boolean resizeableSetExplicitly
- = sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity);
- final boolean resizeable = sa.getBoolean(
- R.styleable.AndroidManifestActivity_resizeableActivity, appDefault);
-
- if (resizeable) {
- if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
- false)) {
- a.info.resizeMode = RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
- } else {
- a.info.resizeMode = RESIZE_MODE_RESIZEABLE;
- }
- } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N
- || resizeableSetExplicitly) {
- a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
- } else if (!a.info.isFixedOrientation() && (a.info.flags & FLAG_IMMERSIVE) == 0) {
- a.info.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
- }
+ setActivityResizeMode(a.info, sa, owner);
if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
a.info.flags |= FLAG_ALWAYS_FOCUSABLE;
@@ -3706,6 +3687,39 @@
return a;
}
+ private void setActivityResizeMode(ActivityInfo aInfo, TypedArray sa, Package owner) {
+ final boolean appExplicitDefault = (owner.applicationInfo.privateFlags
+ & PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET) != 0;
+ final boolean supportsPip =
+ sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, false);
+
+ if (sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity)
+ || appExplicitDefault) {
+ // Activity or app explicitly set if it is resizeable or not;
+ if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
+ appExplicitDefault)) {
+ aInfo.resizeMode =
+ supportsPip ? RESIZE_MODE_RESIZEABLE_AND_PIPABLE : RESIZE_MODE_RESIZEABLE;
+ } else {
+ aInfo.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ }
+ return;
+ }
+
+ if ((owner.applicationInfo.privateFlags
+ & PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION) != 0) {
+ // The activity or app didn't explicitly set the resizing option, however we want to
+ // make it resize due to the sdk version it is targeting.
+ aInfo.resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+ return;
+ }
+
+ // resize preference isn't set and target sdk version doesn't support resizing apps by
+ // default. For the app to be resizeable if it isn't fixed orientation or immersive.
+ aInfo.resizeMode = (aInfo.isFixedOrientation() || (aInfo.flags & FLAG_IMMERSIVE) != 0)
+ ? RESIZE_MODE_UNRESIZEABLE : RESIZE_MODE_FORCE_RESIZEABLE;
+ }
+
private void parseLayout(Resources res, AttributeSet attrs, Activity a) {
TypedArray sw = res.obtainAttributes(attrs,
com.android.internal.R.styleable.AndroidManifestLayout);
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index cd248ea..96ad67c 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -329,7 +329,7 @@
* <p>Applications with a foreground activity or service are not rate-limited.
*
* <p>Rate-limiting will be reset upon certain events, so that even background applications
- * can call these APIs again until they are rate limit is reached again.
+ * can call these APIs again until the rate limit is reached again.
* These events include the following:
* <ul>
* <li>When an application comes to the foreground.
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 4ad86f7..b0d0d79 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -27,6 +27,8 @@
import android.util.SparseArray;
import android.util.TypedValue;
+import dalvik.annotation.optimization.FastNative;
+
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
@@ -752,6 +754,7 @@
* applications.
* {@hide}
*/
+ @FastNative
public native final void setConfiguration(int mcc, int mnc, String locale,
int orientation, int touchscreen, int density, int keyboard,
int keyboardHidden, int navigation, int screenWidth, int screenHeight,
@@ -761,13 +764,18 @@
/**
* Retrieve the resource identifier for the given resource name.
*/
+ @FastNative
/*package*/ native final int getResourceIdentifier(String type,
String name,
String defPackage);
+ @FastNative
/*package*/ native final String getResourceName(int resid);
+ @FastNative
/*package*/ native final String getResourcePackageName(int resid);
+ @FastNative
/*package*/ native final String getResourceTypeName(int resid);
+ @FastNative
/*package*/ native final String getResourceEntryName(int resid);
private native final long openAsset(String fileName, int accessMode);
@@ -781,15 +789,19 @@
private native final int readAssetChar(long asset);
private native final int readAsset(long asset, byte[] b, int off, int len);
private native final long seekAsset(long asset, long offset, int whence);
+ @FastNative
private native final long getAssetLength(long asset);
+ @FastNative
private native final long getAssetRemainingLength(long asset);
/** Returns true if the resource was found, filling in mRetStringBlock and
* mRetData. */
+ @FastNative
private native final int loadResourceValue(int ident, short density, TypedValue outValue,
boolean resolve);
/** Returns true if the resource was found, filling in mRetStringBlock and
* mRetData. */
+ @FastNative
private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
boolean resolve);
/*package*/ static final int STYLE_NUM_ENTRIES = 6;
@@ -802,17 +814,24 @@
static final int STYLE_CHANGING_CONFIGURATIONS = 4;
/*package*/ static final int STYLE_DENSITY = 5;
+ @FastNative
/*package*/ native static final boolean applyStyle(long theme,
int defStyleAttr, int defStyleRes, long xmlParser,
int[] inAttrs, int[] outValues, int[] outIndices);
+ @FastNative
/*package*/ native static final boolean resolveAttrs(long theme,
int defStyleAttr, int defStyleRes, int[] inValues,
int[] inAttrs, int[] outValues, int[] outIndices);
+ @FastNative
/*package*/ native final boolean retrieveAttributes(
long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
+ @FastNative
/*package*/ native final int getArraySize(int resource);
+ @FastNative
/*package*/ native final int retrieveArray(int resource, int[] outValues);
+ @FastNative
private native final int getStringBlockCount();
+ @FastNative
private native final long getNativeStringBlock(int block);
/**
@@ -845,17 +864,22 @@
/*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
/*package*/ native static final void copyTheme(long dest, long source);
/*package*/ native static final void clearTheme(long theme);
+ @FastNative
/*package*/ native static final int loadThemeAttributeValue(long theme, int ident,
TypedValue outValue,
boolean resolve);
/*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix);
+ @FastNative
/*package*/ native static final @NativeConfig int getThemeChangingConfigurations(long theme);
private native final long openXmlAssetNative(int cookie, String fileName);
private native final String[] getArrayStringResource(int arrayRes);
+ @FastNative
private native final int[] getArrayStringInfo(int arrayRes);
+ @FastNative
/*package*/ native final int[] getArrayIntResource(int arrayRes);
+ @FastNative
/*package*/ native final int[] getStyleAttributes(int themeRes);
private native final void init(boolean isSystem);
diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java
index 64b6bf1..b03ed1e 100644
--- a/core/java/android/content/res/ResourcesKey.java
+++ b/core/java/android/content/res/ResourcesKey.java
@@ -59,7 +59,8 @@
mOverlayDirs = overlayDirs;
mLibDirs = libDirs;
mDisplayId = displayId;
- mOverrideConfiguration = overrideConfig != null ? overrideConfig : Configuration.EMPTY;
+ mOverrideConfiguration = new Configuration(overrideConfig != null
+ ? overrideConfig : Configuration.EMPTY);
mCompatInfo = compatInfo != null ? compatInfo : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
int hash = 17;
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index 2f4d69b0..e6b95741 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -20,6 +20,8 @@
import com.android.internal.util.XmlUtils;
+import dalvik.annotation.optimization.FastNative;
+
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
@@ -492,25 +494,42 @@
int offset,
int size);
private static final native long nativeGetStringBlock(long obj);
-
private static final native long nativeCreateParseState(long obj);
- /*package*/ static final native int nativeNext(long state);
- private static final native int nativeGetNamespace(long state);
- /*package*/ static final native int nativeGetName(long state);
- private static final native int nativeGetText(long state);
- private static final native int nativeGetLineNumber(long state);
- private static final native int nativeGetAttributeCount(long state);
- private static final native int nativeGetAttributeNamespace(long state, int idx);
- private static final native int nativeGetAttributeName(long state, int idx);
- private static final native int nativeGetAttributeResource(long state, int idx);
- private static final native int nativeGetAttributeDataType(long state, int idx);
- private static final native int nativeGetAttributeData(long state, int idx);
- private static final native int nativeGetAttributeStringValue(long state, int idx);
- private static final native int nativeGetIdAttribute(long state);
- private static final native int nativeGetClassAttribute(long state);
- private static final native int nativeGetStyleAttribute(long state);
- private static final native int nativeGetAttributeIndex(long state, String namespace, String name);
private static final native void nativeDestroyParseState(long state);
-
private static final native void nativeDestroy(long obj);
+
+ // ----------- @FastNative ------------------
+
+ @FastNative
+ /*package*/ static final native int nativeNext(long state);
+ @FastNative
+ private static final native int nativeGetNamespace(long state);
+ @FastNative
+ /*package*/ static final native int nativeGetName(long state);
+ @FastNative
+ private static final native int nativeGetText(long state);
+ @FastNative
+ private static final native int nativeGetLineNumber(long state);
+ @FastNative
+ private static final native int nativeGetAttributeCount(long state);
+ @FastNative
+ private static final native int nativeGetAttributeNamespace(long state, int idx);
+ @FastNative
+ private static final native int nativeGetAttributeName(long state, int idx);
+ @FastNative
+ private static final native int nativeGetAttributeResource(long state, int idx);
+ @FastNative
+ private static final native int nativeGetAttributeDataType(long state, int idx);
+ @FastNative
+ private static final native int nativeGetAttributeData(long state, int idx);
+ @FastNative
+ private static final native int nativeGetAttributeStringValue(long state, int idx);
+ @FastNative
+ private static final native int nativeGetIdAttribute(long state);
+ @FastNative
+ private static final native int nativeGetClassAttribute(long state);
+ @FastNative
+ private static final native int nativeGetStyleAttribute(long state);
+ @FastNative
+ private static final native int nativeGetAttributeIndex(long state, String namespace, String name);
}
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 2dd4800..bb8d9ff 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -20,6 +20,7 @@
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;
+import java.io.File;
/**
* A helper class to manage database creation and version management.
@@ -54,6 +55,7 @@
private final String mName;
private final CursorFactory mFactory;
private final int mNewVersion;
+ private final int mMinimumSupportedVersion;
private SQLiteDatabase mDatabase;
private boolean mIsInitializing;
@@ -96,6 +98,34 @@
*/
public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
DatabaseErrorHandler errorHandler) {
+ this(context, name, factory, version, 0, errorHandler);
+ }
+
+ /**
+ * Same as {@link #SQLiteOpenHelper(Context, String, CursorFactory, int, DatabaseErrorHandler)}
+ * but also accepts an integer minimumSupportedVersion as a convenience for upgrading very old
+ * versions of this database that are no longer supported. If a database with older version that
+ * minimumSupportedVersion is found, it is simply deleted and a new database is created with the
+ * given name and version
+ *
+ * @param context to use to open or create the database
+ * @param name the name of the database file, null for a temporary in-memory database
+ * @param factory to use for creating cursor objects, null for default
+ * @param version the required version of the database
+ * @param minimumSupportedVersion the minimum version that is supported to be upgraded to
+ * {@code version} via {@link #onUpgrade}. If the current database version is lower
+ * than this, database is simply deleted and recreated with the version passed in
+ * {@code version}. {@link #onBeforeDelete} is called before deleting the database
+ * when this happens. This is 0 by default.
+ * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
+ * corruption, or null to use the default error handler.
+ * @see #onBeforeDelete(SQLiteDatabase)
+ * @see #SQLiteOpenHelper(Context, String, CursorFactory, int, DatabaseErrorHandler)
+ * @see #onUpgrade(SQLiteDatabase, int, int)
+ * @hide
+ */
+ public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
+ int minimumSupportedVersion, DatabaseErrorHandler errorHandler) {
if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
mContext = context;
@@ -103,6 +133,7 @@
mFactory = factory;
mNewVersion = version;
mErrorHandler = errorHandler;
+ mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);
}
/**
@@ -245,21 +276,34 @@
db.getVersion() + " to " + mNewVersion + ": " + mName);
}
- db.beginTransaction();
- try {
- if (version == 0) {
- onCreate(db);
+ if (version > 0 && version < mMinimumSupportedVersion) {
+ File databaseFile = new File(db.getPath());
+ onBeforeDelete(db);
+ db.close();
+ if (SQLiteDatabase.deleteDatabase(databaseFile)) {
+ mIsInitializing = false;
+ return getDatabaseLocked(writable);
} else {
- if (version > mNewVersion) {
- onDowngrade(db, version, mNewVersion);
- } else {
- onUpgrade(db, version, mNewVersion);
- }
+ throw new IllegalStateException("Unable to delete obsolete database "
+ + mName + " with version " + version);
}
- db.setVersion(mNewVersion);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
+ } else {
+ db.beginTransaction();
+ try {
+ if (version == 0) {
+ onCreate(db);
+ } else {
+ if (version > mNewVersion) {
+ onDowngrade(db, version, mNewVersion);
+ } else {
+ onUpgrade(db, version, mNewVersion);
+ }
+ }
+ db.setVersion(mNewVersion);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
}
}
@@ -292,18 +336,18 @@
}
/**
- * Called when the database connection is being configured, to enable features
- * such as write-ahead logging or foreign key support.
+ * Called when the database connection is being configured, to enable features such as
+ * write-ahead logging or foreign key support.
* <p>
- * This method is called before {@link #onCreate}, {@link #onUpgrade},
- * {@link #onDowngrade}, or {@link #onOpen} are called. It should not modify
- * the database except to configure the database connection as required.
- * </p><p>
- * This method should only call methods that configure the parameters of the
- * database connection, such as {@link SQLiteDatabase#enableWriteAheadLogging}
- * {@link SQLiteDatabase#setForeignKeyConstraintsEnabled},
- * {@link SQLiteDatabase#setLocale}, {@link SQLiteDatabase#setMaximumSize},
- * or executing PRAGMA statements.
+ * This method is called before {@link #onCreate}, {@link #onUpgrade}, {@link #onDowngrade}, or
+ * {@link #onOpen} are called. It should not modify the database except to configure the
+ * database connection as required.
+ * </p>
+ * <p>
+ * This method should only call methods that configure the parameters of the database
+ * connection, such as {@link SQLiteDatabase#enableWriteAheadLogging}
+ * {@link SQLiteDatabase#setForeignKeyConstraintsEnabled}, {@link SQLiteDatabase#setLocale},
+ * {@link SQLiteDatabase#setMaximumSize}, or executing PRAGMA statements.
* </p>
*
* @param db The database.
@@ -311,6 +355,20 @@
public void onConfigure(SQLiteDatabase db) {}
/**
+ * Called before the database is deleted when the version returned by
+ * {@link SQLiteDatabase#getVersion()} is lower than the minimum supported version passed (if at
+ * all) while creating this helper. After the database is deleted, a fresh database with the
+ * given version is created. This will be followed by {@link #onConfigure(SQLiteDatabase)} and
+ * {@link #onCreate(SQLiteDatabase)} being called with a new SQLiteDatabase object
+ *
+ * @param db the database opened with this helper
+ * @see #SQLiteOpenHelper(Context, String, CursorFactory, int, int, DatabaseErrorHandler)
+ * @hide
+ */
+ public void onBeforeDelete(SQLiteDatabase db) {
+ }
+
+ /**
* Called when the database is created for the first time. This is where the
* creation of tables and the initial population of the tables should happen.
*
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index fafe116..45aeb4a 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -88,15 +88,13 @@
/* Returns true if the specified USB function is enabled. */
boolean isFunctionEnabled(String function);
- /* Sets the current USB function. */
- void setCurrentFunction(String function);
-
- /* Sets whether USB data (for example, MTP exposed pictures) should be made
- * available on the USB connection. Unlocking data should only be done with
- * user involvement, since exposing pictures or other data could leak sensitive
- * user information.
+ /* Sets the current USB function as well as whether USB data
+ * (for example, MTP exposed pictures) should be made available
+ * on the USB connection. Unlocking data should only be done with
+ * user involvement, since exposing pictures or other data could
+ * leak sensitive user information.
*/
- void setUsbDataUnlocked(boolean unlock);
+ void setCurrentFunction(String function, boolean usbDataUnlocked);
/* Allow USB debugging from the attached host. If alwaysAllow is true, add the
* the public key to list of host keys that the user has approved.
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 1d20c78..3636e4e 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -542,33 +542,23 @@
* {@link #USB_FUNCTION_MIDI}, {@link #USB_FUNCTION_MTP}, {@link #USB_FUNCTION_PTP},
* or {@link #USB_FUNCTION_RNDIS}.
* </p><p>
+ * Also sets whether USB data (for example, MTP exposed pictures) should be made available
+ * on the USB connection when in device mode. Unlocking usb data should only be done with
+ * user involvement, since exposing pictures or other data could leak sensitive
+ * user information.
+ * </p><p>
* Note: This function is asynchronous and may fail silently without applying
* the requested changes.
* </p>
*
* @param function name of the USB function, or null to restore the default function
+ * @param usbDataUnlocked whether user data is accessible
*
* {@hide}
*/
- public void setCurrentFunction(String function) {
+ public void setCurrentFunction(String function, boolean usbDataUnlocked) {
try {
- mService.setCurrentFunction(function);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Sets whether USB data (for example, MTP exposed pictures) should be made available
- * on the USB connection when in device mode. Unlocking usb data should only be done with
- * user involvement, since exposing pictures or other data could leak sensitive
- * user information.
- *
- * {@hide}
- */
- public void setUsbDataUnlocked(boolean unlocked) {
- try {
- mService.setUsbDataUnlocked(unlocked);
+ mService.setCurrentFunction(function, usbDataUnlocked);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index ea53a71..eace8b2 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -124,6 +124,10 @@
return false;
}
+ public boolean isUp() {
+ return hasFlag(FLAG_UP);
+ }
+
/** {@inheritDoc} */
public int describeContents() {
return 0;
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index 59c5fb6..c3abcf7 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -50,9 +50,13 @@
public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
public static final int DHCP_NO_MSG_TYPE = makeErrorCode(DHCP_ERROR, 4);
public static final int DHCP_UNKNOWN_MSG_TYPE = makeErrorCode(DHCP_ERROR, 5);
+ /** {@hide} */
+ public static final int DHCP_NO_COOKIE = makeErrorCode(DHCP_ERROR, 6);
public static final int BUFFER_UNDERFLOW = makeErrorCode(MISC_ERROR, 1);
public static final int RECEIVE_ERROR = makeErrorCode(MISC_ERROR, 2);
+ /** {@hide} */
+ public static final int PARSING_ERROR = makeErrorCode(MISC_ERROR, 3);
public final String ifName;
// error code byte format (MSB to LSB):
@@ -115,8 +119,9 @@
}
final static class Decoder {
- static final SparseArray<String> constants =
- MessageUtils.findMessageNames(new Class[]{DhcpErrorEvent.class},
- new String[]{"L2_", "L3_", "L4_", "BOOTP_", "DHCP_", "BUFFER_", "RECEIVE_"});
+ static final SparseArray<String> constants = MessageUtils.findMessageNames(
+ new Class[]{DhcpErrorEvent.class},
+ new String[]{"L2_", "L3_", "L4_", "BOOTP_", "DHCP_", "BUFFER_", "RECEIVE_",
+ "PARSING_"});
}
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 95dd148..3d5d900 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -5433,7 +5433,8 @@
if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
if (dumpDurationSteps(pw, " ", "Discharge step durations:",
getDischargeLevelStepTracker(), false)) {
- long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
+ long timeRemaining = computeBatteryTimeRemaining(
+ SystemClock.elapsedRealtime() * 1000);
if (timeRemaining >= 0) {
pw.print(" Estimated discharge time remaining: ");
TimeUtils.formatDuration(timeRemaining / 1000, pw);
@@ -5449,7 +5450,8 @@
}
if (dumpDurationSteps(pw, " ", "Charge step durations:",
getChargeLevelStepTracker(), false)) {
- long timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime());
+ long timeRemaining = computeChargeTimeRemaining(
+ SystemClock.elapsedRealtime() * 1000);
if (timeRemaining >= 0) {
pw.print(" Estimated charge time remaining: ");
TimeUtils.formatDuration(timeRemaining / 1000, pw);
@@ -5612,14 +5614,14 @@
if (!filtering || (flags&DUMP_CHARGED_ONLY) != 0) {
dumpDurationSteps(pw, "", DISCHARGE_STEP_DATA, getDischargeLevelStepTracker(), true);
String[] lineArgs = new String[1];
- long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
+ long timeRemaining = computeBatteryTimeRemaining(SystemClock.elapsedRealtime() * 1000);
if (timeRemaining >= 0) {
lineArgs[0] = Long.toString(timeRemaining);
dumpLine(pw, 0 /* uid */, "i" /* category */, DISCHARGE_TIME_REMAIN_DATA,
(Object[])lineArgs);
}
dumpDurationSteps(pw, "", CHARGE_STEP_DATA, getChargeLevelStepTracker(), true);
- timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime());
+ timeRemaining = computeChargeTimeRemaining(SystemClock.elapsedRealtime() * 1000);
if (timeRemaining >= 0) {
lineArgs[0] = Long.toString(timeRemaining);
dumpLine(pw, 0 /* uid */, "i" /* category */, CHARGE_TIME_REMAIN_DATA,
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 7061589..d04d6c2 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -329,25 +329,49 @@
* Filter values in Bundle to only basic types.
* @hide
*/
- public void filterValues() {
+ public Bundle filterValues() {
unparcel();
+ Bundle bundle = this;
if (mMap != null) {
- for (int i = mMap.size() - 1; i >= 0; i--) {
- Object value = mMap.valueAt(i);
+ ArrayMap<String, Object> map = mMap;
+ for (int i = map.size() - 1; i >= 0; i--) {
+ Object value = map.valueAt(i);
if (PersistableBundle.isValidType(value)) {
continue;
}
if (value instanceof Bundle) {
- ((Bundle)value).filterValues();
+ Bundle newBundle = ((Bundle)value).filterValues();
+ if (newBundle != value) {
+ if (map == mMap) {
+ // The filter had to generate a new bundle, but we have not yet
+ // created a new one here. Do that now.
+ bundle = new Bundle(this);
+ // Note the ArrayMap<> constructor is guaranteed to generate
+ // a new object with items in the same order as the original.
+ map = bundle.mMap;
+ }
+ // Replace this current entry with the new child bundle.
+ map.setValueAt(i, newBundle);
+ }
+ continue;
}
if (value.getClass().getName().startsWith("android.")) {
continue;
}
- mMap.removeAt(i);
+ if (map == mMap) {
+ // This is the first time we have had to remove something, that means we
+ // need to switch to a new Bundle.
+ bundle = new Bundle(this);
+ // Note the ArrayMap<> constructor is guaranteed to generate
+ // a new object with items in the same order as the original.
+ map = bundle.mMap;
+ }
+ map.removeAt(i);
}
}
mFlags |= FLAG_HAS_FDS_KNOWN;
mFlags &= ~FLAG_HAS_FDS;
+ return bundle;
}
/**
diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
index 12830a4..c5ceecd 100644
--- a/core/java/android/os/IRecoverySystem.aidl
+++ b/core/java/android/os/IRecoverySystem.aidl
@@ -25,4 +25,5 @@
boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
boolean setupBcb(in String command);
boolean clearBcb();
+ void rebootRecoveryWithCommand(in String command);
}
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index eeb641d..65c60930 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -36,7 +36,8 @@
int getCredentialOwnerProfile(int userHandle);
UserInfo createUser(in String name, int flags);
- UserInfo createProfileForUser(in String name, int flags, int userHandle);
+ UserInfo createProfileForUser(in String name, int flags, int userHandle,
+ in String[] disallowedPackages);
UserInfo createRestrictedProfile(String name, int parentUserHandle);
void setUserEnabled(int userHandle);
boolean removeUser(int userHandle);
@@ -82,4 +83,7 @@
boolean someUserHasSeedAccount(in String accountName, in String accountType);
boolean isManagedProfile(int userId);
boolean isDemoUser(int userId);
+ UserInfo createProfileForUserEvenWhenDisallowed(in String name, int flags, int userHandle,
+ in String[] disallowedPackages);
+ boolean isUserUnlockingOrUnlocked(int userId);
}
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index f6e6ad6..85f999b 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -46,6 +46,7 @@
import java.util.Map;
import java.util.Set;
+import dalvik.annotation.optimization.FastNative;
import dalvik.system.VMRuntime;
/**
@@ -254,22 +255,35 @@
// see libbinder's binder/Status.h
private static final int EX_TRANSACTION_FAILED = -129;
+ @FastNative
private static native int nativeDataSize(long nativePtr);
+ @FastNative
private static native int nativeDataAvail(long nativePtr);
+ @FastNative
private static native int nativeDataPosition(long nativePtr);
+ @FastNative
private static native int nativeDataCapacity(long nativePtr);
+ @FastNative
private static native long nativeSetDataSize(long nativePtr, int size);
+ @FastNative
private static native void nativeSetDataPosition(long nativePtr, int pos);
+ @FastNative
private static native void nativeSetDataCapacity(long nativePtr, int size);
+ @FastNative
private static native boolean nativePushAllowFds(long nativePtr, boolean allowFds);
+ @FastNative
private static native void nativeRestoreAllowFds(long nativePtr, boolean lastValue);
private static native void nativeWriteByteArray(long nativePtr, byte[] b, int offset, int len);
private static native void nativeWriteBlob(long nativePtr, byte[] b, int offset, int len);
+ @FastNative
private static native void nativeWriteInt(long nativePtr, int val);
+ @FastNative
private static native void nativeWriteLong(long nativePtr, long val);
+ @FastNative
private static native void nativeWriteFloat(long nativePtr, float val);
+ @FastNative
private static native void nativeWriteDouble(long nativePtr, double val);
private static native void nativeWriteString(long nativePtr, String val);
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
@@ -277,9 +291,13 @@
private static native byte[] nativeCreateByteArray(long nativePtr);
private static native byte[] nativeReadBlob(long nativePtr);
+ @FastNative
private static native int nativeReadInt(long nativePtr);
+ @FastNative
private static native long nativeReadLong(long nativePtr);
+ @FastNative
private static native float nativeReadFloat(long nativePtr);
+ @FastNative
private static native double nativeReadDouble(long nativePtr);
private static native String nativeReadString(long nativePtr);
private static native IBinder nativeReadStrongBinder(long nativePtr);
@@ -294,6 +312,7 @@
long nativePtr, byte[] data, int offset, int length);
private static native long nativeAppendFrom(
long thisNativePtr, long otherNativePtr, int offset, int length);
+ @FastNative
private static native boolean nativeHasFileDescriptors(long nativePtr);
private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
private static native void nativeEnforceInterface(long nativePtr, String interfaceName);
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 9bbe8f9..c153184 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -53,24 +53,6 @@
*/
public static final int WAKEFULNESS_DOZING = 3;
-
- /**
- * Power hint:
- * Interaction: The user is interacting with the device. The corresponding data field must be
- * the expected duration of the interaction, or 0 if unknown.
- *
- * Sustained Performance Mode: The corresponding data field must be Enable/Disable
- * Sustained Performance Mode.
- *
- * Launch: This is specific for activity launching. The corresponding data field must be
- * the expected duration of the required boost, or 0 if unknown.
- *
- * These must be kept in sync with the values in hardware/libhardware/include/hardware/power.h
- */
- public static final int POWER_HINT_INTERACTION = 2;
- public static final int POWER_HINT_SUSTAINED_PERFORMANCE_MODE = 6;
- public static final int POWER_HINT_LAUNCH = 8;
-
public static String wakefulnessToString(int wakefulness) {
switch (wakefulness) {
case WAKEFULNESS_ASLEEP:
@@ -169,5 +151,9 @@
public abstract void uidGone(int uid);
+ /**
+ * The hintId sent through this method should be in-line with the
+ * PowerHint defined in android/hardware/power/<version 1.0 & up>/IPower.h
+ */
public abstract void powerHint(int hintId, int data);
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index e9ebe2d..f9dee92 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -17,8 +17,6 @@
package android.os;
import android.annotation.TestApi;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
import android.system.Os;
import android.system.OsConstants;
import android.util.Log;
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 0b3abaa..d48431a 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -700,28 +700,22 @@
* @throws IOException if something goes wrong.
*/
private static void bootCommand(Context context, String... args) throws IOException {
- synchronized (sRequestLock) {
- LOG_FILE.delete();
+ LOG_FILE.delete();
- StringBuilder command = new StringBuilder();
- for (String arg : args) {
- if (!TextUtils.isEmpty(arg)) {
- command.append(arg);
- command.append("\n");
- }
+ StringBuilder command = new StringBuilder();
+ for (String arg : args) {
+ if (!TextUtils.isEmpty(arg)) {
+ command.append(arg);
+ command.append("\n");
}
-
- // Write the command into BCB (bootloader control block).
- RecoverySystem rs = (RecoverySystem) context.getSystemService(
- Context.RECOVERY_SERVICE);
- rs.setupBcb(command.toString());
-
- // Having set up the BCB, go ahead and reboot.
- PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- pm.reboot(PowerManager.REBOOT_RECOVERY);
-
- throw new IOException("Reboot failed (no permissions?)");
}
+
+ // Write the command into BCB (bootloader control block) and boot from
+ // there. Will not return unless failed.
+ RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
+ rs.rebootRecoveryWithCommand(command.toString());
+
+ throw new IOException("Reboot failed (no permissions?)");
}
// Read last_install; then report time (in seconds) and I/O (in MiB) for
@@ -916,6 +910,17 @@
}
/**
+ * Talks to RecoverySystemService via Binder to set up the BCB command and
+ * reboot into recovery accordingly.
+ */
+ private void rebootRecoveryWithCommand(String command) {
+ try {
+ mService.rebootRecoveryWithCommand(command);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
* Internally, recovery treats each line of the command file as a separate
* argv, so we only need to protect against newlines and nulls.
*/
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index 831c9b2..dbb9650 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -188,6 +188,25 @@
}
/**
+ * Helper for just system services to ask the shell to open an output file.
+ * @hide
+ */
+ public ParcelFileDescriptor openOutputFileForSystem(String path) {
+ try {
+ ParcelFileDescriptor pfd = getShellCallback().openOutputFile(path,
+ "u:r:system_server:s0");
+ if (pfd != null) {
+ return pfd;
+ }
+ } catch (RuntimeException e) {
+ getErrPrintWriter().println("Failure opening file: " + e.getMessage());
+ }
+ getErrPrintWriter().println("Error: Unable to open file: " + path);
+ getErrPrintWriter().println("Consider using a file under /data/local/tmp/");
+ return null;
+ }
+
+ /**
* Return the next option on the command line -- that is an argument that
* starts with '-'. If the next argument is not an option, null is returned.
*/
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index 672df6d..b3d76d7 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -20,6 +20,8 @@
import android.content.Context;
import android.util.Slog;
+import dalvik.annotation.optimization.CriticalNative;
+
/**
* Core timekeeping facilities.
*
@@ -124,7 +126,7 @@
}
duration = start + ms - uptimeMillis();
} while (duration > 0);
-
+
if (interrupted) {
// Important: we don't want to quietly eat an interrupt() event,
// so we make sure to re-interrupt the thread so that the next
@@ -132,7 +134,7 @@
Thread.currentThread().interrupt();
}
}
-
+
/**
* Sets the current wall time, in milliseconds. Requires the calling
* process to have appropriate permissions.
@@ -162,6 +164,7 @@
*
* @return milliseconds of non-sleep uptime since boot.
*/
+ @CriticalNative
native public static long uptimeMillis();
/**
@@ -169,6 +172,7 @@
*
* @return elapsed milliseconds since boot.
*/
+ @CriticalNative
native public static long elapsedRealtime();
/**
@@ -176,30 +180,34 @@
*
* @return elapsed nanoseconds since boot.
*/
+ @CriticalNative
public static native long elapsedRealtimeNanos();
/**
* Returns milliseconds running in the current thread.
- *
+ *
* @return elapsed milliseconds in the thread
*/
+ @CriticalNative
public static native long currentThreadTimeMillis();
/**
* Returns microseconds running in the current thread.
- *
+ *
* @return elapsed microseconds in the thread
- *
+ *
* @hide
*/
+ @CriticalNative
public static native long currentThreadTimeMicro();
/**
* Returns current wall time in microseconds.
- *
+ *
* @return elapsed microseconds in wall time
- *
+ *
* @hide
*/
+ @CriticalNative
public static native long currentTimeMicro();
}
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 3ae28fd..7e8cc0b8 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -16,6 +16,8 @@
package android.os;
+import dalvik.annotation.optimization.FastNative;
+
/**
* Writes trace events to the system trace buffer. These trace events can be
* collected and visualized using the Systrace tool.
@@ -91,14 +93,20 @@
private static volatile long sEnabledTags = TRACE_TAG_NOT_READY;
private static native long nativeGetEnabledTags();
- private static native void nativeTraceCounter(long tag, String name, int value);
- private static native void nativeTraceBegin(long tag, String name);
- private static native void nativeTraceEnd(long tag);
- private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
- private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
private static native void nativeSetAppTracingAllowed(boolean allowed);
private static native void nativeSetTracingEnabled(boolean allowed);
+ @FastNative
+ private static native void nativeTraceCounter(long tag, String name, int value);
+ @FastNative
+ private static native void nativeTraceBegin(long tag, String name);
+ @FastNative
+ private static native void nativeTraceEnd(long tag);
+ @FastNative
+ private static native void nativeAsyncTraceBegin(long tag, String name, int cookie);
+ @FastNative
+ private static native void nativeAsyncTraceEnd(long tag, String name, int cookie);
+
static {
// We configure two separate change callbacks, one in Trace.cpp and one here. The
// native callback reads the tags from the system property, and this callback
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 5dc18fb..bc5af81 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1094,10 +1094,8 @@
/** {@hide} */
public boolean isUserUnlockingOrUnlocked(@UserIdInt int userId) {
- // TODO Switch to using UMS internal isUserUnlockingOrUnlocked
try {
- return ActivityManagerNative.getDefault().isUserRunning(userId,
- ActivityManager.FLAG_AND_UNLOCKING_OR_UNLOCKED);
+ return mService.isUserUnlockingOrUnlocked(userId);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -1340,15 +1338,52 @@
*
* @param name the user's name
* @param flags flags that identify the type of user and other properties.
- * @see UserInfo
- * @param userHandle new user will be a profile of this use.
+ * @param userHandle new user will be a profile of this user.
*
- * @return the UserInfo object for the created user, or null if the user could not be created.
+ * @return the {@link UserInfo} object for the created user, or null if the user
+ * could not be created.
* @hide
*/
public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle) {
+ return createProfileForUser(name, flags, userHandle, null);
+ }
+
+ /**
+ * Version of {@link #createProfileForUser(String, int, int)} that allows you to specify
+ * any packages that should not be installed in the new profile by default, these packages can
+ * still be installed later by the user if needed.
+ *
+ * @param name the user's name
+ * @param flags flags that identify the type of user and other properties.
+ * @param userHandle new user will be a profile of this user.
+ * @param disallowedPackages packages that will not be installed in the profile being created.
+ *
+ * @return the {@link UserInfo} object for the created user, or null if the user
+ * could not be created.
+ * @hide
+ */
+ public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle,
+ String[] disallowedPackages) {
try {
- return mService.createProfileForUser(name, flags, userHandle);
+ return mService.createProfileForUser(name, flags, userHandle, disallowedPackages);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Similar to {@link #createProfileForUser(String, int, int, String[])}
+ * except bypassing the checking of {@link UserManager#DISALLOW_ADD_USER}.
+ * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+ *
+ * @see #createProfileForUser(String, int, int, String[])
+ * @hide
+ */
+ public UserInfo createProfileForUserEvenWhenDisallowed(String name, int flags,
+ @UserIdInt int userHandle, String[] disallowedPackages) {
+ try {
+ return mService.createProfileForUserEvenWhenDisallowed(name, flags, userHandle,
+ disallowedPackages);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 7399b7b..e399be0 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -437,7 +437,7 @@
final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
intent.addCategory(Intent.CATEGORY_DEFAULT);
- intent.setData(uri);
+ intent.setDataAndType(uri, DocumentsContract.Root.MIME_TYPE_ITEM);
// note that docsui treats this as *force* show advanced. So sending
// false permits advanced to be shown based on user preferences.
diff --git a/core/java/android/print/PrintJobInfo.java b/core/java/android/print/PrintJobInfo.java
index f134943..3d094f7 100644
--- a/core/java/android/print/PrintJobInfo.java
+++ b/core/java/android/print/PrintJobInfo.java
@@ -586,8 +586,6 @@
*
* @param key The option key.
* @return Whether the option is present.
- *
- * @hide
*/
public boolean hasAdvancedOption(String key) {
return mAdvancedOptions != null && mAdvancedOptions.containsKey(key);
@@ -598,8 +596,6 @@
*
* @param key The option key.
* @return The option value.
- *
- * @hide
*/
public String getAdvancedStringOption(String key) {
if (mAdvancedOptions != null) {
@@ -613,8 +609,6 @@
*
* @param key The option key.
* @return The option value.
- *
- * @hide
*/
public int getAdvancedIntOption(String key) {
if (mAdvancedOptions != null) {
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index d409030..b31b295 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -438,21 +438,11 @@
public static final String PRIMARY_ORGANIZATION_ID = "primary_organization";
/**
- * Mark a person as having been contacted.
- *
- * @param resolver the ContentResolver to use
- * @param personId the person who was contacted
- * @deprecated see {@link android.provider.ContactsContract}
+ * This API is no longer supported as of O.
*/
@Deprecated
public static void markAsContacted(ContentResolver resolver, long personId) {
- Uri uri = ContentUris.withAppendedId(CONTENT_URI, personId);
- uri = Uri.withAppendedPath(uri, "update_contact_time");
- ContentValues values = new ContentValues();
- // There is a trigger in place that will update TIMES_CONTACTED when
- // LAST_TIME_CONTACTED is modified.
- values.put(LAST_TIME_CONTACTED, System.currentTimeMillis());
- resolver.update(uri, values, null, null);
+ // No longer supported.
}
/**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index a1763c0..a07aee5 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -19,8 +19,6 @@
import android.accounts.Account;
import android.annotation.SystemApi;
import android.app.Activity;
-import android.app.admin.DevicePolicyManager;
-import android.content.ActivityNotFoundException;
import android.content.ContentProviderClient;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
@@ -44,7 +42,6 @@
import android.util.DisplayMetrics;
import android.util.Pair;
import android.view.View;
-import android.widget.Toast;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -118,6 +115,12 @@
public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
/**
+ * Prefix for column names that are not visible to client apps.
+ * @hide
+ */
+ public static final String HIDDEN_COLUMN_PREFIX = "x_";
+
+ /**
* An optional URI parameter for insert, update, or delete queries
* that allows the caller
* to specify that it is a sync adapter. The default value is false. If true
@@ -661,6 +664,12 @@
ContentValues contentValues = new ContentValues();
resolver.update(Directory.CONTENT_URI, contentValues, null, null);
}
+
+ /**
+ * A query parameter that's passed to directory providers which indicates the client
+ * package name that has made the query requests.
+ */
+ public static final String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
}
/**
@@ -863,6 +872,25 @@
*/
public static final String LAST_TIME_CONTACTED = "last_time_contacted";
+ /** @hide Raw value. */
+ public static final String RAW_TIMES_CONTACTED = HIDDEN_COLUMN_PREFIX + TIMES_CONTACTED;
+
+ /** @hide Raw value. */
+ public static final String RAW_LAST_TIME_CONTACTED =
+ HIDDEN_COLUMN_PREFIX + LAST_TIME_CONTACTED;
+
+ /**
+ * @hide
+ * Low res version. Same as {@link #TIMES_CONTACTED} but use it in CP2 for clarification.
+ */
+ public static final String LR_TIMES_CONTACTED = TIMES_CONTACTED;
+
+ /**
+ * @hide
+ * Low res version. Same as {@link #TIMES_CONTACTED} but use it in CP2 for clarification.
+ */
+ public static final String LR_LAST_TIME_CONTACTED = LAST_TIME_CONTACTED;
+
/**
* Is the contact starred?
* <P>Type: INTEGER (boolean)</P>
@@ -1669,7 +1697,7 @@
Uri uri = ContentUris.withAppendedId(CONTENT_URI, contactId);
ContentValues values = new ContentValues();
// TIMES_CONTACTED will be incremented when LAST_TIME_CONTACTED is modified.
- values.put(LAST_TIME_CONTACTED, System.currentTimeMillis());
+ values.put(LR_LAST_TIME_CONTACTED, System.currentTimeMillis());
resolver.update(uri, values, null, null);
}
@@ -4224,6 +4252,24 @@
/** The number of times the referenced {@link Data} has been used. */
public static final String TIMES_USED = "times_used";
+
+ /** @hide Raw value. */
+ public static final String RAW_LAST_TIME_USED = HIDDEN_COLUMN_PREFIX + LAST_TIME_USED;
+
+ /** @hide Raw value. */
+ public static final String RAW_TIMES_USED = HIDDEN_COLUMN_PREFIX + TIMES_USED;
+
+ /**
+ * @hide
+ * Low res version. Same as {@link #LAST_TIME_USED} but use it in CP2 for clarification.
+ */
+ public static final String LR_LAST_TIME_USED = LAST_TIME_USED;
+
+ /**
+ * @hide
+ * Low res version. Same as {@link #TIMES_USED} but use it in CP2 for clarification.
+ */
+ public static final String LR_TIMES_USED = TIMES_USED;
}
/**
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 6ddaf3b..98371f4 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -36,8 +36,10 @@
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
+import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.OnCloseListener;
+import android.os.Parcelable;
import android.os.RemoteException;
import android.os.storage.StorageVolume;
import android.system.ErrnoException;
@@ -644,6 +646,8 @@
public static final String METHOD_REMOVE_DOCUMENT = "android:removeDocument";
/** {@hide} */
public static final String METHOD_EJECT_ROOT = "android:ejectRoot";
+ /** {@hide} */
+ public static final String METHOD_FIND_PATH = "android:findPath";
/** {@hide} */
public static final String EXTRA_PARENT_URI = "parentUri";
@@ -1307,6 +1311,41 @@
}
/**
+ * Finds the canonical path to the root. Document id should be unique across
+ * roots.
+ *
+ * @param documentUri uri of the document which path is requested.
+ * @return the path to the root of the document, or {@code null} if failed.
+ * @see DocumentsProvider#findPath(String)
+ *
+ * {@hide}
+ */
+ public static Path findPath(ContentResolver resolver, Uri documentUri)
+ throws RemoteException {
+ final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+ documentUri.getAuthority());
+ try {
+ return findPath(client, documentUri);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to find path", e);
+ return null;
+ } finally {
+ ContentProviderClient.releaseQuietly(client);
+ }
+ }
+
+ /** {@hide} */
+ public static Path findPath(ContentProviderClient client, Uri documentUri)
+ throws RemoteException {
+ final Bundle in = new Bundle();
+ in.putParcelable(DocumentsContract.EXTRA_URI, documentUri);
+
+ final Bundle out = client.call(METHOD_FIND_PATH, null, in);
+
+ return out.getParcelable(DocumentsContract.EXTRA_RESULT);
+ }
+
+ /**
* Open the given image for thumbnail purposes, using any embedded EXIF
* thumbnail if available, and providing orientation hints from the parent
* image.
@@ -1345,4 +1384,51 @@
return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH, extras);
}
+
+ /**
+ * Holds a path from a root to a particular document under it.
+ *
+ * @hide
+ */
+ public static final class Path implements Parcelable {
+
+ public final String mRootId;
+ public final List<String> mPath;
+
+ /**
+ * Creates a Path.
+ * @param rootId the id of the root
+ * @param path the list of document ids from the root document
+ * at position 0 to the target document
+ */
+ public Path(String rootId, List<String> path) {
+ mRootId = rootId;
+ mPath = path;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mRootId);
+ dest.writeStringList(mPath);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<Path> CREATOR = new Creator<Path>() {
+ @Override
+ public Path createFromParcel(Parcel in) {
+ final String rootId = in.readString();
+ final List<String> path = in.createStringArrayList();
+ return new Path(rootId, path);
+ }
+
+ @Override
+ public Path[] newArray(int size) {
+ return new Path[size];
+ }
+ };
+ }
}
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 6117ce4..6234f6a 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -20,6 +20,7 @@
import static android.provider.DocumentsContract.METHOD_CREATE_DOCUMENT;
import static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT;
import static android.provider.DocumentsContract.METHOD_EJECT_ROOT;
+import static android.provider.DocumentsContract.METHOD_FIND_PATH;
import static android.provider.DocumentsContract.METHOD_IS_CHILD_DOCUMENT;
import static android.provider.DocumentsContract.METHOD_MOVE_DOCUMENT;
import static android.provider.DocumentsContract.METHOD_REMOVE_DOCUMENT;
@@ -33,6 +34,7 @@
import static android.provider.DocumentsContract.getTreeDocumentId;
import static android.provider.DocumentsContract.isTreeUri;
+import android.Manifest;
import android.annotation.CallSuper;
import android.content.ClipDescription;
import android.content.ContentProvider;
@@ -53,6 +55,7 @@
import android.os.ParcelFileDescriptor.OnCloseListener;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract.Path;
import android.util.Log;
import libcore.io.IoUtils;
@@ -323,6 +326,26 @@
}
/**
+ * Finds the canonical path to the root for the requested document. If there are
+ * more than one path to this document, return the most typical one.
+ *
+ * <p>This API assumes that document id has enough info to infer the root.
+ * Different roots should use different document id to refer to the same
+ * document.
+ *
+ * @param documentId the document which path is requested.
+ * @return the path of the requested document to the root, or null if
+ * such operation is not supported.
+ *
+ * @hide
+ */
+ public Path findPath(String documentId)
+ throws FileNotFoundException {
+ Log.w(TAG, "findPath is called on an unsupported provider.");
+ return null;
+ }
+
+ /**
* Return all roots currently provided. To display to users, you must define
* at least one root. You should avoid making network requests to keep this
* request fast.
@@ -873,6 +896,12 @@
// It's responsibility of the provider to revoke any grants, as the document may be
// still attached to another parents.
+ } else if (METHOD_FIND_PATH.equals(method)) {
+ getContext().enforceCallingPermission(Manifest.permission.MANAGE_DOCUMENTS, null);
+
+ final Path path = findPath(documentId);
+
+ out.putParcelable(DocumentsContract.EXTRA_RESULT, path);
} else {
throw new UnsupportedOperationException("Method not supported " + method);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f8b9361..0f4afae 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1853,7 +1853,6 @@
MOVED_TO_GLOBAL.add(Settings.Global.CALL_AUTO_RETRY);
MOVED_TO_GLOBAL.add(Settings.Global.DEBUG_APP);
MOVED_TO_GLOBAL.add(Settings.Global.WAIT_FOR_DEBUGGER);
- MOVED_TO_GLOBAL.add(Settings.Global.SHOW_PROCESSES);
MOVED_TO_GLOBAL.add(Settings.Global.ALWAYS_FINISH_ACTIVITIES);
MOVED_TO_GLOBAL.add(Settings.Global.TZINFO_UPDATE_CONTENT_URL);
MOVED_TO_GLOBAL.add(Settings.Global.TZINFO_UPDATE_METADATA_URL);
@@ -2791,7 +2790,8 @@
/**
* Control whether the process CPU usage meter should be shown.
*
- * @deprecated Use {@link Global#SHOW_PROCESSES} instead
+ * @deprecated This functionality is no longer available as of
+ * {@link android.os.Build.VERSION_CODES#N_MR1}.
*/
@Deprecated
public static final String SHOW_PROCESSES = Global.SHOW_PROCESSES;
@@ -6460,6 +6460,12 @@
public static final String WEB_ACTION_ENABLED = "web_action_enabled";
/**
+ * Has this pairable device been paired or upgraded from a previously paired system.
+ * @hide
+ */
+ public static final String DEVICE_PAIRED = "device_paired";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -8513,7 +8519,11 @@
/**
* Control whether the process CPU usage meter should be shown.
+ *
+ * @deprecated This functionality is no longer available as of
+ * {@link android.os.Build.VERSION_CODES#N_MR1}.
*/
+ @Deprecated
public static final String SHOW_PROCESSES = "show_processes";
/**
@@ -8968,6 +8978,14 @@
public static final String DATABASE_DOWNGRADE_REASON = "database_downgrade_reason";
/**
+ * Flag to toggle journal mode WAL on or off for the contacts database. WAL is enabled by
+ * default. Set to 0 to disable.
+ *
+ * @hide
+ */
+ public static final String CONTACTS_DATABASE_WAL_ENABLED = "contacts_database_wal_enabled";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index 8689dce..641e1ad 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -76,4 +76,5 @@
int onUserAdded(int userId, int parentId);
int onUserRemoved(int userId);
int attestKey(String alias, in KeymasterArguments params, out KeymasterCertificateChain chain);
+ int onDeviceOffBody();
}
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index b13e162..e6f58f5 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -450,6 +450,28 @@
}
/**
+ * Inform the notification manager about snoozing a specific notification.
+ * <p>
+ * Use this if your listener has a user interface that allows the user to snooze a notification
+ * until a given time. It should be called after the user snoozes a single notification using
+ * your UI; upon being informed, the notification manager will actually remove the notification
+ * and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback. When the
+ * snoozing period expires, you will get a
+ * {@link #onNotificationPosted(StatusBarNotification, RankingMap)} callback for the
+ * notification.
+ * @param key The key of the notification to snooze
+ * @param snoozeUntil A time in the future, in milliseconds.
+ */
+ public final void snoozeNotification(String key, long snoozeUntil) {
+ if (!isBound()) return;
+ try {
+ getNotificationInterface().snoozeNotificationFromListener(mWrapper, key, snoozeUntil);
+ } catch (android.os.RemoteException ex) {
+ Log.v(TAG, "Unable to contact notification manager", ex);
+ }
+ }
+
+ /**
* Inform the notification manager that these notifications have been viewed by the
* user. This should only be called when there is sufficient confidence that the user is
* looking at the notifications, such as when the notifications appear on the screen due to
diff --git a/core/java/android/service/notification/NotificationRankerService.java b/core/java/android/service/notification/NotificationRankerService.java
index 261d82d..928d5d8 100644
--- a/core/java/android/service/notification/NotificationRankerService.java
+++ b/core/java/android/service/notification/NotificationRankerService.java
@@ -102,6 +102,9 @@
/** Notification was canceled by the user banning the channel. */
public static final int REASON_CHANNEL_BANNED = 17;
+ /** Notification was snoozed. */
+ public static final int REASON_SNOOZED = 18;
+
private Handler mHandler;
/** @hide */
diff --git a/core/java/android/text/AutoText.java b/core/java/android/text/AutoText.java
index 04730ec..c5339a4 100644
--- a/core/java/android/text/AutoText.java
+++ b/core/java/android/text/AutoText.java
@@ -18,11 +18,10 @@
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
+import android.view.View;
import com.android.internal.util.XmlUtils;
-import android.view.View;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -97,10 +96,10 @@
sInstance = instance;
}
}
-
+
return instance;
}
-
+
/**
* Retrieves a possible spelling correction for the specified range
* of text. Returns null if no correction can be found.
@@ -119,7 +118,7 @@
*/
public static int getSize(View view) {
- return getInstance(view).getSize();
+ return getInstance(view).getSize();
}
/**
@@ -137,7 +136,7 @@
for (; here != TRIE_NULL; here = mTrie[here + TRIE_NEXT]) {
if (c == mTrie[here + TRIE_C]) {
- if ((i == end - 1)
+ if ((i == end - 1)
&& (mTrie[here + TRIE_OFF] != TRIE_NULL)) {
int off = mTrie[here + TRIE_OFF];
int len = mText.charAt(off);
@@ -174,7 +173,7 @@
while (true) {
XmlUtils.nextElement(parser);
- String element = parser.getName();
+ String element = parser.getName();
if (element == null || !(element.equals("word"))) {
break;
}
@@ -214,7 +213,7 @@
int herep = TRIE_ROOT;
// Keep track of the size of the dictionary
mSize++;
-
+
for (int i = 0; i < slen; i++) {
char c = src.charAt(i);
boolean found = false;
diff --git a/core/java/android/text/BidiFormatter.java b/core/java/android/text/BidiFormatter.java
index 59273f4..d84502f 100644
--- a/core/java/android/text/BidiFormatter.java
+++ b/core/java/android/text/BidiFormatter.java
@@ -16,11 +16,11 @@
package android.text;
+import static android.text.TextDirectionHeuristics.FIRSTSTRONG_LTR;
+
import android.annotation.Nullable;
import android.view.View;
-import static android.text.TextDirectionHeuristics.FIRSTSTRONG_LTR;
-
import java.util.Locale;
/**
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index 409994d..de8aa5a 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -16,19 +16,8 @@
package android.text;
-import com.android.internal.util.ArrayUtils;
-import org.ccil.cowan.tagsoup.HTMLSchema;
-import org.ccil.cowan.tagsoup.Parser;
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.InputSource;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-
import android.app.ActivityThread;
import android.app.Application;
-import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Typeface;
@@ -47,11 +36,21 @@
import android.text.style.StyleSpan;
import android.text.style.SubscriptSpan;
import android.text.style.SuperscriptSpan;
-import android.text.style.TextAppearanceSpan;
import android.text.style.TypefaceSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan;
+import com.android.internal.util.ArrayUtils;
+
+import org.ccil.cowan.tagsoup.HTMLSchema;
+import org.ccil.cowan.tagsoup.Parser;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index c596388..8967b70 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -16,8 +16,6 @@
package android.text;
-import android.text.TextUtils;
-
/**
* Bit definitions for an integer defining the basic content type of text
* held in an {@link Editable} object. Supported classes may be combined
@@ -51,19 +49,19 @@
* or flags.<p>
*/
public static final int TYPE_MASK_CLASS = 0x0000000f;
-
+
/**
* Mask of bits that determine the variation of
* the base content class.
*/
public static final int TYPE_MASK_VARIATION = 0x00000ff0;
-
+
/**
* Mask of bits that provide addition bit flags
* of options.
*/
public static final int TYPE_MASK_FLAGS = 0x00fff000;
-
+
/**
* Special content type for when no explicit type has been specified.
* This should be interpreted to mean that the target input connection
@@ -75,11 +73,11 @@
* flag is set.
*/
public static final int TYPE_NULL = 0x00000000;
-
+
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
-
+
/**
* Class for normal text. This class supports the following flags (only
* one of which should be set):
@@ -92,7 +90,7 @@
* variation, normal should be assumed.
*/
public static final int TYPE_CLASS_TEXT = 0x00000001;
-
+
/**
* Flag for {@link #TYPE_CLASS_TEXT}: capitalize all characters. Overrides
* {@link #TYPE_TEXT_FLAG_CAP_WORDS} and
@@ -101,7 +99,7 @@
* this only affects languages where there are upper-case and lower-case letters.
*/
public static final int TYPE_TEXT_FLAG_CAP_CHARACTERS = 0x00001000;
-
+
/**
* Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of
* every word. Overrides {@link #TYPE_TEXT_FLAG_CAP_SENTENCES}. This
@@ -110,7 +108,7 @@
* this only affects languages where there are upper-case and lower-case letters.
*/
public static final int TYPE_TEXT_FLAG_CAP_WORDS = 0x00002000;
-
+
/**
* Flag for {@link #TYPE_CLASS_TEXT}: capitalize the first character of
* each sentence. This value is explicitly defined
@@ -121,7 +119,7 @@
* this only affects languages where there are upper-case and lower-case letters.
*/
public static final int TYPE_TEXT_FLAG_CAP_SENTENCES = 0x00004000;
-
+
/**
* Flag for {@link #TYPE_CLASS_TEXT}: the user is entering free-form
* text that should have auto-correction applied to it. Without this flag,
@@ -135,7 +133,7 @@
* the IME offers an interface to show suggestions.
*/
public static final int TYPE_TEXT_FLAG_AUTO_CORRECT = 0x00008000;
-
+
/**
* Flag for {@link #TYPE_CLASS_TEXT}: the text editor (which means
* the application) is performing auto-completion of the text being entered
@@ -154,23 +152,23 @@
* it will rely on the Editor to pass completions/corrections.
*/
public static final int TYPE_TEXT_FLAG_AUTO_COMPLETE = 0x00010000;
-
+
/**
* Flag for {@link #TYPE_CLASS_TEXT}: multiple lines of text can be
- * entered into the field. If this flag is not set, the text field
+ * entered into the field. If this flag is not set, the text field
* will be constrained to a single line. The IME may also choose not to
* display an enter key when this flag is not set, as there should be no
* need to create new lines.
*/
public static final int TYPE_TEXT_FLAG_MULTI_LINE = 0x00020000;
-
+
/**
* Flag for {@link #TYPE_CLASS_TEXT}: the regular text view associated
* with this should not be multi-line, but when a fullscreen input method
* is providing text it should use multiple lines if it can.
*/
public static final int TYPE_TEXT_FLAG_IME_MULTI_LINE = 0x00040000;
-
+
/**
* Flag for {@link #TYPE_CLASS_TEXT}: the input method does not need to
* display any dictionary-based candidates. This is useful for text views that
@@ -191,36 +189,36 @@
public static final int TYPE_TEXT_FLAG_NO_SUGGESTIONS = 0x00080000;
// ----------------------------------------------------------------------
-
+
/**
* Default variation of {@link #TYPE_CLASS_TEXT}: plain old normal text.
*/
public static final int TYPE_TEXT_VARIATION_NORMAL = 0x00000000;
-
+
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering a URI.
*/
public static final int TYPE_TEXT_VARIATION_URI = 0x00000010;
-
+
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering an e-mail address.
*/
public static final int TYPE_TEXT_VARIATION_EMAIL_ADDRESS = 0x00000020;
-
+
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering the subject line of
* an e-mail.
*/
public static final int TYPE_TEXT_VARIATION_EMAIL_SUBJECT = 0x00000030;
-
+
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering a short, possibly informal
* message such as an instant message or a text message.
*/
public static final int TYPE_TEXT_VARIATION_SHORT_MESSAGE = 0x00000040;
-
+
/**
- * Variation of {@link #TYPE_CLASS_TEXT}: entering the content of a long, possibly
+ * Variation of {@link #TYPE_CLASS_TEXT}: entering the content of a long, possibly
* formal message such as the body of an e-mail.
*/
public static final int TYPE_TEXT_VARIATION_LONG_MESSAGE = 0x00000050;
@@ -229,34 +227,34 @@
* Variation of {@link #TYPE_CLASS_TEXT}: entering the name of a person.
*/
public static final int TYPE_TEXT_VARIATION_PERSON_NAME = 0x00000060;
-
+
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering a postal mailing address.
*/
public static final int TYPE_TEXT_VARIATION_POSTAL_ADDRESS = 0x00000070;
-
+
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering a password.
*/
public static final int TYPE_TEXT_VARIATION_PASSWORD = 0x00000080;
-
+
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering a password, which should
* be visible to the user.
*/
public static final int TYPE_TEXT_VARIATION_VISIBLE_PASSWORD = 0x00000090;
-
+
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering text inside of a web form.
*/
public static final int TYPE_TEXT_VARIATION_WEB_EDIT_TEXT = 0x000000a0;
-
+
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering text to filter contents
* of a list etc.
*/
public static final int TYPE_TEXT_VARIATION_FILTER = 0x000000b0;
-
+
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering text for phonetic
* pronunciation, such as a phonetic name field in contacts. This is mostly
@@ -264,7 +262,7 @@
* readings, like Japanese.
*/
public static final int TYPE_TEXT_VARIATION_PHONETIC = 0x000000c0;
-
+
/**
* Variation of {@link #TYPE_CLASS_TEXT}: entering e-mail address inside
* of a web form. This was added in
@@ -290,7 +288,7 @@
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
-
+
/**
* Class for numeric text. This class supports the following flags:
* {@link #TYPE_NUMBER_FLAG_SIGNED} and
@@ -301,19 +299,19 @@
* the variation, normal should be assumed.</p>
*/
public static final int TYPE_CLASS_NUMBER = 0x00000002;
-
+
/**
* Flag of {@link #TYPE_CLASS_NUMBER}: the number is signed, allowing
* a positive or negative sign at the start.
*/
public static final int TYPE_NUMBER_FLAG_SIGNED = 0x00001000;
-
+
/**
* Flag of {@link #TYPE_CLASS_NUMBER}: the number is decimal, allowing
* a decimal point to provide fractional values.
*/
public static final int TYPE_NUMBER_FLAG_DECIMAL = 0x00002000;
-
+
// ----------------------------------------------------------------------
/**
@@ -340,17 +338,17 @@
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
-
+
/**
* Class for a phone number. This class currently supports no variations
* or flags.
*/
public static final int TYPE_CLASS_PHONE = 0x00000003;
-
+
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
-
+
/**
* Class for dates and times. It supports the
* following variations:
@@ -359,19 +357,19 @@
* {@link #TYPE_DATETIME_VARIATION_TIME}.
*/
public static final int TYPE_CLASS_DATETIME = 0x00000004;
-
+
/**
* Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering
* both a date and time.
*/
public static final int TYPE_DATETIME_VARIATION_NORMAL = 0x00000000;
-
+
/**
* Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering
* only a date.
*/
public static final int TYPE_DATETIME_VARIATION_DATE = 0x00000010;
-
+
/**
* Default variation of {@link #TYPE_CLASS_DATETIME}: allows entering
* only a time.
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 2a52961..03a2d62 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -16,11 +16,9 @@
package android.text;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
-import android.graphics.RectF;
import android.text.Layout.Directions;
import android.text.Layout.TabStops;
import android.text.style.CharacterStyle;
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 23b22d1..6262fc2 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -60,8 +60,6 @@
import com.android.internal.R;
import com.android.internal.util.ArrayUtils;
-import libcore.icu.ICU;
-
import java.lang.reflect.Array;
import java.util.Iterator;
import java.util.List;
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 3ed37b36..b5a8aca 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -23,15 +23,15 @@
import android.text.Spanned;
import android.text.SpannedString;
+import libcore.icu.ICU;
+import libcore.icu.LocaleData;
+
+import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;
-import java.text.SimpleDateFormat;
-
-import libcore.icu.ICU;
-import libcore.icu.LocaleData;
/**
* Utility class for producing strings with formatted date/time.
diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java
index cb8852c..f16e714 100644
--- a/core/java/android/text/format/DateUtils.java
+++ b/core/java/android/text/format/DateUtils.java
@@ -16,12 +16,16 @@
package android.text.format;
-import com.android.internal.R;
-
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
+import com.android.internal.R;
+
+import libcore.icu.DateIntervalFormat;
+import libcore.icu.LocaleData;
+import libcore.icu.RelativeDateTimeFormatter;
+
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
@@ -30,10 +34,6 @@
import java.util.Locale;
import java.util.TimeZone;
-import libcore.icu.DateIntervalFormat;
-import libcore.icu.LocaleData;
-import libcore.icu.RelativeDateTimeFormatter;
-
/**
* This class contains various date-related utilities for creating text for things like
* elapsed time and date ranges, strings for days of the week and months, and AM/PM text etc.
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index be52464..b67ac98 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -20,11 +20,10 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
+import android.net.NetworkUtils;
import android.text.BidiFormatter;
import android.text.TextUtils;
import android.view.View;
-import android.net.NetworkUtils;
-import android.net.TrafficStats;
import java.util.Locale;
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index 69c2cff..bbd9c9c 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -18,13 +18,13 @@
import android.util.TimeFormatException;
+import libcore.util.ZoneInfo;
+import libcore.util.ZoneInfoDB;
+
import java.io.IOException;
import java.util.Locale;
import java.util.TimeZone;
-import libcore.util.ZoneInfo;
-import libcore.util.ZoneInfoDB;
-
/**
* An alternative to the {@link java.util.Calendar} and
* {@link java.util.GregorianCalendar} classes. An instance of the Time class represents
diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java
index 3a63805..5a14092 100644
--- a/core/java/android/text/format/TimeFormatter.java
+++ b/core/java/android/text/format/TimeFormatter.java
@@ -22,12 +22,13 @@
import android.content.res.Resources;
+import libcore.icu.LocaleData;
+import libcore.util.ZoneInfo;
+
import java.nio.CharBuffer;
import java.util.Formatter;
import java.util.Locale;
import java.util.TimeZone;
-import libcore.icu.LocaleData;
-import libcore.util.ZoneInfo;
/**
* Formatting logic for {@link Time}. Contains a port of Bionic's broken strftime_tz to Java.
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 14e0b4f..90559dc 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -19,19 +19,22 @@
import android.graphics.Paint;
import android.icu.lang.UCharacter;
import android.icu.lang.UProperty;
-import android.view.KeyEvent;
-import android.view.View;
-import android.text.*;
+import android.text.Editable;
+import android.text.Emoji;
+import android.text.InputType;
+import android.text.Layout;
+import android.text.NoCopySpan;
+import android.text.Selection;
+import android.text.Spanned;
import android.text.method.TextKeyListener.Capitalize;
import android.text.style.ReplacementSpan;
+import android.view.KeyEvent;
+import android.view.View;
import android.widget.TextView;
import com.android.internal.annotations.GuardedBy;
import java.text.BreakIterator;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
/**
* Abstract base class for key listeners.
diff --git a/core/java/android/text/method/CharacterPickerDialog.java b/core/java/android/text/method/CharacterPickerDialog.java
index 880e46d..7d838e0 100644
--- a/core/java/android/text/method/CharacterPickerDialog.java
+++ b/core/java/android/text/method/CharacterPickerDialog.java
@@ -16,24 +16,25 @@
package android.text.method;
-import com.android.internal.R;
-
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
-import android.text.*;
+import android.text.Editable;
+import android.text.Selection;
import android.view.LayoutInflater;
-import android.view.View.OnClickListener;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
-import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.GridView;
+import com.android.internal.R;
+
/**
* Dialog for choosing accented characters related to a base character.
*/
diff --git a/core/java/android/text/method/DateKeyListener.java b/core/java/android/text/method/DateKeyListener.java
index e6f63d1..88ef388 100644
--- a/core/java/android/text/method/DateKeyListener.java
+++ b/core/java/android/text/method/DateKeyListener.java
@@ -16,8 +16,8 @@
package android.text.method;
-import android.view.KeyEvent;
import android.text.InputType;
+import android.view.KeyEvent;
/**
* For entering dates in a text field.
@@ -32,7 +32,7 @@
return InputType.TYPE_CLASS_DATETIME
| InputType.TYPE_DATETIME_VARIATION_DATE;
}
-
+
@Override
protected char[] getAcceptedChars()
{
diff --git a/core/java/android/text/method/DialerKeyListener.java b/core/java/android/text/method/DialerKeyListener.java
index bb8b0de..17abed6 100644
--- a/core/java/android/text/method/DialerKeyListener.java
+++ b/core/java/android/text/method/DialerKeyListener.java
@@ -16,10 +16,10 @@
package android.text.method;
-import android.view.KeyEvent;
-import android.view.KeyCharacterMap.KeyData;
import android.text.InputType;
import android.text.Spannable;
+import android.view.KeyCharacterMap.KeyData;
+import android.view.KeyEvent;
/**
* For dialing-only text entry
@@ -47,7 +47,7 @@
public int getInputType() {
return InputType.TYPE_CLASS_PHONE;
}
-
+
/**
* Overrides the superclass's lookup method to prefer the number field
* from the KeyEvent.
diff --git a/core/java/android/text/method/DigitsKeyListener.java b/core/java/android/text/method/DigitsKeyListener.java
index c95df46..4aeb39a 100644
--- a/core/java/android/text/method/DigitsKeyListener.java
+++ b/core/java/android/text/method/DigitsKeyListener.java
@@ -17,8 +17,8 @@
package android.text.method;
import android.text.InputType;
-import android.text.Spanned;
import android.text.SpannableStringBuilder;
+import android.text.Spanned;
import android.view.KeyEvent;
@@ -133,7 +133,7 @@
}
return contentType;
}
-
+
@Override
public CharSequence filter(CharSequence source, int start, int end,
Spanned dest, int dstart, int dend) {
diff --git a/core/java/android/text/method/MetaKeyKeyListener.java b/core/java/android/text/method/MetaKeyKeyListener.java
index e9db5fd..c3c7302 100644
--- a/core/java/android/text/method/MetaKeyKeyListener.java
+++ b/core/java/android/text/method/MetaKeyKeyListener.java
@@ -20,9 +20,9 @@
import android.text.NoCopySpan;
import android.text.Spannable;
import android.text.Spanned;
+import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.view.KeyCharacterMap;
/**
* This base class encapsulates the behavior for tracking the state of
@@ -86,7 +86,7 @@
* Value equals {@link KeyEvent#META_SYM_ON}.
*/
public static final int META_SYM_ON = KeyEvent.META_SYM_ON;
-
+
/**
* Flag that indicates that the SHIFT key is locked in CAPS mode.
*/
@@ -111,11 +111,11 @@
private static final long META_CAP_USED = 1L << 32;
private static final long META_ALT_USED = 1L << 33;
private static final long META_SYM_USED = 1L << 34;
-
+
private static final long META_CAP_PRESSED = 1L << 40;
private static final long META_ALT_PRESSED = 1L << 41;
private static final long META_SYM_PRESSED = 1L << 42;
-
+
private static final long META_CAP_RELEASED = 1L << 48;
private static final long META_ALT_RELEASED = 1L << 49;
private static final long META_SYM_RELEASED = 1L << 50;
@@ -129,7 +129,7 @@
private static final long META_SYM_MASK = META_SYM_ON
| META_SYM_LOCKED | META_SYM_USED
| META_SYM_PRESSED | META_SYM_RELEASED;
-
+
private static final Object CAP = new NoCopySpan.Concrete();
private static final Object ALT = new NoCopySpan.Concrete();
private static final Object SYM = new NoCopySpan.Concrete();
@@ -150,7 +150,7 @@
/**
* Gets the state of the meta keys.
- *
+ *
* @param text the buffer in which the meta key would have been pressed.
*
* @return an integer in which each bit set to one represents a pressed
@@ -448,7 +448,7 @@
/**
* Gets the state of the meta keys.
- *
+ *
* @param state the current meta state bits.
*
* @return an integer in which each bit set to one represents a pressed
@@ -635,26 +635,26 @@
/**
* The meta key has been pressed but has not yet been used.
*/
- private static final int PRESSED =
+ private static final int PRESSED =
Spannable.SPAN_MARK_MARK | (1 << Spannable.SPAN_USER_SHIFT);
/**
* The meta key has been pressed and released but has still
* not yet been used.
*/
- private static final int RELEASED =
+ private static final int RELEASED =
Spannable.SPAN_MARK_MARK | (2 << Spannable.SPAN_USER_SHIFT);
/**
* The meta key has been pressed and used but has not yet been released.
*/
- private static final int USED =
+ private static final int USED =
Spannable.SPAN_MARK_MARK | (3 << Spannable.SPAN_USER_SHIFT);
/**
* The meta key has been pressed and released without use, and then
* pressed again; it may also have been released again.
*/
- private static final int LOCKED =
+ private static final int LOCKED =
Spannable.SPAN_MARK_MARK | (4 << Spannable.SPAN_USER_SHIFT);
}
diff --git a/core/java/android/text/method/MovementMethod.java b/core/java/android/text/method/MovementMethod.java
index 01979fd..f6fe575 100644
--- a/core/java/android/text/method/MovementMethod.java
+++ b/core/java/android/text/method/MovementMethod.java
@@ -16,10 +16,10 @@
package android.text.method;
-import android.widget.TextView;
+import android.text.Spannable;
import android.view.KeyEvent;
import android.view.MotionEvent;
-import android.text.*;
+import android.widget.TextView;
/**
* Provides cursor positioning, scrolling and text selection functionality in a {@link TextView}.
diff --git a/core/java/android/text/method/MultiTapKeyListener.java b/core/java/android/text/method/MultiTapKeyListener.java
index 95ac0a1..5770482 100644
--- a/core/java/android/text/method/MultiTapKeyListener.java
+++ b/core/java/android/text/method/MultiTapKeyListener.java
@@ -16,13 +16,16 @@
package android.text.method;
-import android.view.KeyEvent;
-import android.view.View;
import android.os.Handler;
import android.os.SystemClock;
-import android.text.*;
+import android.text.Editable;
+import android.text.Selection;
+import android.text.SpanWatcher;
+import android.text.Spannable;
import android.text.method.TextKeyListener.Capitalize;
import android.util.SparseArray;
+import android.view.KeyEvent;
+import android.view.View;
/**
* This is the standard key listener for alphabetic input on 12-key
@@ -81,7 +84,7 @@
public int getInputType() {
return makeTextContentType(mCapitalize, mAutoText);
}
-
+
public boolean onKeyDown(View view, Editable content,
int keyCode, KeyEvent event) {
int selStart, selEnd;
@@ -198,7 +201,7 @@
if (selEnd != oldStart) {
Selection.setSelection(content, oldStart, selEnd);
- content.setSpan(TextKeyListener.LAST_TYPED,
+ content.setSpan(TextKeyListener.LAST_TYPED,
oldStart, selEnd,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java
index 988d566..6b12b7e 100644
--- a/core/java/android/text/method/NumberKeyListener.java
+++ b/core/java/android/text/method/NumberKeyListener.java
@@ -16,14 +16,14 @@
package android.text.method;
-import android.view.KeyEvent;
-import android.view.View;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
+import android.view.KeyEvent;
+import android.view.View;
/**
* For numeric text entry
@@ -91,7 +91,7 @@
return false;
}
-
+
@Override
public boolean onKeyDown(View view, Editable content,
int keyCode, KeyEvent event) {
diff --git a/core/java/android/text/method/PasswordTransformationMethod.java b/core/java/android/text/method/PasswordTransformationMethod.java
index 88a69b9..4485e38 100644
--- a/core/java/android/text/method/PasswordTransformationMethod.java
+++ b/core/java/android/text/method/PasswordTransformationMethod.java
@@ -16,18 +16,18 @@
package android.text.method;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
-import android.graphics.Rect;
-import android.view.View;
import android.text.Editable;
import android.text.GetChars;
import android.text.NoCopySpan;
+import android.text.Spannable;
+import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
-import android.text.Spanned;
-import android.text.Spannable;
import android.text.style.UpdateLayout;
+import android.view.View;
import java.lang.ref.WeakReference;
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index b17f502..bea68b1 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -16,7 +16,12 @@
package android.text.method;
-import android.text.*;
+import android.text.AutoText;
+import android.text.Editable;
+import android.text.NoCopySpan;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.TextUtils;
import android.text.method.TextKeyListener.Capitalize;
import android.util.SparseArray;
import android.view.KeyCharacterMap;
@@ -80,7 +85,7 @@
public int getInputType() {
return makeTextContentType(mAutoCap, mAutoText);
}
-
+
public boolean onKeyDown(View view, Editable content,
int keyCode, KeyEvent event) {
int selStart, selEnd;
@@ -191,9 +196,9 @@
}
}
- if ((pref & TextKeyListener.AUTO_CAP) != 0 &&
- Character.isLowerCase(i) &&
- TextKeyListener.shouldCap(mAutoCap, content, selStart)) {
+ if ((pref & TextKeyListener.AUTO_CAP) != 0
+ && Character.isLowerCase(i)
+ && TextKeyListener.shouldCap(mAutoCap, content, selStart)) {
int where = content.getSpanEnd(TextKeyListener.CAPPED);
int flags = content.getSpanFlags(TextKeyListener.CAPPED);
@@ -361,9 +366,9 @@
View view) {
int len = end - start;
boolean changecase = false;
-
+
String replacement = AutoText.get(src, start, end, view);
-
+
if (replacement == null) {
String key = TextUtils.substring(src, start, end).toLowerCase();
replacement = AutoText.get(key, 0, end - start, view);
@@ -372,7 +377,7 @@
if (replacement == null)
return null;
}
-
+
int caps = 0;
if (changecase) {
diff --git a/core/java/android/text/method/ScrollingMovementMethod.java b/core/java/android/text/method/ScrollingMovementMethod.java
index b9f5d5f4..4f422cb 100644
--- a/core/java/android/text/method/ScrollingMovementMethod.java
+++ b/core/java/android/text/method/ScrollingMovementMethod.java
@@ -16,10 +16,11 @@
package android.text.method;
+import android.text.Layout;
+import android.text.Spannable;
import android.view.MotionEvent;
-import android.text.*;
-import android.widget.TextView;
import android.view.View;
+import android.widget.TextView;
/**
* A movement method that interprets movement keys by scrolling the text buffer.
diff --git a/core/java/android/text/method/TextKeyListener.java b/core/java/android/text/method/TextKeyListener.java
index 994f3d7..9cbda9c 100644
--- a/core/java/android/text/method/TextKeyListener.java
+++ b/core/java/android/text/method/TextKeyListener.java
@@ -22,11 +22,16 @@
import android.os.Handler;
import android.provider.Settings;
import android.provider.Settings.System;
-import android.text.*;
+import android.text.Editable;
+import android.text.InputType;
+import android.text.NoCopySpan;
+import android.text.Selection;
+import android.text.SpanWatcher;
+import android.text.Spannable;
+import android.text.TextUtils;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.text.InputType;
import java.lang.ref.WeakReference;
@@ -127,7 +132,7 @@
public int getInputType() {
return makeTextContentType(mAutoCap, mAutoText);
}
-
+
@Override
public boolean onKeyDown(View view, Editable content,
int keyCode, KeyEvent event) {
@@ -213,7 +218,7 @@
public int getInputType() {
return InputType.TYPE_NULL;
}
-
+
public boolean onKeyDown(View view, Editable content,
int keyCode, KeyEvent event) {
return false;
@@ -230,7 +235,7 @@
public void clearMetaKeyState(View view, Editable content, int states) {
}
-
+
public static NullKeyListener getInstance() {
if (sInstance != null)
return sInstance;
diff --git a/core/java/android/text/method/TimeKeyListener.java b/core/java/android/text/method/TimeKeyListener.java
index c5bfd5c..01f4086 100644
--- a/core/java/android/text/method/TimeKeyListener.java
+++ b/core/java/android/text/method/TimeKeyListener.java
@@ -16,8 +16,8 @@
package android.text.method;
-import android.view.KeyEvent;
import android.text.InputType;
+import android.view.KeyEvent;
/**
* For entering times in a text field.
@@ -32,7 +32,7 @@
return InputType.TYPE_CLASS_DATETIME
| InputType.TYPE_DATETIME_VARIATION_TIME;
}
-
+
@Override
protected char[] getAcceptedChars()
{
diff --git a/core/java/android/text/method/WordIterator.java b/core/java/android/text/method/WordIterator.java
index 89ed08c..17938a8 100644
--- a/core/java/android/text/method/WordIterator.java
+++ b/core/java/android/text/method/WordIterator.java
@@ -18,8 +18,8 @@
import android.annotation.NonNull;
import android.icu.text.BreakIterator;
-import android.text.Selection;
import android.text.CharSequenceCharacterIterator;
+import android.text.Selection;
import java.util.Locale;
diff --git a/core/java/android/text/style/DrawableMarginSpan.java b/core/java/android/text/style/DrawableMarginSpan.java
index 20b6886..3524179 100644
--- a/core/java/android/text/style/DrawableMarginSpan.java
+++ b/core/java/android/text/style/DrawableMarginSpan.java
@@ -16,11 +16,11 @@
package android.text.style;
-import android.graphics.drawable.Drawable;
-import android.graphics.Paint;
import android.graphics.Canvas;
-import android.text.Spanned;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
import android.text.Layout;
+import android.text.Spanned;
public class DrawableMarginSpan
implements LeadingMarginSpan, LineHeightSpan
diff --git a/core/java/android/text/style/IconMarginSpan.java b/core/java/android/text/style/IconMarginSpan.java
index cf9a705..304c83f 100644
--- a/core/java/android/text/style/IconMarginSpan.java
+++ b/core/java/android/text/style/IconMarginSpan.java
@@ -16,11 +16,11 @@
package android.text.style;
-import android.graphics.Paint;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.text.Spanned;
+import android.graphics.Paint;
import android.text.Layout;
+import android.text.Spanned;
public class IconMarginSpan
implements LeadingMarginSpan, LineHeightSpan
diff --git a/core/java/android/text/style/LeadingMarginSpan.java b/core/java/android/text/style/LeadingMarginSpan.java
index 339d885..5bd2d60 100644
--- a/core/java/android/text/style/LeadingMarginSpan.java
+++ b/core/java/android/text/style/LeadingMarginSpan.java
@@ -16,8 +16,8 @@
package android.text.style;
-import android.graphics.Paint;
import android.graphics.Canvas;
+import android.graphics.Paint;
import android.os.Parcel;
import android.text.Layout;
import android.text.ParcelableSpan;
@@ -39,7 +39,7 @@
* Returns the amount by which to adjust the leading margin. Positive values
* move away from the leading edge of the paragraph, negative values move
* towards it.
- *
+ *
* @param first true if the request is for the first line of a paragraph,
* false for subsequent lines
* @return the offset for the margin.
@@ -49,7 +49,7 @@
/**
* Renders the leading margin. This is called before the margin has been
* adjusted by the value returned by {@link #getLeadingMargin(boolean)}.
- *
+ *
* @param c the canvas
* @param p the paint. The this should be left unchanged on exit.
* @param x the current position of the margin
@@ -98,11 +98,11 @@
*/
public static class Standard implements LeadingMarginSpan, ParcelableSpan {
private final int mFirst, mRest;
-
+
/**
* Constructor taking separate indents for the first and subsequent
* lines.
- *
+ *
* @param first the indent for the first line of the paragraph
* @param rest the indent for the remaining lines of the paragraph
*/
@@ -123,7 +123,7 @@
mFirst = src.readInt();
mRest = src.readInt();
}
-
+
public int getSpanTypeId() {
return getSpanTypeIdInternal();
}
@@ -132,7 +132,7 @@
public int getSpanTypeIdInternal() {
return TextUtils.LEADING_MARGIN_SPAN;
}
-
+
public int describeContents() {
return 0;
}
diff --git a/core/java/android/text/style/LineBackgroundSpan.java b/core/java/android/text/style/LineBackgroundSpan.java
index 854aeaf..9c7859f 100644
--- a/core/java/android/text/style/LineBackgroundSpan.java
+++ b/core/java/android/text/style/LineBackgroundSpan.java
@@ -16,8 +16,8 @@
package android.text.style;
-import android.graphics.Paint;
import android.graphics.Canvas;
+import android.graphics.Paint;
public interface LineBackgroundSpan
extends ParagraphStyle
diff --git a/core/java/android/text/style/LocaleSpan.java b/core/java/android/text/style/LocaleSpan.java
index b842851..479ff0e 100644
--- a/core/java/android/text/style/LocaleSpan.java
+++ b/core/java/android/text/style/LocaleSpan.java
@@ -16,8 +16,6 @@
package android.text.style;
-import com.android.internal.util.Preconditions;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Paint;
@@ -27,6 +25,8 @@
import android.text.TextPaint;
import android.text.TextUtils;
+import com.android.internal.util.Preconditions;
+
import java.util.Locale;
/**
diff --git a/core/java/android/text/style/QuoteSpan.java b/core/java/android/text/style/QuoteSpan.java
index 0b0a82c..7217e1e 100644
--- a/core/java/android/text/style/QuoteSpan.java
+++ b/core/java/android/text/style/QuoteSpan.java
@@ -17,8 +17,8 @@
package android.text.style;
import android.annotation.ColorInt;
-import android.graphics.Paint;
import android.graphics.Canvas;
+import android.graphics.Paint;
import android.os.Parcel;
import android.text.Layout;
import android.text.ParcelableSpan;
@@ -34,7 +34,7 @@
super();
mColor = 0xff0000ff;
}
-
+
public QuoteSpan(@ColorInt int color) {
super();
mColor = color;
@@ -43,7 +43,7 @@
public QuoteSpan(Parcel src) {
mColor = src.readInt();
}
-
+
public int getSpanTypeId() {
return getSpanTypeIdInternal();
}
@@ -52,7 +52,7 @@
public int getSpanTypeIdInternal() {
return TextUtils.QUOTE_SPAN;
}
-
+
public int describeContents() {
return 0;
}
@@ -70,7 +70,7 @@
public int getColor() {
return mColor;
}
-
+
public int getLeadingMargin(boolean first) {
return STRIPE_WIDTH + GAP_WIDTH;
}
diff --git a/core/java/android/text/style/ReplacementSpan.java b/core/java/android/text/style/ReplacementSpan.java
index 07190b2..5f94ad0 100644
--- a/core/java/android/text/style/ReplacementSpan.java
+++ b/core/java/android/text/style/ReplacementSpan.java
@@ -19,8 +19,8 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.graphics.Paint;
import android.graphics.Canvas;
+import android.graphics.Paint;
import android.text.TextPaint;
public abstract class ReplacementSpan extends MetricAffectingSpan {
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index e9153dd..c5e5df0 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -16,14 +16,14 @@
package android.text.style;
-import java.text.NumberFormat;
-import java.util.Locale;
-
import android.os.Parcel;
import android.os.PersistableBundle;
import android.text.ParcelableSpan;
import android.text.TextUtils;
+import java.text.NumberFormat;
+import java.util.Locale;
+
/**
* A span that supplies additional meta-data for the associated text intended
* for text-to-speech engines. If the text is being processed by a
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index ca037a2..7e6eb49 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -20,16 +20,21 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.telephony.PhoneNumberUtils;
-import android.text.method.LinkMovementMethod;
-import android.text.method.MovementMethod;
-import android.text.style.URLSpan;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
+import android.text.method.LinkMovementMethod;
+import android.text.method.MovementMethod;
+import android.text.style.URLSpan;
import android.util.Patterns;
import android.webkit.WebView;
import android.widget.TextView;
+import com.android.i18n.phonenumbers.PhoneNumberMatch;
+import com.android.i18n.phonenumbers.PhoneNumberUtil;
+import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency;
+
+import libcore.util.EmptyArray;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Retention;
@@ -42,12 +47,6 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import com.android.i18n.phonenumbers.PhoneNumberMatch;
-import com.android.i18n.phonenumbers.PhoneNumberUtil;
-import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency;
-
-import libcore.util.EmptyArray;
-
/**
* Linkify take a piece of text and a regular expression and turns all of the
* regex matches in the text into clickable links. This is particularly
diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java
index a95da97..b6d8aa4 100644
--- a/core/java/android/transition/ChangeBounds.java
+++ b/core/java/android/transition/ChangeBounds.java
@@ -16,19 +16,18 @@
package android.transition;
-import android.animation.AnimatorSet;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.PointF;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.RectEvaluator;
+import android.content.Context;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Path;
+import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
diff --git a/core/java/android/transition/ChangeScroll.java b/core/java/android/transition/ChangeScroll.java
index e092685..8a3fd1c 100644
--- a/core/java/android/transition/ChangeScroll.java
+++ b/core/java/android/transition/ChangeScroll.java
@@ -19,8 +19,6 @@
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.content.Context;
-import android.transition.Transition;
-import android.transition.TransitionValues;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
diff --git a/core/java/android/transition/ChangeTransform.java b/core/java/android/transition/ChangeTransform.java
index 9749121..4b0b065 100644
--- a/core/java/android/transition/ChangeTransform.java
+++ b/core/java/android/transition/ChangeTransform.java
@@ -30,6 +30,7 @@
import android.view.GhostView;
import android.view.View;
import android.view.ViewGroup;
+
import com.android.internal.R;
/**
diff --git a/core/java/android/transition/Explode.java b/core/java/android/transition/Explode.java
index 3445ef2..5f078ca 100644
--- a/core/java/android/transition/Explode.java
+++ b/core/java/android/transition/Explode.java
@@ -15,8 +15,6 @@
*/
package android.transition;
-import com.android.internal.R;
-
import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.content.Context;
@@ -26,6 +24,8 @@
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
+
+import com.android.internal.R;
/**
* This transition tracks changes to the visibility of target views in the
* start and end scenes and moves views in or out from the edges of the
diff --git a/core/java/android/transition/PatternPathMotion.java b/core/java/android/transition/PatternPathMotion.java
index f23863f..7a2c191 100644
--- a/core/java/android/transition/PatternPathMotion.java
+++ b/core/java/android/transition/PatternPathMotion.java
@@ -15,8 +15,6 @@
*/
package android.transition;
-import com.android.internal.R;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Matrix;
@@ -25,6 +23,8 @@
import android.util.AttributeSet;
import android.util.PathParser;
+import com.android.internal.R;
+
/**
* A PathMotion that takes a Path pattern and applies it to the separation between two points.
* The starting point of the Path will be moved to the origin and the end point will be scaled
diff --git a/core/java/android/transition/Slide.java b/core/java/android/transition/Slide.java
index 2645f86..9cf3210 100644
--- a/core/java/android/transition/Slide.java
+++ b/core/java/android/transition/Slide.java
@@ -26,6 +26,7 @@
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
+
import com.android.internal.R;
import java.lang.annotation.Retention;
diff --git a/core/java/android/transition/TransitionInflater.java b/core/java/android/transition/TransitionInflater.java
index cbf76bc..4c5a717 100644
--- a/core/java/android/transition/TransitionInflater.java
+++ b/core/java/android/transition/TransitionInflater.java
@@ -17,11 +17,6 @@
package android.transition;
import android.annotation.TransitionRes;
-import com.android.internal.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -32,6 +27,11 @@
import android.view.InflateException;
import android.view.ViewGroup;
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
diff --git a/core/java/android/transition/TranslationAnimationCreator.java b/core/java/android/transition/TranslationAnimationCreator.java
index b07f3f8..ae76e62 100644
--- a/core/java/android/transition/TranslationAnimationCreator.java
+++ b/core/java/android/transition/TranslationAnimationCreator.java
@@ -15,8 +15,6 @@
*/
package android.transition;
-import com.android.internal.R;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -25,6 +23,8 @@
import android.transition.Transition.TransitionListener;
import android.view.View;
+import com.android.internal.R;
+
/**
* This class is used by Slide and Explode to create an animator that goes from the start
* position to the end position. It takes into account the canceled position so that it
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index f4db4d6..b7099b6 100644
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -268,6 +268,10 @@
}
public void setTo(DisplayMetrics o) {
+ if (this == o) {
+ return;
+ }
+
widthPixels = o.widthPixels;
heightPixels = o.heightPixels;
density = o.density;
diff --git a/core/java/android/util/LocalLog.java b/core/java/android/util/LocalLog.java
index 39f66a5..665c583 100644
--- a/core/java/android/util/LocalLog.java
+++ b/core/java/android/util/LocalLog.java
@@ -20,44 +20,49 @@
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.Iterator;
-import java.util.LinkedList;
+import java.util.Deque;
+import java.util.ArrayDeque;
/**
* @hide
*/
public final class LocalLog {
- private LinkedList<String> mLog;
- private int mMaxLines;
- private long mNow;
+ private final Deque<String> mLog;
+ private final int mMaxLines;
public LocalLog(int maxLines) {
- mLog = new LinkedList<String>();
- mMaxLines = maxLines;
+ mMaxLines = Math.max(0, maxLines);
+ mLog = new ArrayDeque<>(mMaxLines);
}
- public synchronized void log(String msg) {
- if (mMaxLines > 0) {
- mNow = System.currentTimeMillis();
- StringBuilder sb = new StringBuilder();
- Calendar c = Calendar.getInstance();
- c.setTimeInMillis(mNow);
- sb.append(String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c));
- mLog.add(sb.toString() + " - " + msg);
- while (mLog.size() > mMaxLines) mLog.remove();
+ public void log(String msg) {
+ if (mMaxLines <= 0) {
+ return;
}
+ Calendar c = Calendar.getInstance();
+ c.setTimeInMillis(System.currentTimeMillis());
+ append(String.format("%tm-%td %tH:%tM:%tS.%tL - %s", c, c, c, c, c, c, msg));
+ }
+
+ private synchronized void append(String logLine) {
+ while (mLog.size() >= mMaxLines) {
+ mLog.remove();
+ }
+ mLog.add(logLine);
}
public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- Iterator<String> itr = mLog.listIterator(0);
+ Iterator<String> itr = mLog.iterator();
while (itr.hasNext()) {
pw.println(itr.next());
}
}
public synchronized void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) {
- for (int i = mLog.size() - 1; i >= 0; i--) {
- pw.println(mLog.get(i));
+ Iterator<String> itr = mLog.descendingIterator();
+ while (itr.hasNext()) {
+ pw.println(itr.next());
}
}
@@ -69,6 +74,9 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
mLog.dump(fd, pw, args);
}
+ public void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ mLog.reverseDump(fd, pw, args);
+ }
}
public ReadOnlyLocalLog readOnlyLocalLog() {
diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java
index f1c8c7d..6f314d0 100644
--- a/core/java/android/util/PathParser.java
+++ b/core/java/android/util/PathParser.java
@@ -16,6 +16,8 @@
import android.graphics.Path;
+import dalvik.annotation.optimization.FastNative;
+
/**
* @hide
*/
@@ -119,14 +121,24 @@
// Native functions are defined below.
private static native void nParseStringForPath(long pathPtr, String pathString,
int stringLength);
- private static native void nCreatePathFromPathData(long outPathPtr, long pathData);
- private static native long nCreateEmptyPathData();
- private static native long nCreatePathData(long nativePtr);
private static native long nCreatePathDataFromString(String pathString, int stringLength);
+
+ // ----------------- @FastNative -----------------------
+
+ @FastNative
+ private static native void nCreatePathFromPathData(long outPathPtr, long pathData);
+ @FastNative
+ private static native long nCreateEmptyPathData();
+ @FastNative
+ private static native long nCreatePathData(long nativePtr);
+ @FastNative
private static native boolean nInterpolatePathData(long outDataPtr, long fromDataPtr,
long toDataPtr, float fraction);
+ @FastNative
private static native void nFinalize(long nativePtr);
+ @FastNative
private static native boolean nCanMorph(long fromDataPtr, long toDataPtr);
+ @FastNative
private static native void nSetPathData(long outDataPtr, long fromDataPtr);
}
diff --git a/core/java/android/util/proto/EncodedBuffer.java b/core/java/android/util/proto/EncodedBuffer.java
new file mode 100644
index 0000000..ed38e6f
--- /dev/null
+++ b/core/java/android/util/proto/EncodedBuffer.java
@@ -0,0 +1,678 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto;
+
+import android.annotation.TestApi;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * A stream of bytes containing a read pointer and a write pointer,
+ * backed by a set of fixed-size buffers. There are write functions for the
+ * primitive types stored by protocol buffers, but none of the logic
+ * for tags, inner objects, or any of that.
+ *
+ * Terminology:
+ * *Pos: Position in the whole data set (as if it were a single buffer).
+ * *Index: Position within a buffer.
+ * *BufIndex: Index of a buffer within the mBuffers list
+ * @hide
+ */
+@TestApi
+public final class EncodedBuffer {
+ private static final String TAG = "EncodedBuffer";
+
+ private final ArrayList<byte[]> mBuffers = new ArrayList<byte[]>();
+
+ private final int mChunkSize;
+
+ /**
+ * The number of buffers in mBuffers. Stored separately to avoid the extra
+ * function call to size() everywhere for bounds checking.
+ */
+ private int mBufferCount;
+
+ /**
+ * The buffer we are currently writing to.
+ */
+ private byte[] mWriteBuffer;
+
+ /**
+ * The index into mWriteBuffer that we will write to next.
+ * It may point to the end of the buffer, in which case,
+ * the NEXT write will allocate a new buffer.
+ */
+ private int mWriteIndex;
+
+ /**
+ * The index of mWriteBuffer in mBuffers.
+ */
+ private int mWriteBufIndex;
+
+ /**
+ * The buffer we are currently reading from.
+ */
+ private byte[] mReadBuffer;
+
+ /**
+ * The index of mReadBuffer in mBuffers.
+ */
+ private int mReadBufIndex;
+
+ /**
+ * The index into mReadBuffer that we will read from next.
+ * It may point to the end of the buffer, in which case,
+ * the NEXT read will advance to the next buffer.
+ */
+ private int mReadIndex;
+
+ /**
+ * The amount of data in the last buffer.
+ */
+ private int mReadLimit = -1;
+
+ /**
+ * How much data there is total.
+ */
+ private int mReadableSize = -1;
+
+ public EncodedBuffer() {
+ this(0);
+ }
+
+ /**
+ * Construct an EncodedBuffer object.
+ *
+ * @param chunkSize The size of the buffers to use. If chunkSize <= 0, a default
+ * size will be used instead.
+ */
+ public EncodedBuffer(int chunkSize) {
+ if (chunkSize <= 0) {
+ chunkSize = 8 * 1024;
+ }
+ mChunkSize = chunkSize;
+ mWriteBuffer = new byte[mChunkSize];
+ mBuffers.add(mWriteBuffer);
+ mBufferCount = 1;
+ }
+
+ //
+ // Buffer management.
+ //
+
+ /**
+ * Rewind the read and write pointers, and record how much data was last written.
+ */
+ public void startEditing() {
+ mReadableSize = ((mWriteBufIndex) * mChunkSize) + mWriteIndex;
+ mReadLimit = mWriteIndex;
+
+ mWriteBuffer = mBuffers.get(0);
+ mWriteIndex = 0;
+ mWriteBufIndex = 0;
+
+ mReadBuffer = mWriteBuffer;
+ mReadBufIndex = 0;
+ mReadIndex = 0;
+ }
+
+ /**
+ * Rewind the read pointer. Don't touch the write pointer.
+ */
+ public void rewindRead() {
+ mReadBuffer = mBuffers.get(0);
+ mReadBufIndex = 0;
+ mReadIndex = 0;
+ }
+
+ /**
+ * Only valid after startEditing. Returns -1 before that.
+ */
+ public int getReadableSize() {
+ return mReadableSize;
+ }
+
+ //
+ // Reading from the read position.
+ //
+
+ /**
+ * Only valid after startEditing.
+ */
+ public int getReadPos() {
+ return ((mReadBufIndex) * mChunkSize) + mReadIndex;
+ }
+
+ /**
+ * Skip over _amount_ bytes.
+ */
+ public void skipRead(int amount) {
+ if (amount < 0) {
+ throw new RuntimeException("skipRead with negative amount=" + amount);
+ }
+ if (amount == 0) {
+ return;
+ }
+ if (amount <= mChunkSize - mReadIndex) {
+ mReadIndex += amount;
+ } else {
+ amount -= mChunkSize - mReadIndex;
+ mReadIndex = amount % mChunkSize;
+ if (mReadIndex == 0) {
+ mReadIndex = mChunkSize;
+ mReadBufIndex += (amount / mChunkSize);
+ } else {
+ mReadBufIndex += 1 + (amount / mChunkSize);
+ }
+ mReadBuffer = mBuffers.get(mReadBufIndex);
+ }
+ }
+
+ /**
+ * Read one byte from the stream and advance the read pointer.
+ *
+ * @throws IndexOutOfBoundsException if the read point is past the end of
+ * the buffer or past the read limit previously set by startEditing().
+ */
+ public byte readRawByte() {
+ if (mReadBufIndex > mBufferCount
+ || (mReadBufIndex == mBufferCount - 1 && mReadIndex >= mReadLimit)) {
+ throw new IndexOutOfBoundsException("Trying to read too much data"
+ + " mReadBufIndex=" + mReadBufIndex + " mBufferCount=" + mBufferCount
+ + " mReadIndex=" + mReadIndex + " mReadLimit=" + mReadLimit);
+ }
+ if (mReadIndex >= mChunkSize) {
+ mReadBufIndex++;
+ mReadBuffer = mBuffers.get(mReadBufIndex);
+ mReadIndex = 0;
+ }
+ return mReadBuffer[mReadIndex++];
+ }
+
+ /**
+ * Read an unsigned varint. The value will be returend in a java signed long.
+ */
+ public long readRawUnsigned() {
+ int bits = 0;
+ long result = 0;
+ while (true) {
+ final byte b = readRawByte();
+ result |= ((long)(b & 0x7F)) << bits;
+ if ((b & 0x80) == 0) {
+ return result;
+ }
+ bits += 7;
+ if (bits > 64) {
+ throw new ProtoParseException("Varint too long -- " + getDebugString());
+ }
+ }
+ }
+
+ /**
+ * Read 32 little endian bits from the stream.
+ */
+ public int readRawFixed32() {
+ return (readRawByte() & 0x0ff)
+ | ((readRawByte() & 0x0ff) << 8)
+ | ((readRawByte() & 0x0ff) << 16)
+ | ((readRawByte() & 0x0ff) << 24);
+ }
+
+ //
+ // Writing at a the end of the stream.
+ //
+
+ /**
+ * Advance to the next write buffer, allocating it if necessary.
+ *
+ * Must be called immediately <b>before</b> the next write, not after a write,
+ * so that a dangling empty buffer is not created. Doing so will interfere
+ * with the expectation that mWriteIndex will point past the end of the buffer
+ * until the next read happens.
+ */
+ private void nextWriteBuffer() {
+ mWriteBufIndex++;
+ if (mWriteBufIndex >= mBufferCount) {
+ mWriteBuffer = new byte[mChunkSize];
+ mBuffers.add(mWriteBuffer);
+ mBufferCount++;
+ } else {
+ mWriteBuffer = mBuffers.get(mWriteBufIndex);
+ }
+ mWriteIndex = 0;
+ }
+
+ /**
+ * Write a single byte to the stream.
+ */
+ public void writeRawByte(byte val) {
+ if (mWriteIndex >= mChunkSize) {
+ nextWriteBuffer();
+ }
+ mWriteBuffer[mWriteIndex++] = val;
+ }
+
+ /**
+ * Return how many bytes a 32 bit unsigned varint will take when written to the stream.
+ */
+ public static int getRawVarint32Size(int val) {
+ if ((val & (0xffffffff << 7)) == 0) return 1;
+ if ((val & (0xffffffff << 14)) == 0) return 2;
+ if ((val & (0xffffffff << 21)) == 0) return 3;
+ if ((val & (0xffffffff << 28)) == 0) return 4;
+ return 5;
+ }
+
+ /**
+ * Write an unsigned varint to the stream. A signed value would need to take 10 bytes.
+ *
+ * @param val treated as unsigned.
+ */
+ public void writeRawVarint32(int val) {
+ while (true) {
+ if ((val & ~0x7F) == 0) {
+ writeRawByte((byte)val);
+ return;
+ } else {
+ writeRawByte((byte)((val & 0x7F) | 0x80));
+ val >>>= 7;
+ }
+ }
+ }
+
+ /**
+ * Return how many bytes a 32 bit signed zig zag value will take when written to the stream.
+ */
+ public static int getRawZigZag32Size(int val) {
+ return getRawVarint32Size(zigZag32(val));
+ }
+
+ /**
+ * Write a zig-zag encoded value.
+ *
+ * @param val treated as signed
+ */
+ public void writeRawZigZag32(int val) {
+ writeRawVarint32(zigZag32(val));
+ }
+
+ /**
+ * Return how many bytes a 64 bit varint will take when written to the stream.
+ */
+ public static int getRawVarint64Size(long val) {
+ if ((val & (0xffffffffffffffffL << 7)) == 0) return 1;
+ if ((val & (0xffffffffffffffffL << 14)) == 0) return 2;
+ if ((val & (0xffffffffffffffffL << 21)) == 0) return 3;
+ if ((val & (0xffffffffffffffffL << 28)) == 0) return 4;
+ if ((val & (0xffffffffffffffffL << 35)) == 0) return 5;
+ if ((val & (0xffffffffffffffffL << 42)) == 0) return 6;
+ if ((val & (0xffffffffffffffffL << 49)) == 0) return 7;
+ if ((val & (0xffffffffffffffffL << 56)) == 0) return 8;
+ if ((val & (0xffffffffffffffffL << 63)) == 0) return 9;
+ return 10;
+ }
+
+ /**
+ * Write a 64 bit varint to the stream.
+ */
+ public void writeRawVarint64(long val) {
+ while (true) {
+ if ((val & ~0x7FL) == 0) {
+ writeRawByte((byte)val);
+ return;
+ } else {
+ writeRawByte((byte)((val & 0x7F) | 0x80));
+ val >>>= 7;
+ }
+ }
+ }
+
+ /**
+ * Return how many bytes a signed 64 bit zig zag value will take when written to the stream.
+ */
+ public static int getRawZigZag64Size(long val) {
+ return getRawVarint64Size(zigZag64(val));
+ }
+
+ /**
+ * Write a 64 bit signed zig zag value to the stream.
+ */
+ public void writeRawZigZag64(long val) {
+ writeRawVarint64(zigZag64(val));
+ }
+
+ /**
+ * Write 4 little endian bytes to the stream.
+ */
+ public void writeRawFixed32(int val) {
+ writeRawByte((byte)(val));
+ writeRawByte((byte)(val >> 8));
+ writeRawByte((byte)(val >> 16));
+ writeRawByte((byte)(val >> 24));
+ }
+
+ /**
+ * Write 8 little endian bytes to the stream.
+ */
+ public void writeRawFixed64(long val) {
+ writeRawByte((byte)(val));
+ writeRawByte((byte)(val >> 8));
+ writeRawByte((byte)(val >> 16));
+ writeRawByte((byte)(val >> 24));
+ writeRawByte((byte)(val >> 32));
+ writeRawByte((byte)(val >> 40));
+ writeRawByte((byte)(val >> 48));
+ writeRawByte((byte)(val >> 56));
+ }
+
+ /**
+ * Write a buffer to the stream. Writes nothing if val is null or zero-length.
+ */
+ public void writeRawBuffer(byte[] val) {
+ if (val != null && val.length > 0) {
+ writeRawBuffer(val, 0, val.length);
+ }
+ }
+
+ /**
+ * Write part of an array of bytes.
+ */
+ public void writeRawBuffer(byte[] val, int offset, int length) {
+ if (val == null) {
+ return;
+ }
+ // Write up to the amount left in the first chunk to write.
+ int amt = length < (mChunkSize - mWriteIndex) ? length : (mChunkSize - mWriteIndex);
+ if (amt > 0) {
+ System.arraycopy(val, offset, mWriteBuffer, mWriteIndex, amt);
+ mWriteIndex += amt;
+ length -= amt;
+ offset += amt;
+ }
+ while (length > 0) {
+ // We know we're now at the beginning of a chunk
+ nextWriteBuffer();
+ amt = length < mChunkSize ? length : mChunkSize;
+ System.arraycopy(val, offset, mWriteBuffer, mWriteIndex, amt);
+ mWriteIndex += amt;
+ length -= amt;
+ offset += amt;
+ }
+ }
+
+ /**
+ * Copies data _size_ bytes of data within this buffer from _srcOffset_
+ * to the current write position. Like memmov but handles the chunked buffer.
+ */
+ public void writeFromThisBuffer(int srcOffset, int size) {
+ if (mReadLimit < 0) {
+ throw new IllegalStateException("writeFromThisBuffer before startEditing");
+ }
+ if (srcOffset < getWritePos()) {
+ throw new IllegalArgumentException("Can only move forward in the buffer --"
+ + " srcOffset=" + srcOffset + " size=" + size + " " + getDebugString());
+ }
+ if (srcOffset + size > mReadableSize) {
+ throw new IllegalArgumentException("Trying to move more data than there is --"
+ + " srcOffset=" + srcOffset + " size=" + size + " " + getDebugString());
+ }
+ if (size == 0) {
+ return;
+ }
+ if (srcOffset == ((mWriteBufIndex) * mChunkSize) + mWriteIndex /* write pos */) {
+ // Writing to the same location. Just advance the write pointer. We already
+ // checked that size is in bounds, so we don't need to do any more range
+ // checking.
+ if (size <= mChunkSize - mWriteIndex) {
+ mWriteIndex += size;
+ } else {
+ size -= mChunkSize - mWriteIndex;
+ mWriteIndex = size % mChunkSize;
+ if (mWriteIndex == 0) {
+ // Roll it back so nextWriteBuffer can do its job
+ // on the next call (also makes mBuffers.get() not
+ // fail if we're at the end).
+ mWriteIndex = mChunkSize;
+ mWriteBufIndex += (size / mChunkSize);
+ } else {
+ mWriteBufIndex += 1 + (size / mChunkSize);
+ }
+ mWriteBuffer = mBuffers.get(mWriteBufIndex);
+ }
+ } else {
+ // Loop through the buffer, copying as much as we can each time.
+ // We already bounds checked so we don't need to do it again here,
+ // and nextWriteBuffer will never allocate.
+ int readBufIndex = srcOffset / mChunkSize;
+ byte[] readBuffer = mBuffers.get(readBufIndex);
+ int readIndex = srcOffset % mChunkSize;
+ while (size > 0) {
+ if (mWriteIndex >= mChunkSize) {
+ nextWriteBuffer();
+ }
+ if (readIndex >= mChunkSize) {
+ readBufIndex++;
+ readBuffer = mBuffers.get(readBufIndex);
+ readIndex = 0;
+ }
+ final int spaceInWriteBuffer = mChunkSize - mWriteIndex;
+ final int availableInReadBuffer = mChunkSize - readIndex;
+ final int amt = Math.min(size, Math.min(spaceInWriteBuffer, availableInReadBuffer));
+ System.arraycopy(readBuffer, readIndex, mWriteBuffer, mWriteIndex, amt);
+ mWriteIndex += amt;
+ readIndex += amt;
+ size -= amt;
+ }
+ }
+ }
+
+ //
+ // Writing at a particular location.
+ //
+
+ /**
+ * Returns the index into the virtual array of the write pointer.
+ */
+ public int getWritePos() {
+ return ((mWriteBufIndex) * mChunkSize) + mWriteIndex;
+ }
+
+ /**
+ * Resets the write pointer to a virtual location as returned by getWritePos.
+ */
+ public void rewindWriteTo(int writePos) {
+ if (writePos > getWritePos()) {
+ throw new RuntimeException("rewindWriteTo only can go backwards" + writePos);
+ }
+ mWriteBufIndex = writePos / mChunkSize;
+ mWriteIndex = writePos % mChunkSize;
+ if (mWriteIndex == 0 && mWriteBufIndex != 0) {
+ // Roll back so nextWriteBuffer can do its job on the next call
+ // but at the first write we're at 0.
+ mWriteIndex = mChunkSize;
+ mWriteBufIndex--;
+ }
+ mWriteBuffer = mBuffers.get(mWriteBufIndex);
+ }
+
+ /**
+ * Read a 32 bit value from the stream.
+ *
+ * Doesn't touch or affect mWritePos.
+ */
+ public int getRawFixed32At(int pos) {
+ return (0x00ff & (int)mBuffers.get(pos / mChunkSize)[pos % mChunkSize])
+ | ((0x0ff & (int)mBuffers.get((pos+1) / mChunkSize)[(pos+1) % mChunkSize]) << 8)
+ | ((0x0ff & (int)mBuffers.get((pos+2) / mChunkSize)[(pos+2) % mChunkSize]) << 16)
+ | ((0x0ff & (int)mBuffers.get((pos+3) / mChunkSize)[(pos+3) % mChunkSize]) << 24);
+ }
+
+ /**
+ * Overwrite a 32 bit value in the stream.
+ *
+ * Doesn't touch or affect mWritePos.
+ */
+ public void editRawFixed32(int pos, int val) {
+ mBuffers.get(pos / mChunkSize)[pos % mChunkSize] = (byte)(val);
+ mBuffers.get((pos+1) / mChunkSize)[(pos+1) % mChunkSize] = (byte)(val >> 8);
+ mBuffers.get((pos+2) / mChunkSize)[(pos+2) % mChunkSize] = (byte)(val >> 16);
+ mBuffers.get((pos+3) / mChunkSize)[(pos+3) % mChunkSize] = (byte)(val >> 24);
+ }
+
+ //
+ // Zigging and zagging
+ //
+
+ /**
+ * Zig-zag encode a 32 bit value.
+ */
+ private static int zigZag32(int val) {
+ return (val << 1) ^ (val >> 31);
+ }
+
+ /**
+ * Zig-zag encode a 64 bit value.
+ */
+ private static long zigZag64(long val) {
+ return (val << 1) ^ (val >> 63);
+ }
+
+ //
+ // Debugging / testing
+ //
+ // VisibleForTesting
+
+ /**
+ * Get a copy of the first _size_ bytes of data. This is not range
+ * checked, and if the bounds are outside what has been written you will
+ * get garbage and if it is outside the buffers that have been allocated,
+ * you will get an exception.
+ */
+ public byte[] getBytes(int size) {
+ final byte[] result = new byte[size];
+
+ final int bufCount = size / mChunkSize;
+ int bufIndex;
+ int writeIndex = 0;
+
+ for (bufIndex=0; bufIndex<bufCount; bufIndex++) {
+ System.arraycopy(mBuffers.get(bufIndex), 0, result, writeIndex, mChunkSize);
+ writeIndex += mChunkSize;
+ }
+
+ final int lastSize = size - (bufCount * mChunkSize);
+ if (lastSize > 0) {
+ System.arraycopy(mBuffers.get(bufIndex), 0, result, writeIndex, lastSize);
+ }
+
+ return result;
+ }
+
+ /**
+ * Get the number of chunks allocated.
+ */
+ // VisibleForTesting
+ public int getChunkCount() {
+ return mBuffers.size();
+ }
+
+ /**
+ * Get the write position inside the current write chunk.
+ */
+ // VisibleForTesting
+ public int getWriteIndex() {
+ return mWriteIndex;
+ }
+
+ /**
+ * Get the index of the current write chunk in the list of chunks.
+ */
+ // VisibleForTesting
+ public int getWriteBufIndex() {
+ return mWriteBufIndex;
+ }
+
+ /**
+ * Return debugging information about this EncodedBuffer object.
+ */
+ public String getDebugString() {
+ return "EncodedBuffer( mChunkSize=" + mChunkSize + " mBuffers.size=" + mBuffers.size()
+ + " mBufferCount=" + mBufferCount + " mWriteIndex=" + mWriteIndex
+ + " mWriteBufIndex=" + mWriteBufIndex + " mReadBufIndex=" + mReadBufIndex
+ + " mReadIndex=" + mReadIndex + " mReadableSize=" + mReadableSize
+ + " mReadLimit=" + mReadLimit + " )";
+ }
+
+ /**
+ * Print the internal buffer chunks.
+ */
+ public void dumpBuffers(String tag) {
+ final int N = mBuffers.size();
+ int start = 0;
+ for (int i=0; i<N; i++) {
+ start += dumpByteString(tag, "{" + i + "} ", start, mBuffers.get(i));
+ }
+ }
+
+ /**
+ * Print the internal buffer chunks.
+ */
+ public static void dumpByteString(String tag, String prefix, byte[] buf) {
+ dumpByteString(tag, prefix, 0, buf);
+ }
+
+ /**
+ * Print the internal buffer chunks.
+ */
+ private static int dumpByteString(String tag, String prefix, int start, byte[] buf) {
+ StringBuffer sb = new StringBuffer();
+ final int length = buf.length;
+ final int lineLen = 16;
+ int i;
+ for (i=0; i<length; i++) {
+ if (i % lineLen == 0) {
+ if (i != 0) {
+ Log.d(tag, sb.toString());
+ sb = new StringBuffer();
+ }
+ sb.append(prefix);
+ sb.append('[');
+ sb.append(start + i);
+ sb.append(']');
+ sb.append(' ');
+ } else {
+ sb.append(' ');
+ }
+ byte b = buf[i];
+ byte c = (byte)((b >> 4) & 0x0f);
+ if (c < 10) {
+ sb.append((char)('0' + c));
+ } else {
+ sb.append((char)('a' - 10 + c));
+ }
+ byte d = (byte)(b & 0x0f);
+ if (d < 10) {
+ sb.append((char)('0' + d));
+ } else {
+ sb.append((char)('a' - 10 + d));
+ }
+ }
+ Log.d(tag, sb.toString());
+ return length;
+ }
+}
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
new file mode 100644
index 0000000..8f99399
--- /dev/null
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -0,0 +1,1599 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto;
+
+import android.annotation.TestApi;
+import android.util.Log;
+
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+
+/**
+ * Class to write to a protobuf stream.
+ *
+ * Each write method takes an ID code from the protoc generated classes
+ * and the value to write. To make a nested object, call startObject
+ * and then endObject when you are done.
+ *
+ * The ID codes have type information embedded into them, so if you call
+ * the incorrect function you will get an IllegalArgumentException.
+ *
+ * To retrieve the encoded protobuf stream, call getBytes().
+ *
+ * TODO: Add a constructor that takes an OutputStream and write to that
+ * stream as the top-level objects are finished.
+ *
+ * @hide
+ */
+
+/* IMPLEMENTATION NOTES
+ *
+ * Because protobuf has inner values, and they are length prefixed, and
+ * those sizes themselves are stored with a variable length encoding, it
+ * is impossible to know how big an object will be in a single pass.
+ *
+ * The traditional way is to copy the in-memory representation of an object
+ * into the generated proto Message objects, do a traversal of those to
+ * cache the size, and then write the size-prefixed buffers.
+ *
+ * We are trying to avoid too much generated code here, but this class still
+ * needs to have a somewhat sane API. We can't have the multiple passes be
+ * done by the calling code. In addition, we want to avoid the memory high
+ * water mark of duplicating all of the values into the traditional in-memory
+ * Message objects. We need to find another way.
+ *
+ * So what we do here is to let the calling code write the data into a
+ * byte[] (actually a collection of them wrapped in the EncodedBuffer) class,
+ * but not do the varint encoding of the sub-message sizes. Then, we do a
+ * recursive traversal of the buffer itself, calculating the sizes (which are
+ * then knowable, although still not the actual sizes in the buffer because of
+ * possible further nesting). Then we do a third pass, compacting the
+ * buffer and varint encoding the sizes.
+ *
+ * This gets us a relatively small number number of fixed-size allocations,
+ * which is less likely to cause memory fragmentation or churn the GC, and
+ * the same number of data copies as would have gotten with setting it
+ * field-by-field in generated code, and no code bloat from generated code.
+ * The final data copy is also done with System.arraycopy, which will be
+ * more efficient, in general, than doing the individual fields twice (as in
+ * the traditional way).
+ *
+ * To accomplish the multiple passes, whenever we write a
+ * WIRE_TYPE_LENGTH_DELIMITED field, we write the size occupied in our
+ * buffer as a fixed 32 bit int (called childRawSize), not variable length
+ * one. We reserve another 32 bit slot for the computed size (called
+ * childEncodedSize). If we know the size up front, as we do for strings
+ * and byte[], then we also put that into childEncodedSize, if we don't, we
+ * write the negative of childRawSize, as a sentiel that we need to
+ * compute it during the second pass and recursively compact it during the
+ * third pass.
+ *
+ * Unsgigned size varints can be up to five bytes long, but we reserve eight
+ * bytes for overhead, so we know that when we compact the buffer, there
+ * will always be space for the encoded varint.
+ *
+ * When we can figure out the size ahead of time, we do, in order
+ * to save overhead with recalculating it, and with the later arraycopy.
+ *
+ * During the period between when the caller has called startObject, but
+ * not yet called endObject, we maintain a linked list of the tokens
+ * returned by startObject, stored in those 8 bytes of size storage space.
+ * We use that linked list of tokens to ensure that the caller has
+ * correctly matched pairs of startObject and endObject calls, and issue
+ * errors if they are not matched.
+ */
+@TestApi
+public final class ProtoOutputStream {
+ public static final String TAG = "ProtoOutputStream";
+
+ public static final int FIELD_ID_SHIFT = 3;
+ public static final int WIRE_TYPE_MASK = (1<<FIELD_ID_SHIFT)-1;
+ public static final int FIELD_ID_MASK = ~WIRE_TYPE_MASK;
+
+ public static final int WIRE_TYPE_VARINT = 0;
+ public static final int WIRE_TYPE_FIXED64 = 1;
+ public static final int WIRE_TYPE_LENGTH_DELIMITED = 2;
+ public static final int WIRE_TYPE_START_GROUP = 3;
+ public static final int WIRE_TYPE_END_GROUP = 4;
+ public static final int WIRE_TYPE_FIXED32 = 5;
+
+ /**
+ * Position of the field type in a (long) fieldId.
+ */
+ public static final int FIELD_TYPE_SHIFT = 32;
+
+ /**
+ * Mask for the field types stored in a fieldId. Leaves a whole
+ * byte for future expansion, even though there are currently only 17 types.
+ */
+ public static final long FIELD_TYPE_MASK = 0x0ffL << FIELD_TYPE_SHIFT;
+
+ public static final long FIELD_TYPE_UNKNOWN = 0;
+
+ public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_INT32 = 3L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_INT64 = 4L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_UINT32 = 5L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_UINT64 = 6L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_SINT32 = 7L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_SINT64 = 8L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_FIXED32 = 9L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_FIXED64 = 10L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_SFIXED32 = 11L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_SFIXED64 = 12L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_BOOL = 13L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_STRING = 14L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_BYTES = 15L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_ENUM = 16L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_OBJECT = 17L << FIELD_TYPE_SHIFT;
+
+ private static final String[] FIELD_TYPE_NAMES = new String[] {
+ "Double",
+ "Float",
+ "Int32",
+ "Int64",
+ "UInt32",
+ "UInt64",
+ "SInt32",
+ "SInt64",
+ "Fixed32",
+ "Fixed64",
+ "SFixed32",
+ "SFixed64",
+ "Bool",
+ "String",
+ "Bytes",
+ "Enum",
+ "Object",
+ };
+
+ //
+ // FieldId flags for whether the field is single, repeated or packed.
+ //
+ public static final int FIELD_COUNT_SHIFT = 40;
+ public static final long FIELD_COUNT_MASK = 0x0fL << FIELD_COUNT_SHIFT;
+
+ public static final long FIELD_COUNT_UNKNOWN = 0;
+ public static final long FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
+ public static final long FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
+ public static final long FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
+
+ /**
+ * Our buffer.
+ */
+ private EncodedBuffer mBuffer;
+
+ /**
+ * Current nesting depth of startObject calls.
+ */
+ private int mDepth;
+
+ /**
+ * An ID given to objects and returned in the token from startObject
+ * and stored in the buffer until endObject is called, where the two
+ * are checked. Starts at -1 and becomes more negative, so the values
+ * aren't likely to alias with the size it will be overwritten with,
+ * which tend to be small, and we will be more likely to catch when
+ * the caller of endObject uses a stale token that they didn't intend
+ * to (e.g. copy and paste error).
+ */
+ private int mNextObjectId = -1;
+
+ /**
+ * The object token we are expecting in endObject. If another call to
+ * startObject happens, this is written to that location, which gives
+ * us a stack, stored in the space for the as-yet unused size fields.
+ */
+ private long mExpectedObjectToken;
+
+ /**
+ * Index in mBuffer that we should start copying from on the next
+ * pass of compaction.
+ */
+ private int mCopyBegin;
+
+ /**
+ * Whether we've already compacted
+ */
+ private boolean mCompacted;
+
+ /**
+ * Construct a ProtoOutputStream with the default chunk size.
+ */
+ public ProtoOutputStream() {
+ this(0);
+ }
+
+ /**
+ * Construct a ProtoOutputStream with the given chunk size.
+ */
+ public ProtoOutputStream(int chunkSize) {
+ mBuffer = new EncodedBuffer(chunkSize);
+ }
+
+ //
+ // proto3 type: double
+ // java type: double
+ // encoding: fixed64
+ // wire type: WIRE_TYPE_FIXED64
+ //
+
+ /**
+ * Write a single proto "double" type field value.
+ */
+ public void writeDouble(long fieldId, double val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_DOUBLE);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_FIXED64);
+ mBuffer.writeRawFixed64(Double.doubleToLongBits(val));
+ }
+ }
+
+ /**
+ * Write a single repeated proto "double" type field value.
+ */
+ public void writeRepeatedDouble(long fieldId, double val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_DOUBLE);
+
+ writeTag(id, WIRE_TYPE_FIXED64);
+ mBuffer.writeRawFixed64(Double.doubleToLongBits(val));
+ }
+
+ /**
+ * Write a list of packed proto "double" type field values.
+ */
+ public void writePackedDouble(long fieldId, double[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_DOUBLE);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ writeKnownLengthHeader(id, N * 8);
+ for (int i=0; i<N; i++) {
+ mBuffer.writeRawFixed64(Double.doubleToLongBits(val[i]));
+ }
+ }
+ }
+
+ //
+ // proto3 type: float
+ // java type: float
+ // encoding: fixed32
+ // wire type: WIRE_TYPE_FIXED32
+ //
+
+ /**
+ * Write a single proto "float" type field value.
+ */
+ public void writeFloat(long fieldId, float val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FLOAT);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_FIXED32);
+ mBuffer.writeRawFixed32(Float.floatToIntBits(val));
+ }
+ }
+
+ /**
+ * Write a single repeated proto "float" type field value.
+ */
+ public void writeRepeatedFloat(long fieldId, float val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FLOAT);
+
+ writeTag(id, WIRE_TYPE_FIXED32);
+ mBuffer.writeRawFixed32(Float.floatToIntBits(val));
+ }
+
+ /**
+ * Write a list of packed proto "float" type field value.
+ */
+ public void writePackedFloat(long fieldId, float[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FLOAT);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ writeKnownLengthHeader(id, N * 4);
+ for (int i=0; i<N; i++) {
+ mBuffer.writeRawFixed32(Float.floatToIntBits(val[i]));
+ }
+ }
+ }
+
+ //
+ // proto3 type: int32
+ // java type: int
+ // signed/unsigned: signed
+ // encoding: varint
+ // wire type: WIRE_TYPE_VARINT
+ //
+
+ /**
+ * Writes a java int as an usigned varint.
+ *
+ * The unadorned int32 type in protobuf is unfortunate because it
+ * is stored in memory as a signed value, but encodes as unsigned
+ * varints, which are formally always longs. So here, we encode
+ * negative values as 64 bits, which will get the sign-extension,
+ * and positive values as 32 bits, which saves a marginal amount
+ * of work in that it processes ints instead of longs.
+ */
+ private void writeUnsignedVarintFromSignedInt(int val) {
+ if (val >= 0) {
+ mBuffer.writeRawVarint32(val);
+ } else {
+ mBuffer.writeRawVarint64(val);
+ }
+ }
+
+ /**
+ * Write a single proto "int32" type field value.
+ *
+ * Note that these are stored in memory as signed values and written as unsigned
+ * varints, which if negative, are 10 bytes long. If you know the data is likely
+ * to be negative, use "sint32".
+ */
+ public void writeInt32(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_INT32);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_VARINT);
+ writeUnsignedVarintFromSignedInt(val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "int32" type field value.
+ *
+ * Note that these are stored in memory as signed values and written as unsigned
+ * varints, which if negative, are 10 bytes long. If you know the data is likely
+ * to be negative, use "sint32".
+ */
+ public void writeRepeatedInt32(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_INT32);
+
+ writeTag(id, WIRE_TYPE_VARINT);
+ writeUnsignedVarintFromSignedInt(val);
+ }
+
+ /**
+ * Write a list of packed proto "int32" type field value.
+ *
+ * Note that these are stored in memory as signed values and written as unsigned
+ * varints, which if negative, are 10 bytes long. If you know the data is likely
+ * to be negative, use "sint32".
+ */
+ public void writePackedInt32(long fieldId, int[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT32);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ int size = 0;
+ for (int i=0; i<N; i++) {
+ final int v = val[i];
+ size += v >= 0 ? EncodedBuffer.getRawVarint32Size(v) : 10;
+ }
+ writeKnownLengthHeader(id, size);
+ for (int i=0; i<N; i++) {
+ writeUnsignedVarintFromSignedInt(val[i]);
+ }
+ }
+ }
+
+ //
+ // proto3 type: int64
+ // java type: int
+ // signed/unsigned: signed
+ // encoding: varint
+ // wire type: WIRE_TYPE_VARINT
+ //
+
+ /**
+ * Write a single proto "int64" type field value.
+ */
+ public void writeInt64(long fieldId, long val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_INT64);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_VARINT);
+ mBuffer.writeRawVarint64(val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "int64" type field value.
+ */
+ public void writeRepeatedInt64(long fieldId, long val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_INT64);
+
+ writeTag(id, WIRE_TYPE_VARINT);
+ mBuffer.writeRawVarint64(val);
+ }
+
+ /**
+ * Write a list of packed proto "int64" type field value.
+ */
+ public void writePackedInt64(long fieldId, long[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT64);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ int size = 0;
+ for (int i=0; i<N; i++) {
+ size += EncodedBuffer.getRawVarint64Size(val[i]);
+ }
+ writeKnownLengthHeader(id, size);
+ for (int i=0; i<N; i++) {
+ mBuffer.writeRawVarint64(val[i]);
+ }
+ }
+ }
+
+ //
+ // proto3 type: uint32
+ // java type: int
+ // signed/unsigned: unsigned
+ // encoding: varint
+ // wire type: WIRE_TYPE_VARINT
+ //
+
+ /**
+ * Write a single proto "uint32" type field value.
+ */
+ public void writeUInt32(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_UINT32);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_VARINT);
+ mBuffer.writeRawVarint32(val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "uint32" type field value.
+ */
+ public void writeRepeatedUInt32(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_UINT32);
+
+ writeTag(id, WIRE_TYPE_VARINT);
+ mBuffer.writeRawVarint32(val);
+ }
+
+ /**
+ * Write a list of packed proto "uint32" type field value.
+ */
+ public void writePackedUInt32(long fieldId, int[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT32);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ int size = 0;
+ for (int i=0; i<N; i++) {
+ size += EncodedBuffer.getRawVarint32Size(val[i]);
+ }
+ writeKnownLengthHeader(id, size);
+ for (int i=0; i<N; i++) {
+ mBuffer.writeRawVarint32(val[i]);
+ }
+ }
+ }
+
+ //
+ // proto3 type: uint64
+ // java type: int
+ // signed/unsigned: unsigned
+ // encoding: varint
+ // wire type: WIRE_TYPE_VARINT
+ //
+
+ /**
+ * Write a single proto "uint64" type field value.
+ */
+ public void writeUInt64(long fieldId, long val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_UINT64);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_VARINT);
+ mBuffer.writeRawVarint64(val);
+ }
+ }
+
+ /**
+ * Write a single proto "uint64" type field value.
+ */
+ public void writeRepeatedUInt64(long fieldId, long val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_UINT64);
+
+ writeTag(id, WIRE_TYPE_VARINT);
+ mBuffer.writeRawVarint64(val);
+ }
+
+ /**
+ * Write a single proto "uint64" type field value.
+ */
+ public void writePackedUInt64(long fieldId, long[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT64);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ int size = 0;
+ for (int i=0; i<N; i++) {
+ size += EncodedBuffer.getRawVarint64Size(val[i]);
+ }
+ writeKnownLengthHeader(id, size);
+ for (int i=0; i<N; i++) {
+ mBuffer.writeRawVarint64(val[i]);
+ }
+ }
+ }
+
+ //
+ // proto3 type: sint32
+ // java type: int
+ // signed/unsigned: signed
+ // encoding: zig-zag
+ // wire type: WIRE_TYPE_VARINT
+ //
+
+ /**
+ * Write a single proto "sint32" type field value.
+ */
+ public void writeSInt32(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SINT32);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_VARINT);
+ mBuffer.writeRawZigZag32(val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "sint32" type field value.
+ */
+ public void writeRepeatedSInt32(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SINT32);
+
+ writeTag(id, WIRE_TYPE_VARINT);
+ mBuffer.writeRawZigZag32(val);
+ }
+
+ /**
+ * Write a list of packed proto "sint32" type field value.
+ */
+ public void writePackedSInt32(long fieldId, int[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT32);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ int size = 0;
+ for (int i=0; i<N; i++) {
+ size += EncodedBuffer.getRawZigZag32Size(val[i]);
+ }
+ writeKnownLengthHeader(id, size);
+ for (int i=0; i<N; i++) {
+ mBuffer.writeRawZigZag32(val[i]);
+ }
+ }
+ }
+
+ //
+ // proto3 type: sint64
+ // java type: int
+ // signed/unsigned: signed
+ // encoding: zig-zag
+ // wire type: WIRE_TYPE_VARINT
+ //
+
+ /**
+ * Write a single proto "sint64" type field value.
+ */
+ public void writeSInt64(long fieldId, long val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SINT64);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_VARINT);
+ mBuffer.writeRawZigZag64(val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "sint64" type field value.
+ */
+ public void writeRepeatedSInt64(long fieldId, long val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SINT64);
+
+ writeTag(id, WIRE_TYPE_VARINT);
+ mBuffer.writeRawZigZag64(val);
+ }
+
+ /**
+ * Write a list of packed proto "sint64" type field value.
+ */
+ public void writePackedSInt64(long fieldId, long[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT64);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ int size = 0;
+ for (int i=0; i<N; i++) {
+ size += EncodedBuffer.getRawZigZag64Size(val[i]);
+ }
+ writeKnownLengthHeader(id, size);
+ for (int i=0; i<N; i++) {
+ mBuffer.writeRawZigZag64(val[i]);
+ }
+ }
+ }
+
+ //
+ // proto3 type: fixed32
+ // java type: int
+ // encoding: little endian
+ // wire type: WIRE_TYPE_FIXED32
+ //
+
+ /**
+ * Write a single proto "fixed32" type field value.
+ */
+ public void writeFixed32(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED32);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_FIXED32);
+ mBuffer.writeRawFixed32(val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "fixed32" type field value.
+ */
+ public void writeRepeatedFixed32(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FIXED32);
+
+ writeTag(id, WIRE_TYPE_FIXED32);
+ mBuffer.writeRawFixed32(val);
+ }
+
+ /**
+ * Write a list of packed proto "fixed32" type field value.
+ */
+ public void writePackedFixed32(long fieldId, int[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED32);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ writeKnownLengthHeader(id, N * 4);
+ for (int i=0; i<N; i++) {
+ mBuffer.writeRawFixed32(val[i]);
+ }
+ }
+ }
+
+ //
+ // proto3 type: fixed64
+ // java type: long
+ // encoding: fixed64
+ // wire type: WIRE_TYPE_FIXED64
+ //
+
+ /**
+ * Write a single proto "fixed64" type field value.
+ */
+ public void writeFixed64(long fieldId, long val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED64);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_FIXED64);
+ mBuffer.writeRawFixed64(val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "fixed64" type field value.
+ */
+ public void writeRepeatedFixed64(long fieldId, long val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FIXED64);
+
+ writeTag(id, WIRE_TYPE_FIXED64);
+ mBuffer.writeRawFixed64(val);
+ }
+
+ /**
+ * Write a list of packed proto "fixed64" type field value.
+ */
+ public void writePackedFixed64(long fieldId, long[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED64);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ writeKnownLengthHeader(id, N * 8);
+ for (int i=0; i<N; i++) {
+ mBuffer.writeRawFixed64(val[i]);
+ }
+ }
+ }
+
+ //
+ // proto3 type: sfixed32
+ // java type: int
+ // encoding: little endian
+ // wire type: WIRE_TYPE_FIXED32
+ //
+ /**
+ * Write a single proto "sfixed32" type field value.
+ */
+ public void writeSFixed32(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED32);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_FIXED32);
+ mBuffer.writeRawFixed32(val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "sfixed32" type field value.
+ */
+ public void writeRepeatedSFixed32(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SFIXED32);
+
+ writeTag(id, WIRE_TYPE_FIXED32);
+ mBuffer.writeRawFixed32(val);
+ }
+
+ /**
+ * Write a list of packed proto "sfixed32" type field value.
+ */
+ public void writePackedSFixed32(long fieldId, int[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED32);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ writeKnownLengthHeader(id, N * 4);
+ for (int i=0; i<N; i++) {
+ mBuffer.writeRawFixed32(val[i]);
+ }
+ }
+ }
+
+ //
+ // proto3 type: sfixed64
+ // java type: long
+ // encoding: little endian
+ // wire type: WIRE_TYPE_FIXED64
+ //
+
+ /**
+ * Write a single proto "sfixed64" type field value.
+ */
+ public void writeSFixed64(long fieldId, long val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED64);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_FIXED64);
+ mBuffer.writeRawFixed64(val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "sfixed64" type field value.
+ */
+ public void writeRepeatedSFixed64(long fieldId, long val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SFIXED64);
+
+ writeTag(id, WIRE_TYPE_FIXED64);
+ mBuffer.writeRawFixed64(val);
+ }
+
+ /**
+ * Write a list of packed proto "sfixed64" type field value.
+ */
+ public void writePackedSFixed64(long fieldId, long[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED64);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ writeKnownLengthHeader(id, N * 8);
+ for (int i=0; i<N; i++) {
+ mBuffer.writeRawFixed64(val[i]);
+ }
+ }
+ }
+
+ //
+ // proto3 type: bool
+ // java type: boolean
+ // encoding: varint
+ // wire type: WIRE_TYPE_VARINT
+ //
+
+ /**
+ * Write a single proto "bool" type field value.
+ */
+ public void writeBool(long fieldId, boolean val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BOOL);
+
+ if (val) {
+ writeTag(id, WIRE_TYPE_VARINT);
+ // 0 and 1 are the same as their varint counterparts
+ mBuffer.writeRawByte((byte)1);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "bool" type field value.
+ */
+ public void writeRepeatedBool(long fieldId, boolean val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BOOL);
+
+ writeTag(id, WIRE_TYPE_VARINT);
+ mBuffer.writeRawByte((byte)(val ? 1 : 0));
+ }
+
+ /**
+ * Write a list of packed proto "bool" type field value.
+ */
+ public void writePackedBool(long fieldId, boolean[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_BOOL);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ // Write the header
+ writeKnownLengthHeader(id, N);
+
+ // Write the data
+ for (int i=0; i<N; i++) {
+ // 0 and 1 are the same as their varint counterparts
+ mBuffer.writeRawByte((byte)(val[i] ? 1 : 0));
+ }
+ }
+ }
+
+ //
+ // proto3 type: string
+ // java type: String
+ // encoding: utf-8
+ // wire type: WIRE_TYPE_LENGTH_DELIMITED
+ //
+
+ /**
+ * Write a single proto "string" type field value.
+ */
+ public void writeString(long fieldId, String val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_STRING);
+
+ if (val != null && val.length() > 0) {
+ writeUtf8String(id, val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "string" type field value.
+ */
+ public void writeRepeatedString(long fieldId, String val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_STRING);
+
+ if (val == null || val.length() == 0) {
+ writeKnownLengthHeader(id, 0);
+ } else {
+ writeUtf8String(id, val);
+ }
+ }
+
+ /**
+ * Write a list of packed proto "string" type field value.
+ */
+ private void writeUtf8String(int id, String val) {
+ // TODO: Is it worth converting by hand in order to not allocate?
+ try {
+ final byte[] buf = val.getBytes("UTF-8");
+ writeKnownLengthHeader(id, buf.length);
+ mBuffer.writeRawBuffer(buf);
+ } catch (UnsupportedEncodingException ex) {
+ throw new RuntimeException("not possible");
+ }
+ }
+
+ //
+ // proto3 type: bytes
+ // java type: byte[]
+ // encoding: varint
+ // wire type: WIRE_TYPE_VARINT
+ //
+
+ /**
+ * Write a single proto "bytes" type field value.
+ */
+ public void writeBytes(long fieldId, byte[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES);
+
+ if (val != null && val.length > 0) {
+ writeKnownLengthHeader(id, val.length);
+ mBuffer.writeRawBuffer(val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto "bytes" type field value.
+ */
+ public void writeRepeatedBytes(long fieldId, byte[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BYTES);
+
+ writeKnownLengthHeader(id, val == null ? 0 : val.length);
+ mBuffer.writeRawBuffer(val);
+ }
+
+ //
+ // proto3 type: enum
+ // java type: int
+ // signed/unsigned: unsigned
+ // encoding: varint
+ // wire type: WIRE_TYPE_VARINT
+ //
+
+ /**
+ * Write a single proto enum type field value.
+ */
+ public void writeEnum(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_ENUM);
+
+ if (val != 0) {
+ writeTag(id, WIRE_TYPE_VARINT);
+ writeUnsignedVarintFromSignedInt(val);
+ }
+ }
+
+ /**
+ * Write a single repeated proto enum type field value.
+ */
+ public void writeRepeatedEnum(long fieldId, int val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_ENUM);
+
+ writeTag(id, WIRE_TYPE_VARINT);
+ writeUnsignedVarintFromSignedInt(val);
+ }
+
+ /**
+ * Write a list of packed proto enum type field value.
+ */
+ public void writePackedEnum(long fieldId, int[] val) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_ENUM);
+
+ final int N = val != null ? val.length : 0;
+ if (N > 0) {
+ int size = 0;
+ for (int i=0; i<N; i++) {
+ final int v = val[i];
+ size += v >= 0 ? EncodedBuffer.getRawVarint32Size(v) : 10;
+ }
+ writeKnownLengthHeader(id, size);
+ for (int i=0; i<N; i++) {
+ writeUnsignedVarintFromSignedInt(val[i]);
+ }
+ }
+ }
+
+ //
+ // Child objects
+ //
+
+ /**
+ * Make a token.
+ * Bits 61-63 - tag size (So we can go backwards later if the object had not data)
+ * - 3 bits, max value 7, max value needed 5
+ * Bit 60 - true if the object is repeated (lets us require endObject or endRepeatedObject)
+ * Bits 59-51 - depth (For error checking)
+ * - 9 bits, max value 512, when checking, value is masked (if we really
+ * are more than 512 levels deep)
+ * Bits 32-50 - objectId (For error checking)
+ * - 19 bits, max value 524,288. that's a lot of objects. IDs will wrap
+ * because of the overflow, and only the tokens are compared.
+ * Bits 0-31 - offset of the first size field in the buffer.
+ */
+ // VisibleForTesting
+ public static long makeToken(int tagSize, boolean repeated, int depth, int objectId,
+ int sizePos) {
+ return ((0x07L & (long)tagSize) << 61)
+ | (repeated ? (1L << 60) : 0)
+ | (0x01ffL & (long)depth) << 51
+ | (0x07ffffL & (long)objectId) << 32
+ | (0x0ffffffffL & (long)sizePos);
+ }
+
+ /**
+ * Get the encoded tag size from the token.
+ */
+ public static int getTagSizeFromToken(long token) {
+ return (int)(0x7 & (token >> 61));
+ }
+
+ /**
+ * Get whether this is a call to startObject (false) or startRepeatedObject (true).
+ */
+ public static boolean getRepeatedFromToken(long token) {
+ return (0x1 & (token >> 60)) != 0;
+ }
+
+ /**
+ * Get the nesting depth of startObject calls from the token.
+ */
+ public static int getDepthFromToken(long token) {
+ return (int)(0x01ff & (token >> 51));
+ }
+
+ /**
+ * Get the object ID from the token. The object ID is a serial number for the
+ * startObject calls that have happened on this object. The values are truncated
+ * to 9 bits, but that is sufficient for error checking.
+ */
+ public static int getObjectIdFromToken(long token) {
+ return (int)(0x07ffff & (token >> 32));
+ }
+
+ /**
+ * Get the location of the childRawSize (the first 32 bit size field) in this object.
+ */
+ public static int getSizePosFromToken(long token) {
+ return (int)token;
+ }
+
+ /**
+ * Convert the object ID to the ordinal value -- the n-th call to startObject.
+ * The object IDs start at -1 and count backwards, so that the value is unlikely
+ * to alias with an actual size field that had been written.
+ */
+ public static int convertObjectIdToOrdinal(int objectId) {
+ return (-1 & 0x07ffff) - objectId;
+ }
+
+ /**
+ * Return a debugging string of a token.
+ */
+ public static String token2String(long token) {
+ if (token == 0L) {
+ return "Token(0)";
+ } else {
+ return "Token(val=0x" + Long.toHexString(token)
+ + " depth=" + getDepthFromToken(token)
+ + " object=" + convertObjectIdToOrdinal(getObjectIdFromToken(token))
+ + " tagSize=" + getTagSizeFromToken(token)
+ + " sizePos=" + getSizePosFromToken(token)
+ + ')';
+ }
+ }
+
+ /**
+ * Start a child object.
+ *
+ * Returns a token which should be passed to endObject. Calls to endObject must be
+ * nested properly.
+ */
+ public long startObject(long fieldId) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT);
+
+ return startObjectImpl(id, false);
+ }
+
+ /**
+ * End a child object. Pass in the token from the correspoinding startObject call.
+ */
+ public void endObject(long token) {
+ assertNotCompacted();
+
+ endObjectImpl(token, false);
+ }
+
+ /**
+ * Start a repeated child object.
+ *
+ * Returns a token which should be passed to endObject. Calls to endObject must be
+ * nested properly.
+ */
+ public long startRepeatedObject(long fieldId) {
+ assertNotCompacted();
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT);
+
+ return startObjectImpl(id, true);
+ }
+
+ /**
+ * End a child object. Pass in the token from the correspoinding startRepeatedObject call.
+ */
+ public void endRepeatedObject(long token) {
+ assertNotCompacted();
+
+ endObjectImpl(token, true);
+ }
+
+ /**
+ * Common implementation of startObject and startRepeatedObject.
+ */
+ private long startObjectImpl(final int id, boolean repeated) {
+ writeTag(id, WIRE_TYPE_LENGTH_DELIMITED);
+ final int sizePos = mBuffer.getWritePos();
+ mDepth++;
+ mNextObjectId--;
+
+ // Write the previous token, giving us a stack of expected tokens.
+ // After endObject returns, the first fixed32 becomeschildRawSize (set in endObject)
+ // and the second one becomes childEncodedSize (set in editEncodedSize).
+ mBuffer.writeRawFixed32((int)(mExpectedObjectToken >> 32));
+ mBuffer.writeRawFixed32((int)mExpectedObjectToken);
+
+ long old = mExpectedObjectToken;
+
+ mExpectedObjectToken = makeToken(getTagSize(id), repeated, mDepth, mNextObjectId, sizePos);
+ return mExpectedObjectToken;
+ }
+
+ /**
+ * Common implementation of endObject and endRepeatedObject.
+ */
+ private void endObjectImpl(long token, boolean repeated) {
+ // The upper 32 bits of the token is the depth of startObject /
+ // endObject calls. We could get aritrarily sophisticated, but
+ // that's enough to prevent the common error of missing an
+ // endObject somewhere.
+ // The lower 32 bits of the token is the offset in the buffer
+ // at which to write the size.
+ final int depth = getDepthFromToken(token);
+ final boolean expectedRepeated = getRepeatedFromToken(token);
+ final int sizePos = getSizePosFromToken(token);
+ final int childRawSize = mBuffer.getWritePos() - sizePos - 8;
+
+ if (repeated != expectedRepeated) {
+ if (repeated) {
+ throw new IllegalArgumentException("endRepeatedObject called where endObject should"
+ + " have been");
+ } else {
+ throw new IllegalArgumentException("endObject called where endRepeatedObject should"
+ + " have been");
+ }
+ }
+
+ // Check that we're getting the token and depth that we are expecting.
+ if ((mDepth & 0x01ff) != depth || mExpectedObjectToken != token) {
+ // This text of exception is united tested. That test also implicity checks
+ // that we're tracking the objectIds and depths correctly.
+ throw new IllegalArgumentException("Mismatched startObject/endObject calls."
+ + " Current depth " + mDepth
+ + " token=" + token2String(token)
+ + " expectedToken=" + token2String(mExpectedObjectToken));
+ }
+
+ // Get the next expected token that we stashed away in the buffer.
+ mExpectedObjectToken = (((long)mBuffer.getRawFixed32At(sizePos)) << 32)
+ | (0x0ffffffffL & (long)mBuffer.getRawFixed32At(sizePos+4));
+
+ mDepth--;
+ if (childRawSize > 0) {
+ mBuffer.editRawFixed32(sizePos, -childRawSize);
+ mBuffer.editRawFixed32(sizePos+4, -1);
+ } else if (repeated) {
+ mBuffer.editRawFixed32(sizePos, 0);
+ mBuffer.editRawFixed32(sizePos+4, 0);
+ } else {
+ // The object has no data. Don't include it.
+ mBuffer.rewindWriteTo(sizePos - getTagSizeFromToken(token));
+ }
+ }
+
+ //
+ // Tags
+ //
+
+ /**
+ * Combine a fieldId (the field keys in the proto file) and the field flags.
+ * Mostly useful for testing because the generated code contains the fieldId
+ * constants.
+ */
+ public static long makeFieldId(int id, long fieldFlags) {
+ return fieldFlags | (((long)id) & 0x0ffffffffL);
+ }
+
+ /**
+ * Validates that the fieldId providied is of the type and count from expectedType.
+ *
+ * The type must match exactly to pass this check.
+ *
+ * The count must match according to this truth table to pass the check:
+ *
+ * expectedFlags
+ * UNKNOWN SINGLE REPEATED PACKED
+ * fieldId
+ * UNKNOWN true false false false
+ * SINGLE x true false false
+ * REPEATED x false true false
+ * PACKED x false true true
+ *
+ * @throws IllegalArgumentException if it is not.
+ *
+ * @return The raw ID of that field.
+ */
+ public static int checkFieldId(long fieldId, long expectedFlags) {
+ final long fieldCount = fieldId & FIELD_COUNT_MASK;
+ final long fieldType = fieldId & FIELD_TYPE_MASK;
+ final long expectedCount = expectedFlags & FIELD_COUNT_MASK;
+ final long expectedType = expectedFlags & FIELD_TYPE_MASK;
+ if (((int)fieldId) == 0) {
+ throw new IllegalArgumentException("Invalid proto field " + (int)fieldId
+ + " fieldId=" + Long.toHexString(fieldId));
+ }
+ if (fieldType != expectedType
+ || !((fieldCount == expectedCount)
+ || (fieldCount == FIELD_COUNT_PACKED
+ && expectedCount == FIELD_COUNT_REPEATED))) {
+ final String countString = getFieldCountString(fieldCount);
+ final String typeString = getFieldTypeString(fieldType);
+ if (typeString != null && countString != null) {
+ final StringBuilder sb = new StringBuilder();
+ if (expectedType == FIELD_TYPE_OBJECT) {
+ sb.append("start");
+ } else {
+ sb.append("write");
+ }
+ sb.append(getFieldCountString(expectedCount));
+ sb.append(getFieldTypeString(expectedType));
+ sb.append(" called for field ");
+ sb.append((int)fieldId);
+ sb.append(" which should be used with ");
+ if (fieldType == FIELD_TYPE_OBJECT) {
+ sb.append("start");
+ } else {
+ sb.append("write");
+ }
+ sb.append(countString);
+ sb.append(typeString);
+ if (fieldCount == FIELD_COUNT_PACKED) {
+ sb.append(" or writeRepeated");
+ sb.append(typeString);
+ }
+ sb.append('.');
+ throw new IllegalArgumentException(sb.toString());
+ } else {
+ final StringBuilder sb = new StringBuilder();
+ if (expectedType == FIELD_TYPE_OBJECT) {
+ sb.append("start");
+ } else {
+ sb.append("write");
+ }
+ sb.append(getFieldCountString(expectedCount));
+ sb.append(getFieldTypeString(expectedType));
+ sb.append(" called with an invalid fieldId: 0x");
+ sb.append(Long.toHexString(fieldId));
+ sb.append(". The proto field ID might be ");
+ sb.append((int)fieldId);
+ sb.append('.');
+ throw new IllegalArgumentException(sb.toString());
+ }
+ }
+ return (int)fieldId;
+ }
+
+ /**
+ * Get the developer-usable name of a field type.
+ */
+ private static String getFieldTypeString(long fieldType) {
+ int index = ((int)((fieldType & FIELD_TYPE_MASK) >>> FIELD_TYPE_SHIFT)) - 1;
+ if (index >= 0 && index < FIELD_TYPE_NAMES.length) {
+ return FIELD_TYPE_NAMES[index];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the developer-usable name of a field count.
+ */
+ private static String getFieldCountString(long fieldCount) {
+ if (fieldCount == FIELD_COUNT_SINGLE) {
+ return "";
+ } else if (fieldCount == FIELD_COUNT_REPEATED) {
+ return "Repeated";
+ } else if (fieldCount == FIELD_COUNT_PACKED) {
+ return "Packed";
+ } else {
+ return null;
+ }
+ }
+
+
+ /**
+ * Return how many bytes an encoded field tag will require.
+ */
+ private static int getTagSize(int id) {
+ return EncodedBuffer.getRawVarint32Size(id << FIELD_ID_SHIFT);
+ }
+
+ /**
+ * Write a field tage to the stream.
+ */
+ public void writeTag(int id, int wireType) {
+ mBuffer.writeRawVarint32((id << FIELD_ID_SHIFT) | wireType);
+ }
+
+ /**
+ * Write the header of a WIRE_TYPE_LENGTH_DELIMITED field for one where
+ * we know the size in advance and do not need to compute and compact.
+ */
+ private void writeKnownLengthHeader(int id, int size) {
+ // Write the tag
+ writeTag(id, WIRE_TYPE_LENGTH_DELIMITED);
+ // Size will be compacted later, but we know the size, so write it,
+ // once for the rawSize and once for the encodedSize.
+ mBuffer.writeRawFixed32(size);
+ mBuffer.writeRawFixed32(size);
+ }
+
+ //
+ // Getting the buffer and compaction
+ //
+
+ /**
+ * Assert that the compact call has not already occured.
+ *
+ * TODO: Will change when we add the OutputStream version of ProtoOutputStream.
+ */
+ private void assertNotCompacted() {
+ if (mCompacted) {
+ throw new IllegalArgumentException("write called after compact");
+ }
+ }
+
+ /**
+ * Finish the encoding of the data, and return a byte[] with
+ * the protobuf formatted data.
+ *
+ * After this call, do not call any of the write* functions. The
+ * behavior is undefined.
+ */
+ public byte[] getBytes() {
+ compactIfNecessary();
+
+ return mBuffer.getBytes(mBuffer.getReadableSize());
+ }
+
+ /**
+ * If the buffer hasn't already had the nested object size fields compacted
+ * and turned into an actual protobuf format, then do so.
+ */
+ private void compactIfNecessary() {
+ if (!mCompacted) {
+ if (mDepth != 0) {
+ throw new IllegalArgumentException("Trying to compact with " + mDepth
+ + " missing calls to endObject");
+ }
+
+ // The buffer must be compacted.
+ mBuffer.startEditing();
+ final int readableSize = mBuffer.getReadableSize();
+
+ // Cache the sizes of the objects
+ editEncodedSize(readableSize);
+
+ // Re-write the buffer with the sizes as proper varints instead
+ // of pairs of uint32s. We know this will always fit in the same
+ // buffer because the pair of uint32s is exactly 8 bytes long, and
+ // the single varint size will be no more than 5 bytes long.
+ mBuffer.rewindRead();
+ compactSizes(readableSize);
+
+ // If there is any data left over that wasn't copied yet, copy it.
+ if (mCopyBegin < readableSize) {
+ mBuffer.writeFromThisBuffer(mCopyBegin, readableSize - mCopyBegin);
+ }
+
+ // Set the new readableSize
+ mBuffer.startEditing();
+
+ // It's not valid to write to this object anymore. The write
+ // pointers are off, and then some of the data would be compacted
+ // and some not.
+ mCompacted = true;
+ }
+ }
+
+ /**
+ * First compaction pass. Iterate through the data, and fill in the
+ * nested object sizes so the next pass can compact them.
+ */
+ private int editEncodedSize(int rawSize) {
+ int objectStart = mBuffer.getReadPos();
+ int objectEnd = objectStart + rawSize;
+ int encodedSize = 0;
+ int tagPos;
+
+ while ((tagPos = mBuffer.getReadPos()) < objectEnd) {
+ int tag = readRawTag();
+ encodedSize += EncodedBuffer.getRawVarint32Size(tag);
+
+ final int wireType = tag & WIRE_TYPE_MASK;
+ switch (wireType) {
+ case WIRE_TYPE_VARINT:
+ encodedSize++;
+ while ((mBuffer.readRawByte() & 0x80) != 0) {
+ encodedSize++;
+ }
+ break;
+ case WIRE_TYPE_FIXED64:
+ encodedSize += 8;
+ mBuffer.skipRead(8);
+ break;
+ case WIRE_TYPE_LENGTH_DELIMITED: {
+ // This object is not of a fixed-size type. So we need to figure
+ // out how big it should be.
+ final int childRawSize = mBuffer.readRawFixed32();
+ final int childEncodedSizePos = mBuffer.getReadPos();
+ int childEncodedSize = mBuffer.readRawFixed32();
+ if (childRawSize >= 0) {
+ // We know the size, just skip ahead.
+ if (childEncodedSize != childRawSize) {
+ throw new RuntimeException("Pre-computed size where the"
+ + " precomputed size and the raw size in the buffer"
+ + " don't match! childRawSize=" + childRawSize
+ + " childEncodedSize=" + childEncodedSize
+ + " childEncodedSizePos=" + childEncodedSizePos);
+ }
+ mBuffer.skipRead(childRawSize);
+ } else {
+ // We need to compute the size. Recurse.
+ childEncodedSize = editEncodedSize(-childRawSize);
+ mBuffer.editRawFixed32(childEncodedSizePos, childEncodedSize);
+ }
+ encodedSize += EncodedBuffer.getRawVarint32Size(childEncodedSize)
+ + childEncodedSize;
+ break;
+ }
+ case WIRE_TYPE_START_GROUP:
+ case WIRE_TYPE_END_GROUP:
+ throw new RuntimeException("groups not supported at index " + tagPos);
+ case WIRE_TYPE_FIXED32:
+ encodedSize += 4;
+ mBuffer.skipRead(4);
+ break;
+ default:
+ throw new ProtoParseException("editEncodedSize Bad tag tag=0x"
+ + Integer.toHexString(tag) + " wireType=" + wireType
+ + " -- " + mBuffer.getDebugString());
+ }
+ }
+
+ return encodedSize;
+ }
+
+ /**
+ * Second compaction pass. Iterate through the data, and copy the data
+ * forward in the buffer, converting the pairs of uint32s into a single
+ * unsigned varint of the size.
+ */
+ private void compactSizes(int rawSize) {
+ int objectStart = mBuffer.getReadPos();
+ int objectEnd = objectStart + rawSize;
+ int tagPos;
+ while ((tagPos = mBuffer.getReadPos()) < objectEnd) {
+ int tag = readRawTag();
+
+ // For all the non-length-delimited field types, just skip over them,
+ // and we'll just System.arraycopy it later, either in the case for
+ // WIRE_TYPE_LENGTH_DELIMITED or at the top of the stack in compactIfNecessary().
+ final int wireType = tag & WIRE_TYPE_MASK;
+ switch (wireType) {
+ case WIRE_TYPE_VARINT:
+ while ((mBuffer.readRawByte() & 0x80) != 0) { }
+ break;
+ case WIRE_TYPE_FIXED64:
+ mBuffer.skipRead(8);
+ break;
+ case WIRE_TYPE_LENGTH_DELIMITED: {
+ // Copy everything up to now, including the tag for this field.
+ mBuffer.writeFromThisBuffer(mCopyBegin, mBuffer.getReadPos() - mCopyBegin);
+ // Write the new size.
+ final int childRawSize = mBuffer.readRawFixed32();
+ final int childEncodedSize = mBuffer.readRawFixed32();
+ mBuffer.writeRawVarint32(childEncodedSize);
+ // Next time, start copying from here.
+ mCopyBegin = mBuffer.getReadPos();
+ if (childRawSize >= 0) {
+ // This is raw data, not an object. Skip ahead by the size.
+ // Recurse into the child
+ mBuffer.skipRead(childEncodedSize);
+ } else {
+ compactSizes(-childRawSize);
+ }
+ break;
+ // TODO: What does regular proto do if the object would be 0 size
+ // (e.g. if it is all default values).
+ }
+ case WIRE_TYPE_START_GROUP:
+ case WIRE_TYPE_END_GROUP:
+ throw new RuntimeException("groups not supported at index " + tagPos);
+ case WIRE_TYPE_FIXED32:
+ mBuffer.skipRead(4);
+ break;
+ default:
+ throw new ProtoParseException("compactSizes Bad tag tag=0x"
+ + Integer.toHexString(tag) + " wireType=" + wireType
+ + " -- " + mBuffer.getDebugString());
+ }
+ }
+ }
+
+ /**
+ * Read a raw tag from the buffer.
+ */
+ private int readRawTag() {
+ if (mBuffer.getReadPos() == mBuffer.getReadableSize()) {
+ return 0;
+ }
+ return (int)mBuffer.readRawUnsigned();
+ }
+
+ /**
+ * Dump debugging data about the buffers with the given log tag.
+ */
+ public void dump(String tag) {
+ Log.d(tag, mBuffer.getDebugString());
+ mBuffer.dumpBuffers(tag);
+ }
+}
diff --git a/core/java/android/util/proto/ProtoParseException.java b/core/java/android/util/proto/ProtoParseException.java
new file mode 100644
index 0000000..5ba9bf8
--- /dev/null
+++ b/core/java/android/util/proto/ProtoParseException.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.proto;
+
+import android.annotation.TestApi;
+
+/**
+ * Thrown when there is an error parsing protobuf data.
+ *
+ * @hide
+ */
+@TestApi
+public class ProtoParseException extends RuntimeException {
+
+ /**
+ * Construct a ProtoParseException.
+ *
+ * @param msg The message.
+ */
+ public ProtoParseException(String msg) {
+ super(msg);
+ }
+}
+
diff --git a/core/java/android/util/proto/package.html b/core/java/android/util/proto/package.html
new file mode 100644
index 0000000..a636bd4
--- /dev/null
+++ b/core/java/android/util/proto/package.html
@@ -0,0 +1,5 @@
+<body>
+Provides utility classes to export protocol buffers from the system.
+
+{@hide}
+</body>
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 85a4bf9..3beb00f 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -16,11 +16,11 @@
package android.view;
+import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE;
+
import android.annotation.IntDef;
import android.annotation.RequiresPermission;
-import android.content.Context;
import android.content.res.CompatibilityInfo;
-import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.Rect;
@@ -36,8 +36,6 @@
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
-import static android.Manifest.permission.CONFIGURE_DISPLAY_COLOR_MODE;
-
/**
* Provides information about the size and density of a logical display.
* <p>
diff --git a/core/java/android/view/DisplayAdjustments.java b/core/java/android/view/DisplayAdjustments.java
index dd86062..790029b 100644
--- a/core/java/android/view/DisplayAdjustments.java
+++ b/core/java/android/view/DisplayAdjustments.java
@@ -26,18 +26,20 @@
public static final DisplayAdjustments DEFAULT_DISPLAY_ADJUSTMENTS = new DisplayAdjustments();
private volatile CompatibilityInfo mCompatInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
- private Configuration mConfiguration = Configuration.EMPTY;
+ private Configuration mConfiguration;
public DisplayAdjustments() {
}
public DisplayAdjustments(Configuration configuration) {
- mConfiguration = configuration;
+ mConfiguration = new Configuration(configuration != null
+ ? configuration : Configuration.EMPTY);
}
public DisplayAdjustments(DisplayAdjustments daj) {
setCompatibilityInfo(daj.mCompatInfo);
- mConfiguration = daj.mConfiguration;
+ mConfiguration = new Configuration(daj.mConfiguration != null
+ ? daj.mConfiguration : Configuration.EMPTY);
}
public void setCompatibilityInfo(CompatibilityInfo compatInfo) {
@@ -62,7 +64,7 @@
throw new IllegalArgumentException(
"setConfiguration: Cannot modify DEFAULT_DISPLAY_ADJUSTMENTS");
}
- mConfiguration = configuration != null ? configuration : Configuration.EMPTY;
+ mConfiguration.setTo(configuration != null ? configuration : Configuration.EMPTY);
}
public Configuration getConfiguration() {
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 5a9a1ea..67cdfc5 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -16,12 +16,13 @@
package android.view;
-import dalvik.system.CloseGuard;
-
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
+import dalvik.annotation.optimization.FastNative;
+import dalvik.system.CloseGuard;
+
import java.lang.ref.WeakReference;
/**
@@ -47,6 +48,7 @@
private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
MessageQueue messageQueue);
private static native void nativeDispose(long receiverPtr);
+ @FastNative
private static native void nativeScheduleVsync(long receiverPtr);
/**
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index bc40849..1aef6ec 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -23,10 +23,10 @@
import android.util.ArraySet;
import android.util.DisplayMetrics;
-import java.util.Arrays;
-
import libcore.util.Objects;
+import java.util.Arrays;
+
/**
* Describes the characteristics of a particular logical display.
* @hide
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index 44d7a86..872303a 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -24,6 +24,8 @@
import android.graphics.Paint;
import android.util.Pools.SynchronizedPool;
+import dalvik.annotation.optimization.FastNative;
+
/**
* A Canvas implementation that records view system drawing operations for deferred rendering.
* This is intended for use with a DisplayList. This class keeps a list of all the Paint and
@@ -83,9 +85,6 @@
mDensity = 0; // disable bitmap density scaling
}
- private static native long nCreateDisplayListCanvas(int width, int height);
- private static native void nResetDisplayListCanvas(long canvas, int width, int height);
-
///////////////////////////////////////////////////////////////////////////
// Canvas management
///////////////////////////////////////////////////////////////////////////
@@ -131,9 +130,6 @@
return nGetMaximumTextureHeight();
}
- private static native int nGetMaximumTextureWidth();
- private static native int nGetMaximumTextureHeight();
-
///////////////////////////////////////////////////////////////////////////
// Setup
///////////////////////////////////////////////////////////////////////////
@@ -148,8 +144,6 @@
nInsertReorderBarrier(mNativeCanvasWrapper, false);
}
- private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
-
///////////////////////////////////////////////////////////////////////////
// Functor
///////////////////////////////////////////////////////////////////////////
@@ -180,15 +174,10 @@
nCallDrawGLFunction(mNativeCanvasWrapper, drawGLFunctor, releasedCallback);
}
- private static native void nCallDrawGLFunction(long renderer,
- long drawGLFunction, Runnable releasedCallback);
-
///////////////////////////////////////////////////////////////////////////
// Display list
///////////////////////////////////////////////////////////////////////////
- protected static native long nFinishRecording(long renderer);
-
/**
* Draws the specified display list onto this canvas. The display list can only
* be drawn if {@link android.view.RenderNode#isValid()} returns true.
@@ -199,8 +188,6 @@
nDrawRenderNode(mNativeCanvasWrapper, renderNode.getNativeDisplayList());
}
- private static native void nDrawRenderNode(long renderer, long renderNode);
-
///////////////////////////////////////////////////////////////////////////
// Hardware layer
///////////////////////////////////////////////////////////////////////////
@@ -214,8 +201,6 @@
nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle());
}
- private static native void nDrawLayer(long renderer, long layer);
-
///////////////////////////////////////////////////////////////////////////
// Drawing
///////////////////////////////////////////////////////////////////////////
@@ -226,9 +211,6 @@
radius.getNativeContainer(), paint.getNativeContainer());
}
- private static native void nDrawCircle(long renderer, long propCx,
- long propCy, long propRadius, long propPaint);
-
public void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top,
CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx,
CanvasProperty<Float> ry, CanvasProperty<Paint> paint) {
@@ -238,9 +220,6 @@
paint.getNativeContainer());
}
- private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
- long propRight, long propBottom, long propRx, long propRy, long propPaint);
-
@Override
protected void throwIfCannotDraw(Bitmap bitmap) {
super.throwIfCannotDraw(bitmap);
@@ -250,4 +229,30 @@
"Canvas: trying to draw too large(" + bitmapSize + "bytes) bitmap.");
}
}
+
+ @FastNative
+ private static native long nCreateDisplayListCanvas(int width, int height);
+ @FastNative
+ private static native void nResetDisplayListCanvas(long canvas, int width, int height);
+ @FastNative
+ private static native int nGetMaximumTextureWidth();
+ @FastNative
+ private static native int nGetMaximumTextureHeight();
+ @FastNative
+ private static native void nInsertReorderBarrier(long renderer, boolean enableReorder);
+ @FastNative
+ private static native void nCallDrawGLFunction(long renderer,
+ long drawGLFunction, Runnable releasedCallback);
+ @FastNative
+ private static native long nFinishRecording(long renderer);
+ @FastNative
+ private static native void nDrawRenderNode(long renderer, long renderNode);
+ @FastNative
+ private static native void nDrawLayer(long renderer, long layer);
+ @FastNative
+ private static native void nDrawCircle(long renderer, long propCx,
+ long propCy, long propRadius, long propPaint);
+ @FastNative
+ private static native void nDrawRoundRect(long renderer, long propLeft, long propTop,
+ long propRight, long propBottom, long propRx, long propRy, long propPaint);
}
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 2baa0b4..16f2d7d 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -26,7 +26,7 @@
//TODO: Improve Javadoc
/**
* Represents an event that is sent out by the system at various times during a drag and drop
- * operation. It is a complex data structure that contains several important pieces of data about
+ * operation. It is a data structure that contains several important pieces of data about
* the operation and the underlying data.
* <p>
* View objects that receive a DragEvent call {@link #getAction()}, which returns
@@ -161,8 +161,8 @@
* event when they are added or becoming visible.
* </p>
* <p>
- * A View only receives further drag events if it returns {@code true} in response to
- * ACTION_DRAG_STARTED.
+ * A View only receives further drag events for the drag operation if it returns {@code true}
+ * in response to ACTION_DRAG_STARTED.
* </p>
* @see #ACTION_DRAG_ENDED
* @see #getX()
@@ -172,8 +172,9 @@
/**
* Action constant returned by {@link #getAction()}: Sent to a View after
- * {@link #ACTION_DRAG_ENTERED} if the drag shadow is still within the View object's bounding
- * box. The {@link #getX()} and {@link #getY()} methods supply
+ * {@link #ACTION_DRAG_ENTERED} while the drag shadow is still within the View object's bounding
+ * box, but not within a descendant view that can accept the data. The {@link #getX()} and
+ * {@link #getY()} methods supply
* the X and Y position of of the drag point within the View object's bounding box.
* <p>
* A View receives an {@link #ACTION_DRAG_ENTERED} event before receiving any
@@ -355,9 +356,10 @@
/**
* Returns the {@link android.content.ClipData} object sent to the system as part of the call
* to
- * {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+ * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ * startDragAndDrop()}.
* This method only returns valid data if the event action is {@link #ACTION_DROP}.
- * @return The ClipData sent to the system by startDrag().
+ * @return The ClipData sent to the system by startDragAndDrop().
*/
public ClipData getClipData() {
return mClipData;
@@ -366,12 +368,14 @@
/**
* Returns the {@link android.content.ClipDescription} object contained in the
* {@link android.content.ClipData} object sent to the system as part of the call to
- * {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+ * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ * startDragAndDrop()}.
* The drag handler or listener for a View can use the metadata in this object to decide if the
* View can accept the dragged View object's data.
* <p>
* This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
- * @return The ClipDescription that was part of the ClipData sent to the system by startDrag().
+ * @return The ClipDescription that was part of the ClipData sent to the system by
+ * startDragAndDrop().
*/
public ClipDescription getClipDescription() {
return mClipDescription;
@@ -384,7 +388,8 @@
/**
* Returns the local state object sent to the system as part of the call to
- * {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+ * {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ * startDragAndDrop()}.
* The object is intended to provide local information about the drag and drop operation. For
* example, it can indicate whether the drag and drop operation is a copy or a move.
* <p>
@@ -394,7 +399,7 @@
* <p>
* This method returns valid data for all event actions except for {@link #ACTION_DRAG_ENDED}.
* </p>
- * @return The local state object sent to the system by startDrag().
+ * @return The local state object sent to the system by startDragAndDrop().
*/
public Object getLocalState() {
return mLocalState;
diff --git a/core/java/android/view/FallbackEventHandler.java b/core/java/android/view/FallbackEventHandler.java
index dd68d89..8e00d6d 100644
--- a/core/java/android/view/FallbackEventHandler.java
+++ b/core/java/android/view/FallbackEventHandler.java
@@ -24,4 +24,3 @@
public void preDispatchKeyEvent(KeyEvent event);
public boolean dispatchKeyEvent(KeyEvent event);
}
-
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 2b938d0..800a63f 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -17,7 +17,6 @@
package android.view;
import android.annotation.IntDef;
-import android.view.Window;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/view/FrameMetricsObserver.java b/core/java/android/view/FrameMetricsObserver.java
index 6331357..9e81de0 100644
--- a/core/java/android/view/FrameMetricsObserver.java
+++ b/core/java/android/view/FrameMetricsObserver.java
@@ -17,15 +17,12 @@
package android.view;
import android.annotation.NonNull;
-import android.util.Log;
import android.os.Looper;
import android.os.MessageQueue;
import com.android.internal.util.VirtualRefBasePtr;
-import java.lang.NullPointerException;
import java.lang.ref.WeakReference;
-import java.lang.SuppressWarnings;
/**
* Provides streaming access to frame stats information from the rendering
diff --git a/core/java/android/view/HandlerActionQueue.java b/core/java/android/view/HandlerActionQueue.java
index 4758a34..d016a74 100644
--- a/core/java/android/view/HandlerActionQueue.java
+++ b/core/java/android/view/HandlerActionQueue.java
@@ -16,11 +16,9 @@
package android.view;
-import com.android.internal.util.GrowingArrayUtils;
-
import android.os.Handler;
-import java.util.ArrayList;
+import com.android.internal.util.GrowingArrayUtils;
/**
* Class used to enqueue pending work from Views when no Handler is attached.
diff --git a/core/java/android/view/IAssetAtlas.aidl b/core/java/android/view/IAssetAtlas.aidl
deleted file mode 100644
index edce059..0000000
--- a/core/java/android/view/IAssetAtlas.aidl
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Copyright (c) 2013, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.view;
-
-import android.view.GraphicBuffer;
-
-/**
- * Programming interface to the system assets atlas. This atlas, when
- * present, holds preloaded drawable in a single, shareable graphics
- * buffer. This allows multiple processes to share the same data to
- * save up on memory.
- *
- * @hide
- */
-interface IAssetAtlas {
- /**
- * Indicates whether the atlas is compatible with the specified
- * parent process id. If the atlas' ppid does not match, this
- * method will return false.
- */
- boolean isCompatible(int ppid);
-
- /**
- * Returns the atlas buffer (texture) or null if the atlas is
- * not available yet.
- */
- GraphicBuffer getBuffer();
-
- /**
- * Returns the map of the bitmaps stored in the atlas or null
- * if the atlas is not available yet.
- *
- * Each bitmap is represented by several entries in the array:
- * long0: SkBitmap*, the native bitmap object
- * long1: x position
- * long2: y position
- * long3: rotated, 1 if the bitmap must be rotated, 0 otherwise
- */
- long[] getMap();
-}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 897e29b..717b675 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -454,12 +454,13 @@
void registerShortcutKey(in long shortcutCode, IShortcutService keySubscriber);
/**
- * Create the input consumer for wallpaper events.
+ * Create an input consumer by name.
*/
- void createWallpaperInputConsumer(out InputChannel inputChannel);
+ void createInputConsumer(String name, out InputChannel inputChannel);
/**
- * Remove the input consumer for wallpaper events.
+ * Destroy an input consumer by name. This method will also dispose the input channels
+ * associated with that InputConsumer.
*/
- void removeWallpaperInputConsumer();
+ boolean destroyInputConsumer(String name);
}
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index f8796c3..55f64d9 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -19,10 +19,10 @@
import android.content.Context;
import android.hardware.input.InputDeviceIdentifier;
import android.hardware.input.InputManager;
+import android.os.NullVibrator;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Vibrator;
-import android.os.NullVibrator;
import java.util.ArrayList;
import java.util.List;
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 91ef50d..20ab539 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -16,13 +16,13 @@
package android.view;
-import dalvik.system.CloseGuard;
-
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
import android.util.SparseIntArray;
+import dalvik.system.CloseGuard;
+
import java.lang.ref.WeakReference;
/**
diff --git a/core/java/android/view/InputEventSender.java b/core/java/android/view/InputEventSender.java
index 304ea3f..b25fb65 100644
--- a/core/java/android/view/InputEventSender.java
+++ b/core/java/android/view/InputEventSender.java
@@ -16,12 +16,12 @@
package android.view;
-import dalvik.system.CloseGuard;
-
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
+import dalvik.system.CloseGuard;
+
import java.lang.ref.WeakReference;
/**
diff --git a/core/java/android/view/InputFilter.java b/core/java/android/view/InputFilter.java
index 4aba30c..d0dab40 100644
--- a/core/java/android/view/InputFilter.java
+++ b/core/java/android/view/InputFilter.java
@@ -20,12 +20,6 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
-import android.view.IInputFilter;
-import android.view.InputEvent;
-import android.view.InputEventConsistencyVerifier;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.WindowManagerPolicy;
/**
* Filters input events before they are dispatched to the system.
diff --git a/core/java/android/view/InputQueue.java b/core/java/android/view/InputQueue.java
index aebc601..582ae79 100644
--- a/core/java/android/view/InputQueue.java
+++ b/core/java/android/view/InputQueue.java
@@ -16,13 +16,13 @@
package android.view;
-import dalvik.system.CloseGuard;
-
import android.os.Looper;
import android.os.MessageQueue;
+import android.util.LongSparseArray;
import android.util.Pools.Pool;
import android.util.Pools.SimplePool;
-import android.util.LongSparseArray;
+
+import dalvik.system.CloseGuard;
import java.lang.ref.WeakReference;
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index c8b89e7..88f2d34 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -16,14 +16,13 @@
package android.view;
+import android.hardware.input.InputManager;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.method.MetaKeyKeyListener;
import android.util.AndroidRuntimeException;
import android.util.SparseIntArray;
-import android.hardware.input.InputManager;
-import java.lang.Character;
import java.text.Normalizer;
/**
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index b73acda..5d8f336 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -21,7 +21,6 @@
import android.text.method.MetaKeyKeyListener;
import android.util.Log;
import android.util.SparseIntArray;
-import android.view.KeyCharacterMap;
import android.view.KeyCharacterMap.KeyData;
/**
diff --git a/core/java/android/view/KeyboardShortcutGroup.java b/core/java/android/view/KeyboardShortcutGroup.java
index 57d07c0..78f0b30 100644
--- a/core/java/android/view/KeyboardShortcutGroup.java
+++ b/core/java/android/view/KeyboardShortcutGroup.java
@@ -15,6 +15,8 @@
*/
package android.view;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
@@ -24,8 +26,6 @@
import java.util.Collections;
import java.util.List;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
/**
* A group of {@link KeyboardShortcutInfo}.
*/
diff --git a/core/java/android/view/KeyboardShortcutInfo.java b/core/java/android/view/KeyboardShortcutInfo.java
index a9f2699..c934a4e 100644
--- a/core/java/android/view/KeyboardShortcutInfo.java
+++ b/core/java/android/view/KeyboardShortcutInfo.java
@@ -15,14 +15,15 @@
*/
package android.view;
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import static java.lang.Character.MIN_VALUE;
+
import android.annotation.Nullable;
import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.os.Parcelable;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static java.lang.Character.MIN_VALUE;
-
/**
* Information about a Keyboard Shortcut.
*/
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 914bd56..e3ac40c 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -16,11 +16,6 @@
package android.view;
-import com.android.internal.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.annotation.LayoutRes;
import android.annotation.Nullable;
import android.content.Context;
@@ -37,6 +32,11 @@
import android.util.Xml;
import android.widget.FrameLayout;
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.HashMap;
@@ -51,20 +51,20 @@
*
* <pre>LayoutInflater inflater = (LayoutInflater)context.getSystemService
* (Context.LAYOUT_INFLATER_SERVICE);</pre>
- *
+ *
* <p>
* To create a new LayoutInflater with an additional {@link Factory} for your
* own views, you can use {@link #cloneInContext} to clone an existing
* ViewFactory, and then call {@link #setFactory} on it to include your
* Factory.
- *
+ *
* <p>
* For performance reasons, view inflation relies heavily on pre-processing of
* XML files that is done at build time. Therefore, it is not currently possible
* to use LayoutInflater with an XmlPullParser over a plain XML file at runtime;
* it only works with an XmlPullParser returned from a compiled resource
* (R.<em>something</em> file.)
- *
+ *
* @see Context#getSystemService
*/
public abstract class LayoutInflater {
@@ -95,7 +95,7 @@
private static final HashMap<String, Constructor<? extends View>> sConstructorMap =
new HashMap<String, Constructor<? extends View>>();
-
+
private HashMap<String, Boolean> mFilterMap;
private TypedValue mTempValue;
@@ -114,36 +114,36 @@
/**
* Hook to allow clients of the LayoutInflater to restrict the set of Views that are allowed
* to be inflated.
- *
+ *
*/
public interface Filter {
/**
- * Hook to allow clients of the LayoutInflater to restrict the set of Views
+ * Hook to allow clients of the LayoutInflater to restrict the set of Views
* that are allowed to be inflated.
- *
+ *
* @param clazz The class object for the View that is about to be inflated
- *
+ *
* @return True if this class is allowed to be inflated, or false otherwise
*/
@SuppressWarnings("unchecked")
boolean onLoadClass(Class clazz);
}
-
+
public interface Factory {
/**
* Hook you can supply that is called when inflating from a LayoutInflater.
* You can use this to customize the tag names available in your XML
* layout files.
- *
+ *
* <p>
* Note that it is good practice to prefix these custom names with your
* package (i.e., com.coolcompany.apps) to avoid conflicts with system
* names.
- *
+ *
* @param name Tag name to be inflated.
* @param context The context the view is being created in.
* @param attrs Inflation attributes as specified in XML file.
- *
+ *
* @return View Newly created view. Return null for the default
* behavior.
*/
@@ -171,14 +171,14 @@
private static class FactoryMerger implements Factory2 {
private final Factory mF1, mF2;
private final Factory2 mF12, mF22;
-
+
FactoryMerger(Factory f1, Factory2 f12, Factory f2, Factory2 f22) {
mF1 = f1;
mF2 = f2;
mF12 = f12;
mF22 = f22;
}
-
+
public View onCreateView(String name, Context context, AttributeSet attrs) {
View v = mF1.onCreateView(name, context, attrs);
if (v != null) return v;
@@ -193,13 +193,13 @@
: mF2.onCreateView(name, context, attrs);
}
}
-
+
/**
* Create a new LayoutInflater instance associated with a particular Context.
* Applications will almost always want to use
* {@link Context#getSystemService Context.getSystemService()} to retrieve
* the standard {@link Context#LAYOUT_INFLATER_SERVICE Context.INFLATER_SERVICE}.
- *
+ *
* @param context The Context in which this LayoutInflater will create its
* Views; most importantly, this supplies the theme from which the default
* values for their attributes are retrieved.
@@ -212,7 +212,7 @@
* Create a new LayoutInflater instance that is a copy of an existing
* LayoutInflater, optionally with its Context changed. For use in
* implementing {@link #cloneInContext}.
- *
+ *
* @param original The original LayoutInflater to copy.
* @param newContext The new Context to use.
*/
@@ -223,7 +223,7 @@
mPrivateFactory = original.mPrivateFactory;
setFilter(original.mFilter);
}
-
+
/**
* Obtains the LayoutInflater from the given context.
*/
@@ -241,15 +241,15 @@
* pointing to a different Context than the original. This is used by
* {@link ContextThemeWrapper} to create a new LayoutInflater to go along
* with the new Context theme.
- *
+ *
* @param newContext The new Context to associate with the new LayoutInflater.
* May be the same as the original Context if desired.
- *
+ *
* @return Returns a brand spanking new LayoutInflater object associated with
* the given Context.
*/
public abstract LayoutInflater cloneInContext(Context newContext);
-
+
/**
* Return the context we are running in, for access to resources, class
* loader, etc.
@@ -285,7 +285,7 @@
* called on each element name as the xml is parsed. If the factory returns
* a View, that is added to the hierarchy. If it returns null, the next
* factory default {@link #onCreateView} method is called.
- *
+ *
* <p>If you have an existing
* LayoutInflater and want to add your own factory to it, use
* {@link #cloneInContext} to clone the existing instance and then you
@@ -345,13 +345,13 @@
public Filter getFilter() {
return mFilter;
}
-
+
/**
* Sets the {@link Filter} to by this LayoutInflater. If a view is attempted to be inflated
* which is not allowed by the {@link Filter}, the {@link #inflate(int, ViewGroup)} call will
* throw an {@link InflateException}. This filter will replace any previous filter set on this
* LayoutInflater.
- *
+ *
* @param filter The Filter which restricts the set of Views that are allowed to be inflated.
* This filter will replace any previous filter set on this LayoutInflater.
*/
@@ -365,7 +365,7 @@
/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
- *
+ *
* @param resource ID for an XML layout resource to load (e.g.,
* <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy.
@@ -385,7 +385,7 @@
* reasons, view inflation relies heavily on pre-processing of XML files
* that is done at build time. Therefore, it is not currently possible to
* use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
- *
+ *
* @param parser XML dom node containing the description of the view
* hierarchy.
* @param root Optional view to be the parent of the generated hierarchy.
@@ -400,7 +400,7 @@
/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
- *
+ *
* @param resource ID for an XML layout resource to load (e.g.,
* <code>R.layout.main_page</code>)
* @param root Optional view to be the parent of the generated hierarchy (if
@@ -437,7 +437,7 @@
* reasons, view inflation relies heavily on pre-processing of XML files
* that is done at build time. Therefore, it is not currently possible to
* use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
- *
+ *
* @param parser XML dom node containing the description of the view
* hierarchy.
* @param root Optional view to be the parent of the generated hierarchy (if
@@ -475,7 +475,7 @@
}
final String name = parser.getName();
-
+
if (DEBUG) {
System.out.println("**************************");
System.out.println("Creating root view: "
@@ -579,17 +579,17 @@
* Low-level function for instantiating a view by name. This attempts to
* instantiate a view class of the given <var>name</var> found in this
* LayoutInflater's ClassLoader.
- *
+ *
* <p>
* There are two things that can happen in an error case: either the
* exception describing the error will be thrown, or a null will be
* returned. You must deal with both possibilities -- the former will happen
* the first time createView() is called for a class of a particular name,
* the latter every time there-after for that class name.
- *
+ *
* @param name The full name of the class to be instantiated.
* @param attrs The XML attributes supplied for this instance.
- *
+ *
* @return View The newly instantiated view, or null.
*/
public final View createView(String name, String prefix, AttributeSet attrs)
@@ -608,7 +608,7 @@
// Class not found in the cache, see if it's real, and try to add it
clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name).asSubclass(View.class);
-
+
if (mFilter != null && clazz != null) {
boolean allowed = mFilter.onLoadClass(clazz);
if (!allowed) {
@@ -627,7 +627,7 @@
// New class -- remember whether it is allowed
clazz = mContext.getClassLoader().loadClass(
prefix != null ? (prefix + name) : name).asSubclass(View.class);
-
+
boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
mFilterMap.put(name, allowed);
if (!allowed) {
@@ -689,10 +689,10 @@
* given the xml element name. Override it to handle custom view objects. If
* you override this in your subclass be sure to call through to
* super.onCreateView(name) for names you do not recognize.
- *
+ *
* @param name The fully qualified class name of the View to be create.
* @param attrs An AttributeSet of attributes to apply to the View.
- *
+ *
* @return View The View created.
*/
protected View onCreateView(String name, AttributeSet attrs)
@@ -842,7 +842,7 @@
}
final String name = parser.getName();
-
+
if (TAG_REQUEST_FOCUS.equals(name)) {
parseRequestFocus(parser, parent);
} else if (TAG_TAG.equals(name)) {
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index 1c67ba7..73ea9ee 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -16,11 +16,6 @@
package android.view;
-import com.android.internal.view.menu.MenuItemImpl;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.annotation.MenuRes;
import android.app.Activity;
import android.content.Context;
@@ -31,6 +26,11 @@
import android.util.Log;
import android.util.Xml;
+import com.android.internal.view.menu.MenuItemImpl;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
@@ -49,15 +49,15 @@
/** Menu tag name in XML. */
private static final String XML_MENU = "menu";
-
+
/** Group tag name in XML. */
private static final String XML_GROUP = "group";
-
+
/** Item tag name in XML. */
private static final String XML_ITEM = "item";
private static final int NO_ID = 0;
-
+
private static final Class<?>[] ACTION_VIEW_CONSTRUCTOR_SIGNATURE = new Class[] {Context.class};
private static final Class<?>[] ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE = ACTION_VIEW_CONSTRUCTOR_SIGNATURE;
@@ -71,7 +71,7 @@
/**
* Constructs a menu inflater.
- *
+ *
* @see Activity#getMenuInflater()
*/
public MenuInflater(Context context) {
@@ -96,7 +96,7 @@
/**
* Inflate a menu hierarchy from the specified XML resource. Throws
* {@link InflateException} if there is an error.
- *
+ *
* @param menuRes Resource ID for an XML layout resource to load (e.g.,
* <code>R.menu.main_activity</code>)
* @param menu The Menu to inflate into. The items and submenus will be
@@ -107,7 +107,7 @@
try {
parser = mContext.getResources().getLayout(menuRes);
AttributeSet attrs = Xml.asAttributeSet(parser);
-
+
parseMenu(parser, attrs, menu);
} catch (XmlPullParserException e) {
throw new InflateException("Error inflating menu XML", e);
@@ -140,12 +140,12 @@
eventType = parser.next();
break;
}
-
+
throw new RuntimeException("Expecting menu, got " + tagName);
}
eventType = parser.next();
} while (eventType != XmlPullParser.END_DOCUMENT);
-
+
boolean reachedEndOfMenu = false;
while (!reachedEndOfMenu) {
switch (eventType) {
@@ -153,7 +153,7 @@
if (lookingForEndOfUnknownTag) {
break;
}
-
+
tagName = parser.getName();
if (tagName.equals(XML_GROUP)) {
menuState.readGroup(attrs);
@@ -171,7 +171,7 @@
unknownTagName = tagName;
}
break;
-
+
case XmlPullParser.END_TAG:
tagName = parser.getName();
if (lookingForEndOfUnknownTag && tagName.equals(unknownTagName)) {
@@ -194,11 +194,11 @@
reachedEndOfMenu = true;
}
break;
-
+
case XmlPullParser.END_DOCUMENT:
throw new RuntimeException("Unexpected end of document");
}
-
+
eventType = parser.next();
}
}
@@ -229,10 +229,10 @@
private static class InflatedOnMenuItemClickListener
implements MenuItem.OnMenuItemClickListener {
private static final Class<?>[] PARAM_TYPES = new Class[] { MenuItem.class };
-
+
private Object mRealOwner;
private Method mMethod;
-
+
public InflatedOnMenuItemClickListener(Object realOwner, String methodName) {
mRealOwner = realOwner;
Class<?> c = realOwner.getClass();
@@ -246,7 +246,7 @@
throw ex;
}
}
-
+
public boolean onMenuItemClick(MenuItem item) {
try {
if (mMethod.getReturnType() == Boolean.TYPE) {
@@ -277,7 +277,7 @@
}
return owner;
}
-
+
/**
* State for the current menu.
* <p>
@@ -316,7 +316,7 @@
private boolean itemChecked;
private boolean itemVisible;
private boolean itemEnabled;
-
+
/**
* Sync to attrs.xml enum, values in MenuItem:
* - 0: never
@@ -331,7 +331,7 @@
private String itemActionProviderClassName;
private String itemListenerMethodName;
-
+
private ActionProvider itemActionProvider;
private static final int defaultGroupId = NO_ID;
@@ -342,13 +342,13 @@
private static final boolean defaultItemChecked = false;
private static final boolean defaultItemVisible = true;
private static final boolean defaultItemEnabled = true;
-
+
public MenuState(final Menu menu) {
this.menu = menu;
-
+
resetGroup();
}
-
+
public void resetGroup() {
groupId = defaultGroupId;
groupCategory = defaultItemCategory;
@@ -364,7 +364,7 @@
public void readGroup(AttributeSet attrs) {
TypedArray a = mContext.obtainStyledAttributes(attrs,
com.android.internal.R.styleable.MenuGroup);
-
+
groupId = a.getResourceId(com.android.internal.R.styleable.MenuGroup_id, defaultGroupId);
groupCategory = a.getInt(com.android.internal.R.styleable.MenuGroup_menuCategory, defaultItemCategory);
groupOrder = a.getInt(com.android.internal.R.styleable.MenuGroup_orderInCategory, defaultItemOrder);
@@ -374,7 +374,7 @@
a.recycle();
}
-
+
/**
* Called when the parser is pointing to an item tag.
*/
@@ -436,7 +436,7 @@
return shortcutString.charAt(0);
}
}
-
+
private void setItem(MenuItem item) {
item.setChecked(itemChecked)
.setVisible(itemVisible)
@@ -446,11 +446,11 @@
.setIcon(itemIconResId)
.setAlphabeticShortcut(itemAlphabeticShortcut)
.setNumericShortcut(itemNumericShortcut);
-
+
if (itemShowAsAction >= 0) {
item.setShowAsAction(itemShowAsAction);
}
-
+
if (itemListenerMethodName != null) {
if (mContext.isRestricted()) {
throw new IllegalStateException("The android:onClick attribute cannot "
@@ -494,14 +494,14 @@
setItem(item);
return item;
}
-
+
public SubMenu addSubMenuItem() {
itemAdded = true;
SubMenu subMenu = menu.addSubMenu(groupId, itemId, itemCategoryOrder, itemTitle);
setItem(subMenu.getItem());
return subMenu;
}
-
+
public boolean hasAddedItem() {
return itemAdded;
}
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index fab5364..2316b38 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -23,6 +23,9 @@
import android.os.SystemClock;
import android.util.SparseArray;
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
/**
* Object used to report movement (mouse, pen, finger, trackball) events.
* Motion events may hold either absolute or relative movements and other data,
@@ -433,6 +436,14 @@
public static final int FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2;
/**
+ * This private flag is only set on {@link #ACTION_HOVER_MOVE} events and indicates that
+ * this event will be immediately followed by a {@link #ACTION_HOVER_EXIT}. It is used to
+ * prevent generating redundant {@link #ACTION_HOVER_ENTER} events.
+ * @hide
+ */
+ public static final int FLAG_HOVER_EXIT_PENDING = 0x4;
+
+ /**
* Private flag that indicates when the system has detected that this motion event
* may be inconsistent with respect to the sequence of previously delivered motion events,
* such as when a pointer move event is sent but the pointer is not down.
@@ -1445,60 +1456,98 @@
float xOffset, float yOffset, float xPrecision, float yPrecision,
long downTimeNanos, long eventTimeNanos,
int pointerCount, PointerProperties[] pointerIds, PointerCoords[] pointerCoords);
- private static native long nativeCopy(long destNativePtr, long sourceNativePtr,
- boolean keepHistory);
private static native void nativeDispose(long nativePtr);
private static native void nativeAddBatch(long nativePtr, long eventTimeNanos,
PointerCoords[] pointerCoords, int metaState);
-
- private static native int nativeGetDeviceId(long nativePtr);
- private static native int nativeGetSource(long nativePtr);
- private static native int nativeSetSource(long nativePtr, int source);
- private static native int nativeGetAction(long nativePtr);
- private static native void nativeSetAction(long nativePtr, int action);
- private static native boolean nativeIsTouchEvent(long nativePtr);
- private static native int nativeGetFlags(long nativePtr);
- private static native void nativeSetFlags(long nativePtr, int flags);
- private static native int nativeGetEdgeFlags(long nativePtr);
- private static native void nativeSetEdgeFlags(long nativePtr, int action);
- private static native int nativeGetMetaState(long nativePtr);
- private static native int nativeGetButtonState(long nativePtr);
- private static native void nativeSetButtonState(long nativePtr, int buttonState);
- private static native int nativeGetActionButton(long nativePtr);
- private static native void nativeSetActionButton(long nativePtr, int actionButton);
- private static native void nativeOffsetLocation(long nativePtr, float deltaX, float deltaY);
- private static native float nativeGetXOffset(long nativePtr);
- private static native float nativeGetYOffset(long nativePtr);
- private static native float nativeGetXPrecision(long nativePtr);
- private static native float nativeGetYPrecision(long nativePtr);
- private static native long nativeGetDownTimeNanos(long nativePtr);
- private static native void nativeSetDownTimeNanos(long nativePtr, long downTime);
-
- private static native int nativeGetPointerCount(long nativePtr);
- private static native int nativeGetPointerId(long nativePtr, int pointerIndex);
- private static native int nativeGetToolType(long nativePtr, int pointerIndex);
- private static native int nativeFindPointerIndex(long nativePtr, int pointerId);
-
- private static native int nativeGetHistorySize(long nativePtr);
- private static native long nativeGetEventTimeNanos(long nativePtr, int historyPos);
- private static native float nativeGetRawAxisValue(long nativePtr,
- int axis, int pointerIndex, int historyPos);
- private static native float nativeGetAxisValue(long nativePtr,
- int axis, int pointerIndex, int historyPos);
private static native void nativeGetPointerCoords(long nativePtr,
int pointerIndex, int historyPos, PointerCoords outPointerCoords);
private static native void nativeGetPointerProperties(long nativePtr,
int pointerIndex, PointerProperties outPointerProperties);
- private static native void nativeScale(long nativePtr, float scale);
- private static native void nativeTransform(long nativePtr, Matrix matrix);
-
private static native long nativeReadFromParcel(long nativePtr, Parcel parcel);
private static native void nativeWriteToParcel(long nativePtr, Parcel parcel);
private static native String nativeAxisToString(int axis);
private static native int nativeAxisFromString(String label);
+ // -------------- @FastNative -------------------------
+
+ @FastNative
+ private static native int nativeGetPointerId(long nativePtr, int pointerIndex);
+ @FastNative
+ private static native int nativeGetToolType(long nativePtr, int pointerIndex);
+ @FastNative
+ private static native long nativeGetEventTimeNanos(long nativePtr, int historyPos);
+ @FastNative
+ private static native float nativeGetRawAxisValue(long nativePtr,
+ int axis, int pointerIndex, int historyPos);
+ @FastNative
+ private static native float nativeGetAxisValue(long nativePtr,
+ int axis, int pointerIndex, int historyPos);
+
+ // -------------- @CriticalNative ----------------------
+
+ @CriticalNative
+ private static native long nativeCopy(long destNativePtr, long sourceNativePtr,
+ boolean keepHistory);
+ @CriticalNative
+ private static native int nativeGetDeviceId(long nativePtr);
+ @CriticalNative
+ private static native int nativeGetSource(long nativePtr);
+ @CriticalNative
+ private static native int nativeSetSource(long nativePtr, int source);
+ @CriticalNative
+ private static native int nativeGetAction(long nativePtr);
+ @CriticalNative
+ private static native void nativeSetAction(long nativePtr, int action);
+ @CriticalNative
+ private static native boolean nativeIsTouchEvent(long nativePtr);
+ @CriticalNative
+ private static native int nativeGetFlags(long nativePtr);
+ @CriticalNative
+ private static native void nativeSetFlags(long nativePtr, int flags);
+ @CriticalNative
+ private static native int nativeGetEdgeFlags(long nativePtr);
+ @CriticalNative
+ private static native void nativeSetEdgeFlags(long nativePtr, int action);
+ @CriticalNative
+ private static native int nativeGetMetaState(long nativePtr);
+ @CriticalNative
+ private static native int nativeGetButtonState(long nativePtr);
+ @CriticalNative
+ private static native void nativeSetButtonState(long nativePtr, int buttonState);
+ @CriticalNative
+ private static native int nativeGetActionButton(long nativePtr);
+ @CriticalNative
+ private static native void nativeSetActionButton(long nativePtr, int actionButton);
+ @CriticalNative
+ private static native void nativeOffsetLocation(long nativePtr, float deltaX, float deltaY);
+ @CriticalNative
+ private static native float nativeGetXOffset(long nativePtr);
+ @CriticalNative
+ private static native float nativeGetYOffset(long nativePtr);
+ @CriticalNative
+ private static native float nativeGetXPrecision(long nativePtr);
+ @CriticalNative
+ private static native float nativeGetYPrecision(long nativePtr);
+ @CriticalNative
+ private static native long nativeGetDownTimeNanos(long nativePtr);
+ @CriticalNative
+ private static native void nativeSetDownTimeNanos(long nativePtr, long downTime);
+
+ @CriticalNative
+ private static native int nativeGetPointerCount(long nativePtr);
+ @CriticalNative
+ private static native int nativeFindPointerIndex(long nativePtr, int pointerId);
+
+ @CriticalNative
+ private static native int nativeGetHistorySize(long nativePtr);
+
+ @CriticalNative
+ private static native void nativeScale(long nativePtr, float scale);
+ @CriticalNative
+ private static native void nativeTransform(long nativePtr, long matrix);
+
private MotionEvent() {
}
@@ -1906,6 +1955,20 @@
: flags & ~FLAG_TARGET_ACCESSIBILITY_FOCUS);
}
+ /** @hide */
+ public final boolean isHoverExitPending() {
+ final int flags = getFlags();
+ return (flags & FLAG_HOVER_EXIT_PENDING) != 0;
+ }
+
+ /** @hide */
+ public void setHoverExitPending(boolean hoverExitPending) {
+ final int flags = getFlags();
+ nativeSetFlags(mNativePtr, hoverExitPending
+ ? flags | FLAG_HOVER_EXIT_PENDING
+ : flags & ~FLAG_HOVER_EXIT_PENDING);
+ }
+
/**
* Returns the time (in ms) when the user originally pressed down to start
* a stream of position events.
@@ -2065,7 +2128,7 @@
public final int getPointerCount() {
return nativeGetPointerCount(mNativePtr);
}
-
+
/**
* Return the pointer identifier associated with a particular pointer
* data index in this event. The identifier tells you the actual pointer
@@ -2891,7 +2954,7 @@
throw new IllegalArgumentException("matrix must not be null");
}
- nativeTransform(mNativePtr, matrix);
+ nativeTransform(mNativePtr, matrix.native_instance);
}
/**
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index fc79f53..998fd01 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -17,9 +17,6 @@
package android.view;
import android.annotation.NonNull;
-import android.util.SparseArray;
-import com.android.internal.util.XmlUtils;
-
import android.annotation.XmlRes;
import android.content.Context;
import android.content.res.Resources;
@@ -32,6 +29,9 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.util.XmlUtils;
/**
* Represents an icon that can be used as a mouse pointer.
diff --git a/core/java/android/view/RemotableViewMethod.java b/core/java/android/view/RemotableViewMethod.java
index e5cae84..03aed9a 100644
--- a/core/java/android/view/RemotableViewMethod.java
+++ b/core/java/android/view/RemotableViewMethod.java
@@ -36,6 +36,3 @@
*/
String asyncImpl() default "";
}
-
-
-
diff --git a/core/java/android/view/RenderNodeAnimatorSetHelper.java b/core/java/android/view/RenderNodeAnimatorSetHelper.java
index ba592d29..e1ef059 100644
--- a/core/java/android/view/RenderNodeAnimatorSetHelper.java
+++ b/core/java/android/view/RenderNodeAnimatorSetHelper.java
@@ -16,6 +16,7 @@
package android.view;
import android.animation.TimeInterpolator;
+
import com.android.internal.view.animation.FallbackLUTInterpolator;
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
diff --git a/core/java/android/view/RoundScrollbarRenderer.java b/core/java/android/view/RoundScrollbarRenderer.java
index b77be8c..4c555ae 100644
--- a/core/java/android/view/RoundScrollbarRenderer.java
+++ b/core/java/android/view/RoundScrollbarRenderer.java
@@ -19,8 +19,8 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
-import android.graphics.RectF;
import android.graphics.Rect;
+import android.graphics.RectF;
/**
* Helper class for drawing round scroll bars on round Wear devices.
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 7cd161c..9787494 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -20,7 +20,6 @@
import android.content.res.Resources;
import android.os.Build;
import android.os.Handler;
-import android.os.SystemClock;
/**
* Detects scaling transformation gestures using the supplied {@link MotionEvent}s.
diff --git a/core/java/android/view/SearchEvent.java b/core/java/android/view/SearchEvent.java
index 643cc3e..72b5e4b 100644
--- a/core/java/android/view/SearchEvent.java
+++ b/core/java/android/view/SearchEvent.java
@@ -16,8 +16,6 @@
package android.view;
-import android.view.InputDevice;
-
/**
* Class that contains information about an event that triggers a search.
*/
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 22e68a3..ecd5e3b 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -26,11 +26,11 @@
import android.os.Parcelable;
import android.util.Log;
+import dalvik.system.CloseGuard;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import dalvik.system.CloseGuard;
-
/**
* Handle onto a raw buffer that is being managed by the screen compositor.
*
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6456826..b87250e 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -16,7 +16,6 @@
package android.view;
-import dalvik.system.CloseGuard;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.Region;
@@ -24,6 +23,8 @@
import android.util.Log;
import android.view.Surface.OutOfResourcesException;
+import dalvik.system.CloseGuard;
+
/**
* SurfaceControl
* @hide
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 2a2f659..80f447e 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,11 +16,9 @@
package android.view;
-import com.android.internal.view.BaseIWindow;
-
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.CompatibilityInfo.Translator;
+import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
@@ -28,12 +26,14 @@
import android.graphics.Region;
import android.os.Handler;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.os.ParcelFileDescriptor;
import android.util.AttributeSet;
import android.util.Log;
+import com.android.internal.view.BaseIWindow;
+
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;
@@ -600,7 +600,9 @@
// surfaceDestroyed and surfaceCreated, we force a disconnect,
// so the next connect will always work if we end up reusing
// the surface.
- mSurface.forceScopedDisconnect();
+ if (mSurface.isValid()) {
+ mSurface.forceScopedDisconnect();
+ }
}
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index ce390a2..0bb84cc 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -16,9 +16,9 @@
package android.view;
-import android.app.ActivityManagerNative;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -916,7 +916,6 @@
mInitialized = true;
initSched(context, renderProxy);
initGraphicsStats(context, renderProxy);
- initAssetAtlas(context, renderProxy);
}
private static void initSched(Context context, long renderProxy) {
@@ -944,32 +943,6 @@
Log.w(LOG_TAG, "Could not acquire gfx stats buffer", t);
}
}
-
- private static void initAssetAtlas(Context context, long renderProxy) {
- IBinder binder = ServiceManager.getService("assetatlas");
- if (binder == null) return;
-
- IAssetAtlas atlas = IAssetAtlas.Stub.asInterface(binder);
- try {
- if (atlas.isCompatible(android.os.Process.myPpid())) {
- GraphicBuffer buffer = atlas.getBuffer();
- if (buffer != null) {
- long[] map = atlas.getMap();
- if (map != null) {
- nSetAtlas(renderProxy, buffer, map);
- }
- // If IAssetAtlas is not the same class as the IBinder
- // we are using a remote service and we can safely
- // destroy the graphic buffer
- if (atlas.getClass() != binder.getClass()) {
- buffer.destroy();
- }
- }
- }
- } catch (RemoteException e) {
- Log.w(LOG_TAG, "Could not acquire atlas", e);
- }
- }
}
void addFrameMetricsObserver(FrameMetricsObserver observer) {
@@ -984,7 +957,6 @@
static native void setupShadersDiskCache(String cacheFile);
- private static native void nSetAtlas(long nativeProxy, GraphicBuffer buffer, long[] map);
private static native void nSetProcessStatsBuffer(long nativeProxy, int fd);
private static native int nGetRenderThreadTid(long nativeProxy);
diff --git a/core/java/android/view/TouchDelegate.java b/core/java/android/view/TouchDelegate.java
index 27b49db..cf36f43 100644
--- a/core/java/android/view/TouchDelegate.java
+++ b/core/java/android/view/TouchDelegate.java
@@ -17,9 +17,6 @@
package android.view;
import android.graphics.Rect;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewConfiguration;
/**
* Helper class to handle situations where you want a view to have a larger touch area than its
@@ -33,24 +30,24 @@
* </p>
*/
public class TouchDelegate {
-
+
/**
- * View that should receive forwarded touch events
+ * View that should receive forwarded touch events
*/
private View mDelegateView;
-
+
/**
* Bounds in local coordinates of the containing view that should be mapped to the delegate
* view. This rect is used for initial hit testing.
*/
private Rect mBounds;
-
+
/**
* mBounds inflated to include some slop. This rect is to track whether the motion events
* should be considered to be be within the delegate view.
*/
private Rect mSlopBounds;
-
+
/**
* True if the delegate had been targeted on a down event (intersected mBounds).
*/
@@ -82,7 +79,7 @@
/**
* Constructor
- *
+ *
* @param bounds Bounds in local coordinates of the containing view that should be mapped to
* the delegate view
* @param delegateView The view that should receive motion events
@@ -99,7 +96,7 @@
/**
* Will forward touch events to the delegate view if the event is within the bounds
* specified in the constructor.
- *
+ *
* @param event The touch event to forward
* @return True if the event was forwarded to the delegate, false otherwise.
*/
@@ -136,7 +133,7 @@
}
if (sendToDelegate) {
final View delegateView = mDelegateView;
-
+
if (hit) {
// Offset event coordinates to be inside the target view
event.setLocation(delegateView.getWidth() / 2, delegateView.getHeight() / 2);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d060aac..20876a9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,6 +16,14 @@
package android.view;
+import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+import static android.os.Build.VERSION_CODES.KITKAT;
+import static android.os.Build.VERSION_CODES.M;
+import static android.os.Build.VERSION_CODES.N;
+
+import static java.lang.Math.max;
+
import android.animation.AnimatorInflater;
import android.animation.StateListAnimator;
import android.annotation.CallSuper;
@@ -40,6 +48,7 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Interpolator;
import android.graphics.LinearGradient;
@@ -79,11 +88,11 @@
import android.util.StateSet;
import android.util.SuperNotCalledException;
import android.util.TypedValue;
-import android.view.ContextMenu.ContextMenuInfo;
import android.view.AccessibilityIterators.CharacterTextSegmentIterator;
import android.view.AccessibilityIterators.ParagraphTextSegmentIterator;
import android.view.AccessibilityIterators.TextSegmentIterator;
import android.view.AccessibilityIterators.WordTextSegmentIterator;
+import android.view.ContextMenu.ContextMenuInfo;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityEventSource;
import android.view.accessibility.AccessibilityManager;
@@ -99,17 +108,15 @@
import android.widget.Checkable;
import android.widget.FrameLayout;
import android.widget.ScrollBarDrawable;
-import static android.os.Build.VERSION_CODES.*;
-import static java.lang.Math.max;
import com.android.internal.R;
import com.android.internal.util.Predicate;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.widget.ScrollBarUtils;
+
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
-import java.lang.NullPointerException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
@@ -757,6 +764,9 @@
AccessibilityEventSource {
private static final boolean DBG = false;
+ /** @hide */
+ public static boolean DEBUG_DRAW = false;
+
/**
* The logging tag used by this class with android.util.Log.
*/
@@ -1184,6 +1194,8 @@
*/
static final int PARENT_SAVE_DISABLED_MASK = 0x20000000;
+ private static Paint sDebugPaint;
+
/** @hide */
@IntDef(flag = true,
value = {
@@ -1655,6 +1667,10 @@
| AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
| AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;
+ static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255);
+
+ static final int DEBUG_CORNERS_SIZE_DIP = 8;
+
/**
* Temporary Rect currently for use in setBackground(). This will probably
* be extended in the future to hold our own class with more than just
@@ -4743,6 +4759,10 @@
mRenderNode = RenderNode.create(getClass().getName(), this);
}
+ final boolean debugDraw() {
+ return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout;
+ }
+
private static SparseArray<String> getAttributeMap() {
if (mAttributeMap == null) {
mAttributeMap = new SparseArray<>();
@@ -16137,6 +16157,9 @@
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().draw(canvas);
}
+ if (debugDraw()) {
+ debugDrawFocus(canvas);
+ }
} else {
draw(canvas);
}
@@ -17115,6 +17138,44 @@
return more;
}
+ static Paint getDebugPaint() {
+ if (sDebugPaint == null) {
+ sDebugPaint = new Paint();
+ sDebugPaint.setAntiAlias(false);
+ }
+ return sDebugPaint;
+ }
+
+ final int dipsToPixels(int dips) {
+ float scale = getContext().getResources().getDisplayMetrics().density;
+ return (int) (dips * scale + 0.5f);
+ }
+
+ final private void debugDrawFocus(Canvas canvas) {
+ if (isFocused()) {
+ final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP);
+ final int l = mScrollX;
+ final int r = l + mRight - mLeft;
+ final int t = mScrollY;
+ final int b = t + mBottom - mTop;
+
+ final Paint paint = getDebugPaint();
+ paint.setColor(DEBUG_CORNERS_COLOR);
+
+ // Draw squares in corners.
+ paint.setStyle(Paint.Style.FILL);
+ canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint);
+ canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint);
+ canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint);
+ canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint);
+
+ // Draw big X across the view.
+ paint.setStyle(Paint.Style.STROKE);
+ canvas.drawLine(l, t, r, b, paint);
+ canvas.drawLine(l, b, r, t, paint);
+ }
+ }
+
/**
* Manually render this view (and all of its children) to the given Canvas.
* The view must have already done a full layout before this function is
@@ -17169,6 +17230,10 @@
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
+ if (debugDraw()) {
+ debugDrawFocus(canvas);
+ }
+
// we're done...
return;
}
@@ -17317,6 +17382,10 @@
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
+
+ if (debugDraw()) {
+ debugDrawFocus(canvas);
+ }
}
/**
@@ -20661,7 +20730,9 @@
return false;
}
- data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0);
+ if (data != null) {
+ data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0);
+ }
boolean okay = false;
@@ -20830,6 +20901,9 @@
* {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or
* {@code false} if it didn't.
* </p>
+ * <p>
+ * For all other events, the return value is ignored.
+ * </p>
*/
public boolean onDragEvent(DragEvent event) {
return false;
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index e1ff0d6..047a515 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -51,8 +51,8 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
-import java.util.concurrent.TimeoutException;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
/**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1b3f6ff..e39cb96 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -16,10 +16,13 @@
package android.view;
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+
import android.animation.LayoutTransition;
import android.annotation.IdRes;
import android.annotation.NonNull;
import android.annotation.UiThread;
+import android.content.ClipData;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -61,8 +64,6 @@
import java.util.List;
import java.util.Map;
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
-
/**
* <p>
* A <code>ViewGroup</code> is a special view that can contain other views
@@ -115,8 +116,6 @@
private static final String TAG = "ViewGroup";
private static final boolean DBG = false;
- /** @hide */
- public static boolean DEBUG_DRAW = false;
/**
* Views which have been hidden or removed which need to be animated on
@@ -475,7 +474,6 @@
private static final int ARRAY_INITIAL_CAPACITY = 12;
private static final int ARRAY_CAPACITY_INCREMENT = 12;
- private static Paint sDebugPaint;
private static float[] sDebugLines;
// Used to draw cached views
@@ -585,10 +583,6 @@
initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
}
- private boolean debugDraw() {
- return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout;
- }
-
private void initViewGroup() {
// ViewGroup doesn't draw by default
if (!debugDraw()) {
@@ -1380,6 +1374,7 @@
boolean retval = false;
final float tx = event.mX;
final float ty = event.mY;
+ final ClipData td = event.mClipData;
// Dispatch down the view hierarchy
final PointF localPoint = getLocalPoint();
@@ -1465,6 +1460,7 @@
// ACTION_DRAG_EXITED.
event.mX = 0;
event.mY = 0;
+ event.mClipData = null;
if (mCurrentDragChild != null) {
event.mAction = DragEvent.ACTION_DRAG_EXITED;
@@ -1479,6 +1475,7 @@
event.mAction = action;
event.mX = tx;
event.mY = ty;
+ event.mClipData = td;
}
mCurrentDragChild = target;
}
@@ -1861,8 +1858,11 @@
// Synthesize an exit from a move or enter.
// Ignore the result because hover focus has moved to a different view.
if (action == MotionEvent.ACTION_HOVER_MOVE) {
+ final boolean hoverExitPending = event.isHoverExitPending();
+ event.setHoverExitPending(true);
dispatchTransformedGenericPointerEvent(
event, child); // move
+ event.setHoverExitPending(hoverExitPending);
}
eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
@@ -1876,8 +1876,10 @@
firstOldHoverTarget = nextOldHoverTarget;
}
- // Send events to the view group itself if no children have handled it.
- boolean newHoveredSelf = !handled;
+ // Send events to the view group itself if no children have handled it and the view group
+ // itself is not currently being hover-exited.
+ boolean newHoveredSelf = !handled &&
+ (action != MotionEvent.ACTION_HOVER_EXIT) && !event.isHoverExitPending();
if (newHoveredSelf == mHoveredSelf) {
if (newHoveredSelf) {
// Send event to the view group as before.
@@ -3371,11 +3373,6 @@
fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
}
- private int dipsToPixels(int dips) {
- float scale = getContext().getResources().getDisplayMetrics().density;
- return (int) (dips * scale + 0.5f);
- }
-
private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
int lineLength, int lineWidth) {
drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
@@ -3444,10 +3441,10 @@
// Draw clip bounds
{
- paint.setColor(Color.rgb(63, 127, 255));
+ paint.setColor(DEBUG_CORNERS_COLOR);
paint.setStyle(Paint.Style.FILL);
- int lineLength = dipsToPixels(8);
+ int lineLength = dipsToPixels(DEBUG_CORNERS_SIZE_DIP);
int lineWidth = dipsToPixels(1);
for (int i = 0; i < getChildCount(); i++) {
View c = getChildAt(i);
@@ -7922,14 +7919,6 @@
}
}
- private static Paint getDebugPaint() {
- if (sDebugPaint == null) {
- sDebugPaint = new Paint();
- sDebugPaint.setAntiAlias(false);
- }
- return sDebugPaint;
- }
-
private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
if (sDebugLines== null) {
// TODO: This won't work with multiple UI threads in a single process
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index c604234..6c84b63 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -17,8 +17,9 @@
package android.view;
import android.animation.Animator;
-import android.animation.ValueAnimator;
import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
@@ -42,7 +43,7 @@
* <p>This class is not constructed by the caller, but rather by the View whose properties
* it will animate. Calls to {@link android.view.View#animate()} will return a reference
* to the appropriate ViewPropertyAnimator object for that View.</p>
- *
+ *
*/
public class ViewPropertyAnimator {
@@ -332,7 +333,7 @@
* Sets the interpolator for the underlying animator that animates the requested properties.
* By default, the animator uses the default interpolator for ValueAnimator. Calling this method
* will cause the declared object to be used instead.
- *
+ *
* @param interpolator The TimeInterpolator to be used for ensuing property animations. A value
* of <code>null</code> will result in linear interpolation.
* @return This object, allowing calls to methods in this class to be chained.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ec29abf..87b330d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -29,6 +29,7 @@
import android.annotation.NonNull;
import android.app.ActivityManagerNative;
import android.app.ResourcesManager;
+import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ComponentCallbacks;
import android.content.Context;
@@ -5551,8 +5552,8 @@
// Remember who the current drag target is pre-dispatch
final View prevDragView = mCurrentDragView;
- if (what == DragEvent.ACTION_DROP) {
- event.getClipData().prepareToEnterProcess();
+ if (what == DragEvent.ACTION_DROP && event.mClipData != null) {
+ event.mClipData.prepareToEnterProcess();
}
// Now dispatch the drag/drop event
@@ -5657,9 +5658,11 @@
final float tx = event.mX;
final float ty = event.mY;
final int action = event.mAction;
+ final ClipData td = event.mClipData;
// Position should not be available for ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED.
event.mX = 0;
event.mY = 0;
+ event.mClipData = null;
if (mCurrentDragView != null) {
event.mAction = DragEvent.ACTION_DRAG_EXITED;
@@ -5674,6 +5677,7 @@
event.mAction = action;
event.mX = tx;
event.mY = ty;
+ event.mClipData = td;
}
mCurrentDragView = newDragTarget;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index b046e2d..2c13831 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
@@ -24,7 +26,6 @@
import android.annotation.Nullable;
import android.annotation.StyleRes;
import android.annotation.SystemApi;
-import android.app.ActivityManagerNative;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -44,8 +45,6 @@
import android.transition.TransitionManager;
import android.view.accessibility.AccessibilityEvent;
-import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-
import java.util.List;
/**
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 395f738..abb3051 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -64,6 +64,13 @@
/** @hide */
int DOCKED_BOTTOM = 4;
+ /** @hide */
+ final static String INPUT_CONSUMER_PIP = "pip_input_consumer";
+ /** @hide */
+ final static String INPUT_CONSUMER_NAVIGATION = "nav_input_consumer";
+ /** @hide */
+ final static String INPUT_CONSUMER_WALLPAPER = "wallpaper_input_consumer";
+
/**
* Exception that is thrown when trying to add view whose
* {@link LayoutParams} {@link LayoutParams#token}
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index dd4e096..c1b8f04 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -23,7 +23,6 @@
import android.os.RemoteException;
import com.android.internal.os.IResultReceiver;
-import com.android.internal.R;
import java.util.List;
@@ -38,11 +37,11 @@
* Additional window manager specific layout parameters are defined for
* control over how windows are displayed. It also implements the {@link WindowManager}
* interface, allowing you to control the displays attached to the device.
- *
+ *
* <p>Applications will not normally use WindowManager directly, instead relying
* on the higher-level facilities in {@link android.app.Activity} and
* {@link android.app.Dialog}.
- *
+ *
* <p>Even for low-level window manager access, it is almost never correct to use
* this class. For example, {@link android.app.Activity#getWindowManager}
* provides a window manager for adding windows that are associated with that
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index da361c1..a6be493 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -25,12 +25,12 @@
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.view.animation.Animation;
+
import com.android.internal.policy.IShortcutService;
import java.io.PrintWriter;
@@ -458,7 +458,7 @@
/**
* Add a input consumer which will consume all input events going to any window below it.
*/
- public InputConsumer addInputConsumer(Looper looper,
+ public InputConsumer createInputConsumer(Looper looper, String name,
InputEventReceiver.Factory inputEventReceiverFactory);
/**
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 44f6fac..8084195 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -21,7 +21,6 @@
import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.Handler;
@@ -92,9 +91,6 @@
/** @hide */
public static final int AUTOCLICK_DELAY_DEFAULT = 600;
- /** @hide */
- public static final int MAX_A11Y_EVENTS_PER_SERVICE_CALL = 20;
-
static final Object sInstanceSync = new Object();
private static AccessibilityManager sInstance;
@@ -103,8 +99,6 @@
private IAccessibilityManager mService;
- private EventDispatchThread mEventDispatchThread;
-
final int mUserId;
final Handler mHandler;
@@ -303,32 +297,44 @@
* their descendants.
*/
public void sendAccessibilityEvent(AccessibilityEvent event) {
- if (!isEnabled()) {
- Looper myLooper = Looper.myLooper();
- if (myLooper == Looper.getMainLooper()) {
- throw new IllegalStateException(
- "Accessibility off. Did you forget to check that?");
- } else {
- // If we're not running on the thread with the main looper, it's possible for
- // the state of accessibility to change between checking isEnabled and
- // calling this method. So just log the error rather than throwing the
- // exception.
- Log.e(LOG_TAG, "AccessibilityEvent sent with accessibility disabled");
+ final IAccessibilityManager service;
+ final int userId;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
return;
}
- }
- event.setEventTime(SystemClock.uptimeMillis());
-
- getEventDispatchThread().scheduleEvent(event);
- }
-
- private EventDispatchThread getEventDispatchThread() {
- synchronized (mLock) {
- if (mEventDispatchThread == null) {
- mEventDispatchThread = new EventDispatchThread(mService, mUserId);
- mEventDispatchThread.start();
+ if (!mIsEnabled) {
+ Looper myLooper = Looper.myLooper();
+ if (myLooper == Looper.getMainLooper()) {
+ throw new IllegalStateException(
+ "Accessibility off. Did you forget to check that?");
+ } else {
+ // If we're not running on the thread with the main looper, it's possible for
+ // the state of accessibility to change between checking isEnabled and
+ // calling this method. So just log the error rather than throwing the
+ // exception.
+ Log.e(LOG_TAG, "AccessibilityEvent sent with accessibility disabled");
+ return;
+ }
}
- return mEventDispatchThread;
+ userId = mUserId;
+ }
+ try {
+ event.setEventTime(SystemClock.uptimeMillis());
+ // it is possible that this manager is in the same process as the service but
+ // client using it is called through Binder from another process. Example: MMS
+ // app adds a SMS notification and the NotificationManagerService calls this method
+ long identityToken = Binder.clearCallingIdentity();
+ service.sendAccessibilityEvent(event, userId);
+ Binder.restoreCallingIdentity(identityToken);
+ if (DEBUG) {
+ Log.i(LOG_TAG, event + " sent");
+ }
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error during sending " + event + " ", re);
+ } finally {
+ event.recycle();
}
}
@@ -713,99 +719,4 @@
}
}
}
-
- private static class EventDispatchThread extends Thread {
- // Second lock used to keep UI thread performant. Never try to grab mLock when holding
- // this one, or the UI thread will block in send AccessibilityEvent.
- private final Object mEventQueueLock = new Object();
-
- // Two lists to hold events. The app thread fills one while we empty the other.
- private final ArrayList<AccessibilityEvent> mEventLists0 =
- new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL);
- private final ArrayList<AccessibilityEvent> mEventLists1 =
- new ArrayList<>(MAX_A11Y_EVENTS_PER_SERVICE_CALL);
-
- private boolean mPingPongListToggle;
-
- private final IAccessibilityManager mService;
-
- private final int mUserId;
-
- EventDispatchThread(IAccessibilityManager service, int userId) {
- mService = service;
- mUserId = userId;
- }
-
- @Override
- public void run() {
- while (true) {
- ArrayList<AccessibilityEvent> listBeingDrained;
- synchronized (mEventQueueLock) {
- ArrayList<AccessibilityEvent> listBeingFilled = getListBeingFilledLocked();
- if (listBeingFilled.isEmpty()) {
- try {
- mEventQueueLock.wait();
- } catch (InterruptedException e) {
- // Treat as a notify
- }
- }
- // Swap buffers
- mPingPongListToggle = !mPingPongListToggle;
- listBeingDrained = listBeingFilled;
- }
- dispatchEvents(listBeingDrained);
- }
- }
-
- public void scheduleEvent(AccessibilityEvent event) {
- synchronized (mEventQueueLock) {
- getListBeingFilledLocked().add(event);
- mEventQueueLock.notifyAll();
- }
- }
-
- private ArrayList<AccessibilityEvent> getListBeingFilledLocked() {
- return (mPingPongListToggle) ? mEventLists0 : mEventLists1;
- }
-
- private void dispatchEvents(ArrayList<AccessibilityEvent> events) {
- int eventListCapacityLowerBound = events.size();
- while (events.size() > 0) {
- // We don't want to consume extra memory if an app sends a lot of events in a
- // one-off event. Cap the list length at double the max events per call.
- // We'll end up with extra GC for apps that send huge numbers of events, but
- // sending that many events will lead to bad performance in any case.
- if ((eventListCapacityLowerBound > 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL)
- && (events.size() <= 2 * MAX_A11Y_EVENTS_PER_SERVICE_CALL)) {
- events.trimToSize();
- eventListCapacityLowerBound = events.size();
- }
- // We only expect this loop to run once, as the app shouldn't be sending
- // huge numbers of events.
- // The clear in the called method will remove the sent events
- dispatchOneBatchOfEvents(events.subList(0,
- Math.min(events.size(), MAX_A11Y_EVENTS_PER_SERVICE_CALL)));
- }
- }
-
- private void dispatchOneBatchOfEvents(List<AccessibilityEvent> events) {
- if (events.isEmpty()) {
- return;
- }
- long identityToken = Binder.clearCallingIdentity();
- try {
- mService.sendAccessibilityEvents(new ParceledListSlice<>(events),
- mUserId);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error sending multiple events");
- }
- Binder.restoreCallingIdentity(identityToken);
- if (DEBUG) {
- Log.i(LOG_TAG, events.size() + " events sent");
- }
- for (int i = events.size() - 1; i >= 0; i--) {
- events.remove(i).recycle();
- }
- }
- }
}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index aa9cb39..71e77c4 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -21,7 +21,6 @@
import android.accessibilityservice.IAccessibilityServiceConnection;
import android.accessibilityservice.IAccessibilityServiceClient;
import android.content.ComponentName;
-import android.content.pm.ParceledListSlice;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -30,7 +29,7 @@
/**
* Interface implemented by the AccessibilityManagerService called by
- * the AccessibilityMasngers.
+ * the AccessibilityManagers.
*
* @hide
*/
@@ -40,8 +39,6 @@
void sendAccessibilityEvent(in AccessibilityEvent uiEvent, int userId);
- void sendAccessibilityEvents(in ParceledListSlice events, int userId);
-
List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId);
List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType, int userId);
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index d89c172..474db12 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -26,6 +26,7 @@
import android.os.SystemProperties;
import android.util.AttributeSet;
import android.util.TypedValue;
+
import dalvik.system.CloseGuard;
/**
@@ -80,13 +81,13 @@
* order.
*/
public static final int ZORDER_NORMAL = 0;
-
+
/**
* Requests that the content being animated be forced on top of all other
* content for the duration of the animation.
*/
public static final int ZORDER_TOP = 1;
-
+
/**
* Requests that the content being animated be forced under all other
* content for the duration of the animation.
@@ -138,7 +139,7 @@
/**
* Indicates whether fillBefore should be taken into account.
*/
- boolean mFillEnabled = false;
+ boolean mFillEnabled = false;
/**
* The time in milliseconds at which the animation must start;
@@ -240,7 +241,7 @@
setDuration((long) a.getInt(com.android.internal.R.styleable.Animation_duration, 0));
setStartOffset((long) a.getInt(com.android.internal.R.styleable.Animation_startOffset, 0));
-
+
setFillEnabled(a.getBoolean(com.android.internal.R.styleable.Animation_fillEnabled, mFillEnabled));
setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore));
setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter));
@@ -249,7 +250,7 @@
setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART));
setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL));
-
+
setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));
setDetachWallpaper(a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));
@@ -294,13 +295,13 @@
/**
* Cancel the animation. Cancelling an animation invokes the animation
* listener, if set, to notify the end of the animation.
- *
+ *
* If you cancel an animation manually, you must call {@link #reset()}
* before starting the animation again.
- *
- * @see #reset()
- * @see #start()
- * @see #startNow()
+ *
+ * @see #reset()
+ * @see #start()
+ * @see #startNow()
*/
public void cancel() {
if (mStarted && !mEnded) {
@@ -356,7 +357,7 @@
/**
* Sets the handler used to invoke listeners.
- *
+ *
* @hide
*/
public void setListenerHandler(Handler handler) {
@@ -424,7 +425,7 @@
/**
* How long this animation should last. The duration cannot be negative.
- *
+ *
* @param durationMillis Duration in milliseconds
*
* @throws java.lang.IllegalArgumentException if the duration is < 0
@@ -443,7 +444,7 @@
* than <var>durationMillis</var>. In addition to adjusting the duration
* itself, this ensures that the repeat count also will not make it run
* longer than the given time.
- *
+ *
* @param durationMillis The maximum duration the animation is allowed
* to run.
*/
@@ -455,7 +456,7 @@
mRepeatCount = 0;
return;
}
-
+
long dur = mDuration + mStartOffset;
if (dur > durationMillis) {
mDuration = durationMillis-mStartOffset;
@@ -480,7 +481,7 @@
}
}
}
-
+
/**
* How much to scale the duration by.
*
@@ -528,7 +529,7 @@
/**
* Defines what this animation should do when it reaches the end. This
* setting is applied only when the repeat count is either greater than
- * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}.
+ * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}.
*
* @param repeatMode {@link #RESTART} or {@link #REVERSE}
* @attr ref android.R.styleable#Animation_repeatMode
@@ -606,7 +607,7 @@
* @param fillAfter true if the animation should apply its transformation after it ends
* @attr ref android.R.styleable#Animation_fillAfter
*
- * @see #setFillEnabled(boolean)
+ * @see #setFillEnabled(boolean)
*/
public void setFillAfter(boolean fillAfter) {
mFillAfter = fillAfter;
@@ -614,7 +615,7 @@
/**
* Set the Z ordering mode to use while running the animation.
- *
+ *
* @param zAdjustment The desired mode, one of {@link #ZORDER_NORMAL},
* {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}.
* @attr ref android.R.styleable#Animation_zAdjustment
@@ -622,7 +623,7 @@
public void setZAdjustment(int zAdjustment) {
mZAdjustment = zAdjustment;
}
-
+
/**
* Set background behind animation.
*
@@ -634,11 +635,11 @@
}
/**
- * The scale factor is set by the call to <code>getTransformation</code>. Overrides of
+ * The scale factor is set by the call to <code>getTransformation</code>. Overrides of
* {@link #getTransformation(long, Transformation, float)} will get this value
* directly. Overrides of {@link #applyTransformation(float, Transformation)} can
* call this method to get the value.
- *
+ *
* @return float The scale factor that should be applied to pre-scaled values in
* an Animation such as the pivot points in {@link ScaleAnimation} and {@link RotateAnimation}.
*/
@@ -748,7 +749,7 @@
/**
* Returns the Z ordering mode to use while running the animation as
* previously set by {@link #setZAdjustment}.
- *
+ *
* @return Returns one of {@link #ZORDER_NORMAL},
* {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}.
* @attr ref android.R.styleable#Animation_zAdjustment
@@ -827,7 +828,7 @@
public long computeDurationHint() {
return (getStartOffset() + getDuration()) * (getRepeatCount() + 1);
}
-
+
/**
* Gets the transformation to apply at a specified point in time. Implementations of this
* method should always replace the specified Transformation or document they are doing
@@ -975,7 +976,7 @@
* their transforms given an interpolation value. Implementations of this
* method should always replace the specified Transformation or document
* they are doing otherwise.
- *
+ *
* @param interpolatedTime The value of the normalized time (0.0 to 1.0)
* after it has been run through the interpolation function.
* @param t The Transformation object to fill in with the current
@@ -1015,7 +1016,7 @@
* @param bottom
* @param invalidate
* @param transformation
- *
+ *
* @hide
*/
public void getInvalidateRegion(int left, int top, int right, int bottom,
@@ -1072,7 +1073,7 @@
/**
* Return true if this animation changes the view's alpha property.
- *
+ *
* @hide
*/
public boolean hasAlpha() {
diff --git a/core/java/android/view/animation/AnimationSet.java b/core/java/android/view/animation/AnimationSet.java
index 71c7450..09d4dfc 100644
--- a/core/java/android/view/animation/AnimationSet.java
+++ b/core/java/android/view/animation/AnimationSet.java
@@ -18,17 +18,17 @@
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.RectF;
import android.os.Build;
import android.util.AttributeSet;
-import android.graphics.RectF;
import java.util.ArrayList;
import java.util.List;
/**
* Represents a group of Animations that should be played together.
- * The transformation of each individual animation are composed
- * together into a single transform.
+ * The transformation of each individual animation are composed
+ * together into a single transform.
* If AnimationSet sets any properties that its children also set
* (for example, duration or fillBefore), the values of AnimationSet
* override the child values.
@@ -72,17 +72,17 @@
private long[] mStoredOffsets;
/**
- * Constructor used when an AnimationSet is loaded from a resource.
- *
+ * Constructor used when an AnimationSet is loaded from a resource.
+ *
* @param context Application context to use
* @param attrs Attribute set from which to read values
*/
public AnimationSet(Context context, AttributeSet attrs) {
super(context, attrs);
-
+
TypedArray a =
context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AnimationSet);
-
+
setFlag(PROPERTY_SHARE_INTERPOLATOR_MASK,
a.getBoolean(com.android.internal.R.styleable.AnimationSet_shareInterpolator, true));
init();
@@ -108,11 +108,11 @@
a.recycle();
}
-
-
+
+
/**
* Constructor to use when building an AnimationSet from code
- *
+ *
* @param shareInterpolator Pass true if all of the animations in this set
* should use the interpolator associated with this AnimationSet.
* Pass false if each animation should use its own interpolator.
@@ -244,10 +244,10 @@
mDirty = true;
}
-
+
/**
* Sets the start time of this animation and all child animations
- *
+ *
* @see android.view.animation.Animation#setStartTime(long)
*/
@Override
@@ -289,11 +289,11 @@
animations.get(i).restrictDuration(durationMillis);
}
}
-
+
/**
- * The duration of an AnimationSet is defined to be the
+ * The duration of an AnimationSet is defined to be the
* duration of the longest child animation.
- *
+ *
* @see android.view.animation.Animation#getDuration()
*/
@Override
@@ -317,7 +317,7 @@
/**
* The duration hint of an animation set is the maximum of the duration
* hints of all of its component animations.
- *
+ *
* @see android.view.animation.Animation#computeDurationHint
*/
public long computeDurationHint() {
@@ -362,7 +362,7 @@
/**
* The transformation of an animation set is the concatenation of all of its
* component animations.
- *
+ *
* @see android.view.animation.Animation#getTransformation
*/
@Override
@@ -404,7 +404,7 @@
return more;
}
-
+
/**
* @see android.view.animation.Animation#scaleCurrentDuration(float)
*/
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 351b6db..f5c3613 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -16,19 +16,19 @@
package android.view.animation;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.annotation.AnimRes;
import android.annotation.InterpolatorRes;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.Theme;
import android.content.res.XmlResourceParser;
-import android.content.res.Resources.NotFoundException;
+import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Xml;
-import android.os.SystemClock;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java
index fb66c31..7a837c3 100644
--- a/core/java/android/view/animation/AnticipateInterpolator.java
+++ b/core/java/android/view/animation/AnticipateInterpolator.java
@@ -18,8 +18,8 @@
import android.content.Context;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import com.android.internal.R;
diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
index 1af72da..9a75134 100644
--- a/core/java/android/view/animation/AnticipateOvershootInterpolator.java
+++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java
@@ -16,6 +16,10 @@
package android.view.animation;
+import static com.android.internal.R.styleable.AnticipateOvershootInterpolator;
+import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_extraTension;
+import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_tension;
+
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
@@ -26,10 +30,6 @@
import com.android.internal.view.animation.NativeInterpolatorFactory;
import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
-import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_extraTension;
-import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_tension;
-import static com.android.internal.R.styleable.AnticipateOvershootInterpolator;
-
/**
* An interpolator where the change starts backward then flings forward and overshoots
* the target value and finally goes back to the final value.
diff --git a/core/java/android/view/animation/CycleInterpolator.java b/core/java/android/view/animation/CycleInterpolator.java
index 663c109..72d64a1 100644
--- a/core/java/android/view/animation/CycleInterpolator.java
+++ b/core/java/android/view/animation/CycleInterpolator.java
@@ -18,8 +18,8 @@
import android.content.Context;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import com.android.internal.R;
diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java
index f426f60..f89743c 100644
--- a/core/java/android/view/animation/DecelerateInterpolator.java
+++ b/core/java/android/view/animation/DecelerateInterpolator.java
@@ -18,8 +18,8 @@
import android.content.Context;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
import android.util.AttributeSet;
import com.android.internal.R;
diff --git a/core/java/android/view/animation/GridLayoutAnimationController.java b/core/java/android/view/animation/GridLayoutAnimationController.java
index 9161d8b..0f189ae 100644
--- a/core/java/android/view/animation/GridLayoutAnimationController.java
+++ b/core/java/android/view/animation/GridLayoutAnimationController.java
@@ -16,11 +16,11 @@
package android.view.animation;
-import android.view.View;
-import android.view.ViewGroup;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
import java.util.Random;
@@ -43,7 +43,7 @@
*
* @see LayoutAnimationController
* @see android.widget.GridView
- *
+ *
* @attr ref android.R.styleable#GridLayoutAnimation_columnDelay
* @attr ref android.R.styleable#GridLayoutAnimation_rowDelay
* @attr ref android.R.styleable#GridLayoutAnimation_direction
@@ -206,7 +206,7 @@
*
* @see #getRowDelay()
* @see #getColumnDelay()
- * @see #setColumnDelay(float)
+ * @see #setColumnDelay(float)
*/
public void setRowDelay(float rowDelay) {
mRowDelay = rowDelay;
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 38962a3..5f7a0f7 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2008 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
@@ -35,7 +35,6 @@
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.View;
-import android.view.ViewRootImpl;
class ComposingText implements NoCopySpan {
}
@@ -56,25 +55,25 @@
protected final InputMethodManager mIMM;
final View mTargetView;
final boolean mDummyMode;
-
+
private Object[] mDefaultComposingSpans;
-
+
Editable mEditable;
KeyCharacterMap mKeyCharacterMap;
-
+
BaseInputConnection(InputMethodManager mgr, boolean fullEditor) {
mIMM = mgr;
mTargetView = null;
mDummyMode = !fullEditor;
}
-
+
public BaseInputConnection(View targetView, boolean fullEditor) {
mIMM = (InputMethodManager)targetView.getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
mTargetView = targetView;
mDummyMode = !fullEditor;
}
-
+
public static final void removeComposingSpans(Spannable text) {
text.removeSpan(COMPOSING);
Object[] sps = text.getSpans(0, text.length(), Object.class);
@@ -104,8 +103,8 @@
}
final int fl = text.getSpanFlags(o);
- if ((fl&(Spanned.SPAN_COMPOSING|Spanned.SPAN_POINT_MARK_MASK))
- != (Spanned.SPAN_COMPOSING|Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)) {
+ if ((fl & (Spanned.SPAN_COMPOSING | Spanned.SPAN_POINT_MARK_MASK))
+ != (Spanned.SPAN_COMPOSING | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)) {
text.setSpan(o, text.getSpanStart(o), text.getSpanEnd(o),
(fl & ~Spanned.SPAN_POINT_MARK_MASK)
| Spanned.SPAN_COMPOSING
@@ -117,15 +116,15 @@
text.setSpan(COMPOSING, start, end,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE | Spanned.SPAN_COMPOSING);
}
-
+
public static int getComposingSpanStart(Spannable text) {
return text.getSpanStart(COMPOSING);
}
-
+
public static int getComposingSpanEnd(Spannable text) {
return text.getSpanEnd(COMPOSING);
}
-
+
/**
* Return the target of edit operations. The default implementation
* returns its own fake editable that is just used for composing text;
@@ -139,7 +138,7 @@
}
return mEditable;
}
-
+
/**
* Default implementation does nothing.
*/
@@ -452,10 +451,10 @@
*/
public int getCursorCapsMode(int reqModes) {
if (mDummyMode) return 0;
-
+
final Editable content = getEditable();
if (content == null) return 0;
-
+
int a = Selection.getSelectionStart(content);
int b = Selection.getSelectionEnd(content);
@@ -495,7 +494,7 @@
if (a <= 0) {
return "";
}
-
+
if (length > a) {
length = a;
}
@@ -702,7 +701,7 @@
if (!mDummyMode) {
return;
}
-
+
Editable content = getEditable();
if (content != null) {
final int N = content.length();
@@ -727,7 +726,7 @@
return;
}
}
-
+
// Otherwise, revert to the special key event containing
// the actual characters.
KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(),
@@ -768,7 +767,7 @@
if (content == null) {
return;
}
-
+
beginBatchEdit();
// delete composing text set previously.
@@ -776,7 +775,7 @@
int b = getComposingSpanEnd(content);
if (DEBUG) Log.v(TAG, "Composing span: " + a + " to " + b);
-
+
if (b < a) {
int tmp = a;
a = b;
@@ -814,11 +813,11 @@
}
setComposingSpans(sp);
}
-
+
if (DEBUG) Log.v(TAG, "Replacing from " + a + " to " + b + " with \""
+ text + "\", composing=" + composing
+ ", type=" + text.getClass().getCanonicalName());
-
+
if (DEBUG) {
LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG);
lp.println("Current text:");
@@ -842,13 +841,13 @@
Selection.setSelection(content, newCursorPosition);
content.replace(a, b, text);
-
+
if (DEBUG) {
LogPrinter lp = new LogPrinter(Log.VERBOSE, TAG);
lp.println("Final text:");
TextUtils.dumpSpans(content, lp, " ");
}
-
+
endBatchEdit();
}
diff --git a/core/java/android/view/inputmethod/InputConnectionInspector.java b/core/java/android/view/inputmethod/InputConnectionInspector.java
index 2b292bb..5f25bf5 100644
--- a/core/java/android/view/inputmethod/InputConnectionInspector.java
+++ b/core/java/android/view/inputmethod/InputConnectionInspector.java
@@ -16,6 +16,8 @@
package android.view.inputmethod;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,8 +30,6 @@
import java.util.Map;
import java.util.WeakHashMap;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
/**
* @hide
*/
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 661b52f..5c8e6dc 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -16,9 +16,6 @@
package android.view.inputmethod;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -39,6 +36,9 @@
import android.util.Xml;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index ca370dc..2e99092 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2007-2008 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
@@ -16,15 +16,7 @@
package android.view.inputmethod;
-import com.android.internal.inputmethod.IInputContentUriToken;
-import com.android.internal.os.SomeArgs;
-import com.android.internal.view.IInputConnectionWrapper;
-import com.android.internal.view.IInputContext;
-import com.android.internal.view.IInputMethodClient;
-import com.android.internal.view.IInputMethodManager;
-import com.android.internal.view.IInputMethodSession;
-import com.android.internal.view.InputBindResult;
-import com.android.internal.view.InputMethodClient;
+import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -40,8 +32,8 @@
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
-import android.os.Trace;
import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.Trace;
import android.text.TextUtils;
import android.text.style.SuggestionSpan;
import android.util.Log;
@@ -56,11 +48,19 @@
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewRootImpl;
-import android.view.textservice.TextServicesManager;
+
+import com.android.internal.inputmethod.IInputContentUriToken;
+import com.android.internal.os.SomeArgs;
+import com.android.internal.view.IInputConnectionWrapper;
+import com.android.internal.view.IInputContext;
+import com.android.internal.view.IInputMethodClient;
+import com.android.internal.view.IInputMethodManager;
+import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.InputBindResult;
+import com.android.internal.view.InputMethodClient;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -70,14 +70,12 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
-
/**
* Central system API to the overall input method framework (IMF) architecture,
* which arbitrates interaction between applications and the current input method.
* You can retrieve an instance of this interface with
* {@link Context#getSystemService(String) Context.getSystemService()}.
- *
+ *
* <p>Topics covered here:
* <ol>
* <li><a href="#ArchitectureOverview">Architecture Overview</a>
@@ -85,13 +83,13 @@
* <li><a href="#InputMethods">Input Methods</a>
* <li><a href="#Security">Security</a>
* </ol>
- *
+ *
* <a name="ArchitectureOverview"></a>
* <h3>Architecture Overview</h3>
- *
+ *
* <p>There are three primary parties involved in the input method
* framework (IMF) architecture:</p>
- *
+ *
* <ul>
* <li> The <strong>input method manager</strong> as expressed by this class
* is the central point of the system that manages interaction between all
@@ -106,16 +104,16 @@
* method manager for input focus and control over the state of the IME. Only
* one such client is ever active (working with the IME) at a time.
* </ul>
- *
- *
+ *
+ *
* <a name="Applications"></a>
* <h3>Applications</h3>
- *
+ *
* <p>In most cases, applications that are using the standard
* {@link android.widget.TextView} or its subclasses will have little they need
* to do to work well with soft input methods. The main things you need to
* be aware of are:</p>
- *
+ *
* <ul>
* <li> Properly set the {@link android.R.attr#inputType} in your editable
* text views, so that the input method will have enough context to help the
@@ -131,43 +129,43 @@
* for your window using the same {@link android.R.attr#windowSoftInputMode}
* attribute.
* </ul>
- *
+ *
* <p>More finer-grained control is available through the APIs here to directly
* interact with the IMF and its IME -- either showing or hiding the input
* area, letting the user pick an input method, etc.</p>
- *
+ *
* <p>For the rare people amongst us writing their own text editors, you
* will need to implement {@link android.view.View#onCreateInputConnection}
* to return a new instance of your own {@link InputConnection} interface
* allowing the IME to interact with your editor.</p>
- *
- *
+ *
+ *
* <a name="InputMethods"></a>
* <h3>Input Methods</h3>
- *
+ *
* <p>An input method (IME) is implemented
* as a {@link android.app.Service}, typically deriving from
* {@link android.inputmethodservice.InputMethodService}. It must provide
* the core {@link InputMethod} interface, though this is normally handled by
* {@link android.inputmethodservice.InputMethodService} and implementors will
* only need to deal with the higher-level API there.</p>
- *
+ *
* See the {@link android.inputmethodservice.InputMethodService} class for
* more information on implementing IMEs.
- *
- *
+ *
+ *
* <a name="Security"></a>
* <h3>Security</h3>
- *
+ *
* <p>There are a lot of security issues associated with input methods,
* since they essentially have freedom to completely drive the UI and monitor
* everything the user enters. The Android input method framework also allows
* arbitrary third party IMEs, so care must be taken to restrict their
* selection and interactions.</p>
- *
+ *
* <p>Here are some key points about the security architecture behind the
* IMF:</p>
- *
+ *
* <ul>
* <li> <p>Only the system is allowed to directly access an IME's
* {@link InputMethod} interface, via the
@@ -175,11 +173,11 @@
* enforced in the system by not binding to an input method service that does
* not require this permission, so the system can guarantee no other untrusted
* clients are accessing the current input method outside of its control.</p>
- *
+ *
* <li> <p>There may be many client processes of the IMF, but only one may
* be active at a time. The inactive clients can not interact with key
* parts of the IMF through the mechanisms described below.</p>
- *
+ *
* <li> <p>Clients of an input method are only given access to its
* {@link InputMethodSession} interface. One instance of this interface is
* created for each client, and only calls from the session associated with
@@ -187,19 +185,19 @@
* by {@link android.inputmethodservice.AbstractInputMethodService} for normal
* IMEs, but must be explicitly handled by an IME that is customizing the
* raw {@link InputMethodSession} implementation.</p>
- *
+ *
* <li> <p>Only the active client's {@link InputConnection} will accept
* operations. The IMF tells each client process whether it is active, and
* the framework enforces that in inactive processes calls on to the current
* InputConnection will be ignored. This ensures that the current IME can
* only deliver events and text edits to the UI that the user sees as
* being in focus.</p>
- *
+ *
* <li> <p>An IME can never interact with an {@link InputConnection} while
* the screen is off. This is enforced by making all clients inactive while
* the screen is off, and prevents bad IMEs from driving the UI when the user
* can not be aware of its behavior.</p>
- *
+ *
* <li> <p>A client application can ask that the system let the user pick a
* new IME, but can not programmatically switch to one itself. This avoids
* malicious applications from switching the user to their own IME, which
@@ -207,7 +205,7 @@
* IME, on the other hand, <em>is</em> allowed to programmatically switch
* the system to another IME, since it already has full control of user
* input.</p>
- *
+ *
* <li> <p>The user must explicitly enable a new IME in settings before
* they can switch to it, to confirm with the system that they know about it
* and want to make it available for use.</p>
@@ -268,11 +266,11 @@
final IInputMethodManager mService;
final Looper mMainLooper;
-
+
// For scheduling work on the main thread. This also serves as our
// global lock.
final H mH;
-
+
// Our generic input connection if the current target does not have its own.
final IInputContext mIInputContext;
@@ -280,20 +278,20 @@
* True if this input method client is active, initially false.
*/
boolean mActive = false;
-
+
/**
* Set whenever this client becomes inactive, to know we need to reset
* state with the IME the next time we receive focus.
*/
boolean mHasBeenInactive = true;
-
+
/**
* As reported by IME through InputConnection.
*/
boolean mFullscreenMode;
-
+
// -----------------------------------------------------------
-
+
/**
* This is the root view of the overall window that currently has input
* method focus.
@@ -328,7 +326,7 @@
* The completions that were last provided by the served view.
*/
CompletionInfo[] mCompletions;
-
+
// Cursor position on the screen.
Rect mTmpCursorRect = new Rect();
Rect mCursorRect = new Rect();
@@ -389,7 +387,7 @@
final SparseArray<PendingEvent> mPendingEvents = new SparseArray<>(20);
// -----------------------------------------------------------
-
+
static final int MSG_DUMP = 1;
static final int MSG_BIND = 2;
static final int MSG_UNBIND = 3;
@@ -403,7 +401,7 @@
H(Looper looper) {
super(looper, null, true);
}
-
+
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
@@ -654,7 +652,7 @@
return sInstance;
}
}
-
+
/**
* Private optimization: retrieve the global InputMethodManager instance,
* if it exists.
@@ -663,17 +661,17 @@
public static InputMethodManager peekInstance() {
return sInstance;
}
-
+
/** @hide */
public IInputMethodClient getClient() {
return mClient;
}
-
+
/** @hide */
public IInputContext getInputContext() {
return mIInputContext;
}
-
+
public List<InputMethodInfo> getInputMethodList() {
try {
return mService.getInputMethodList();
@@ -784,7 +782,7 @@
&& mCurrentTextBoxAttribute != null;
}
}
-
+
/**
* Return true if any view is currently active in the input method.
*/
@@ -794,7 +792,7 @@
return mServedView != null && mCurrentTextBoxAttribute != null;
}
}
-
+
/**
* Return true if the currently served view is accepting full text edits.
* If false, it has no input connection, so can only handle raw key events.
@@ -871,7 +869,7 @@
|| !mServedView.checkInputConnectionProxy(view))) {
return;
}
-
+
mCompletions = completions;
if (mCurMethod != null) {
try {
@@ -881,7 +879,7 @@
}
}
}
-
+
public void updateExtractedText(View view, int token, ExtractedText text) {
checkFocus();
synchronized (mH) {
@@ -889,7 +887,7 @@
|| !mServedView.checkInputConnectionProxy(view))) {
return;
}
-
+
if (mCurMethod != null) {
try {
mCurMethod.updateExtractedText(token, text);
@@ -898,26 +896,26 @@
}
}
}
-
+
/**
* Flag for {@link #showSoftInput} to indicate that this is an implicit
* request to show the input window, not as the result of a direct request
* by the user. The window may not be shown in this case.
*/
public static final int SHOW_IMPLICIT = 0x0001;
-
+
/**
* Flag for {@link #showSoftInput} to indicate that the user has forced
* the input method open (such as by long-pressing menu) so it should
* not be closed until they explicitly do so.
*/
public static final int SHOW_FORCED = 0x0002;
-
+
/**
* Synonym for {@link #showSoftInput(View, int, ResultReceiver)} without
* a result receiver: explicitly request that the current input method's
* soft input area be shown to the user, if needed.
- *
+ *
* @param view The currently focused view, which would like to receive
* soft keyboard input.
* @param flags Provides additional operating flags. Currently may be
@@ -926,7 +924,7 @@
public boolean showSoftInput(View view, int flags) {
return showSoftInput(view, flags, null);
}
-
+
/**
* Flag for the {@link ResultReceiver} result code from
* {@link #showSoftInput(View, int, ResultReceiver)} and
@@ -934,7 +932,7 @@
* state of the soft input window was unchanged and remains shown.
*/
public static final int RESULT_UNCHANGED_SHOWN = 0;
-
+
/**
* Flag for the {@link ResultReceiver} result code from
* {@link #showSoftInput(View, int, ResultReceiver)} and
@@ -942,7 +940,7 @@
* state of the soft input window was unchanged and remains hidden.
*/
public static final int RESULT_UNCHANGED_HIDDEN = 1;
-
+
/**
* Flag for the {@link ResultReceiver} result code from
* {@link #showSoftInput(View, int, ResultReceiver)} and
@@ -950,7 +948,7 @@
* state of the soft input window changed from hidden to shown.
*/
public static final int RESULT_SHOWN = 2;
-
+
/**
* Flag for the {@link ResultReceiver} result code from
* {@link #showSoftInput(View, int, ResultReceiver)} and
@@ -958,7 +956,7 @@
* state of the soft input window changed from shown to hidden.
*/
public static final int RESULT_HIDDEN = 3;
-
+
/**
* Explicitly request that the current input method's soft input area be
* shown to the user, if needed. Call this if the user interacts with
@@ -1000,7 +998,7 @@
}
}
}
-
+
/** @hide */
public void showSoftInputUnchecked(int flags, ResultReceiver resultReceiver) {
try {
@@ -1009,14 +1007,14 @@
throw e.rethrowFromSystemServer();
}
}
-
+
/**
* Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
* input window should only be hidden if it was not explicitly shown
* by the user.
*/
public static final int HIDE_IMPLICIT_ONLY = 0x0001;
-
+
/**
* Flag for {@link #hideSoftInputFromWindow} to indicate that the soft
* input window should normally be hidden, unless it was originally
@@ -1028,7 +1026,7 @@
* Synonym for {@link #hideSoftInputFromWindow(IBinder, int, ResultReceiver)}
* without a result: request to hide the soft input window from the
* context of the window that is currently accepting input.
- *
+ *
* @param windowToken The token of the window that is making the request,
* as returned by {@link View#getWindowToken() View.getWindowToken()}.
* @param flags Provides additional operating flags. Currently may be
@@ -1037,7 +1035,7 @@
public boolean hideSoftInputFromWindow(IBinder windowToken, int flags) {
return hideSoftInputFromWindow(windowToken, flags, null);
}
-
+
/**
* Request to hide the soft input window from the context of the window
* that is currently accepting input. This should be called as a result
@@ -1079,11 +1077,11 @@
}
}
}
-
+
/**
* This method toggles the input method window display.
- * If the input window is already displayed, it gets hidden.
+ * If the input window is already displayed, it gets hidden.
* If not the input window will be displayed.
* @param windowToken The token of the window that is making the request,
* as returned by {@link View#getWindowToken() View.getWindowToken()}.
@@ -1110,7 +1108,7 @@
/*
* This method toggles the input method window display.
- * If the input window is already displayed, it gets hidden.
+ * If the input window is already displayed, it gets hidden.
* If not the input window will be displayed.
* @param showFlags Provides additional operating flags. May be
* 0 or have the {@link #SHOW_IMPLICIT},
@@ -1134,7 +1132,7 @@
* restart it with its new contents. You should call this when the text
* within your view changes outside of the normal input method or key
* input flow, such as when an application calls TextView.setText().
- *
+ *
* @param view The view whose text has changed.
*/
public void restartInput(View view) {
@@ -1144,7 +1142,7 @@
|| !mServedView.checkInputConnectionProxy(view))) {
return;
}
-
+
mServedConnecting = true;
}
@@ -1196,7 +1194,7 @@
});
return false;
}
-
+
// Okay we are now ready to call into the served view and have it
// do its stuff.
// Life is good: let's hook everything up!
@@ -1465,7 +1463,7 @@
return true;
}
-
+
void closeCurrentInput() {
try {
mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null);
@@ -1504,7 +1502,7 @@
if (first) {
controlFlags |= CONTROL_WINDOW_FIRST;
}
-
+
if (checkFocusNoStartInput(forceNewFocus)) {
// We need to restart input on the current focus view. This
// should be done in conjunction with telling the system service
@@ -1792,7 +1790,7 @@
* Close/hide the input method's soft input area, so the user no longer
* sees it or can interact with it. This can only be called
* from the currently active input method, as validated by the given token.
- *
+ *
* @param token Supplies the identifying token given to an input method
* when it was started, which allows it to perform this operation on
* itself.
@@ -1807,13 +1805,13 @@
throw e.rethrowFromSystemServer();
}
}
-
+
/**
- * Show the input method's soft input area, so the user
+ * Show the input method's soft input area, so the user
* sees the input method window and can interact with it.
* This can only be called from the currently active input method,
* as validated by the given token.
- *
+ *
* @param token Supplies the identifying token given to an input method
* when it was started, which allows it to perform this operation on
* itself.
@@ -2335,7 +2333,7 @@
void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
final Printer p = new PrintWriterPrinter(fout);
p.println("Input method client state for " + this + ":");
-
+
p.println(" mService=" + mService);
p.println(" mMainLooper=" + mMainLooper);
p.println(" mIInputContext=" + mIInputContext);
diff --git a/core/java/android/view/textservice/SpellCheckerInfo.java b/core/java/android/view/textservice/SpellCheckerInfo.java
index fc17f7a..7aa2c23 100644
--- a/core/java/android/view/textservice/SpellCheckerInfo.java
+++ b/core/java/android/view/textservice/SpellCheckerInfo.java
@@ -16,9 +16,6 @@
package android.view.textservice;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -35,6 +32,9 @@
import android.util.Slog;
import android.util.Xml;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index e77dc0d..729eb8d 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -16,11 +16,6 @@
package android.view.textservice;
-import com.android.internal.textservice.ISpellCheckerSession;
-import com.android.internal.textservice.ISpellCheckerSessionListener;
-import com.android.internal.textservice.ITextServicesManager;
-import com.android.internal.textservice.ITextServicesSessionListener;
-
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -29,6 +24,11 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.textservice.ISpellCheckerSession;
+import com.android.internal.textservice.ISpellCheckerSessionListener;
+import com.android.internal.textservice.ITextServicesManager;
+import com.android.internal.textservice.ITextServicesSessionListener;
+
import java.util.LinkedList;
import java.util.Queue;
diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java
index 8dff0c6..026610e 100644
--- a/core/java/android/view/textservice/SpellCheckerSubtype.java
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.java
@@ -16,8 +16,6 @@
package android.view.textservice;
-import com.android.internal.inputmethod.InputMethodUtils;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -27,6 +25,8 @@
import android.text.TextUtils;
import android.util.Slog;
+import com.android.internal.inputmethod.InputMethodUtils;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
index 78bc1a9..dc2051c 100644
--- a/core/java/android/view/textservice/SuggestionsInfo.java
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -16,11 +16,11 @@
package android.view.textservice;
-import com.android.internal.util.ArrayUtils;
-
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.ArrayUtils;
+
/**
* This class contains a metadata of suggestions from the text service
*/
diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl
index 9434f0c..894f080 100644
--- a/core/java/android/webkit/IWebViewUpdateService.aidl
+++ b/core/java/android/webkit/IWebViewUpdateService.aidl
@@ -64,6 +64,11 @@
String getCurrentWebViewPackageName();
/**
+ * Used by public API for debugging purposes.
+ */
+ PackageInfo getCurrentWebViewPackage();
+
+ /**
* Used by Settings to determine whether a certain package can be enabled/disabled by the user -
* the package should not be modifiable in this way if it is a fallback package.
*/
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index aaa7b26..939f45f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -21,6 +21,7 @@
import android.annotation.Widget;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -36,6 +37,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.StrictMode;
+import android.os.RemoteException;
import android.print.PrintDocumentAdapter;
import android.security.KeyChain;
import android.util.AttributeSet;
@@ -1768,6 +1770,7 @@
* requests. This will replace the current handler.
*
* @param client an implementation of WebViewClient
+ * @see #getWebViewClient
*/
public void setWebViewClient(WebViewClient client) {
checkThread();
@@ -1775,6 +1778,17 @@
}
/**
+ * Gets the WebViewClient.
+ *
+ * @return the WebViewClient, or a default client if not yet set
+ * @see #setWebViewClient
+ */
+ public WebViewClient getWebViewClient() {
+ checkThread();
+ return mProvider.getWebViewClient();
+ }
+
+ /**
* Registers the interface to be used when content can not be handled by
* the rendering engine, and should be downloaded instead. This will replace
* the current handler.
@@ -1792,6 +1806,7 @@
* This will replace the current handler.
*
* @param client an implementation of WebChromeClient
+ * @see #getWebChromeClient
*/
public void setWebChromeClient(WebChromeClient client) {
checkThread();
@@ -1799,6 +1814,17 @@
}
/**
+ * Gets the chrome handler.
+ *
+ * @return the WebChromeClient, or null if not yet set
+ * @see #setWebChromeClient
+ */
+ public WebChromeClient getWebChromeClient() {
+ checkThread();
+ return mProvider.getWebChromeClient();
+ }
+
+ /**
* Sets the Picture listener. This is an interface used to receive
* notifications of a new Picture.
*
@@ -2650,6 +2676,26 @@
}
/**
+ * If WebView has already been loaded into the current process this method will return the
+ * package that was used to load it. Otherwise, the package that would be used if the WebView
+ * was loaded right now will be returned; this does not cause WebView to be loaded, so this
+ * information may become outdated at any time.
+ * @return the current WebView package, or null if there is none.
+ */
+ public static PackageInfo getCurrentWebViewPackage() {
+ PackageInfo webviewPackage = WebViewFactory.getLoadedPackageInfo();
+ if (webviewPackage != null) {
+ return webviewPackage;
+ }
+
+ try {
+ return WebViewFactory.getUpdateService().getCurrentWebViewPackage();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}.
*
* @param requestCode The integer request code originally supplied to
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 4bfc718..884a86c 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -135,7 +135,9 @@
}
public static PackageInfo getLoadedPackageInfo() {
- return sPackageInfo;
+ synchronized (sProviderLock) {
+ return sPackageInfo;
+ }
}
/**
@@ -170,9 +172,8 @@
Log.e(LOGTAG, "Couldn't find package " + packageName);
return LIBLOAD_WRONG_PACKAGE_NAME;
}
- sPackageInfo = packageInfo;
- int loadNativeRet = loadNativeLibrary(clazzLoader);
+ int loadNativeRet = loadNativeLibrary(clazzLoader, packageInfo);
// If we failed waiting for relro we want to return that fact even if we successfully load
// the relro file.
if (loadNativeRet == LIBLOAD_SUCCESS) return response.status;
@@ -358,7 +359,7 @@
ClassLoader clazzLoader = webViewContext.getClassLoader();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
- loadNativeLibrary(clazzLoader);
+ loadNativeLibrary(clazzLoader, sPackageInfo);
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
@@ -637,14 +638,14 @@
}
}
- // Assumes that we have waited for relro creation and set sPackageInfo
- private static int loadNativeLibrary(ClassLoader clazzLoader) {
+ // Assumes that we have waited for relro creation
+ private static int loadNativeLibrary(ClassLoader clazzLoader, PackageInfo packageInfo) {
if (!sAddressSpaceReserved) {
Log.e(LOGTAG, "can't load with relro file; address space not reserved");
return LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
}
- String[] args = getWebViewNativeLibraryPaths(sPackageInfo);
+ String[] args = getWebViewNativeLibraryPaths(packageInfo);
int result = nativeLoadWithRelroFile(args[0] /* path32 */,
args[1] /* path64 */,
CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index e5b65e7..95ec179 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -229,10 +229,14 @@
public void setWebViewClient(WebViewClient client);
+ public WebViewClient getWebViewClient();
+
public void setDownloadListener(DownloadListener listener);
public void setWebChromeClient(WebChromeClient client);
+ public WebChromeClient getWebChromeClient();
+
public void setPictureListener(PictureListener listener);
public void addJavascriptInterface(Object obj, String interfaceName);
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 01a95a4..5d136dc 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -36,6 +34,8 @@
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.R;
+
/**
* AbsSeekBar extends the capabilities of ProgressBar by adding a draggable thumb.
@@ -469,7 +469,7 @@
/**
* Returns the amount of progress changed via the arrow keys.
* <p>
- * By default, this will be a value that is derived from the max progress.
+ * By default, this will be a value that is derived from the progress range.
*
* @return The amount to increment or decrement when the user presses the
* arrow keys. This will be positive.
@@ -479,13 +479,27 @@
}
@Override
- public synchronized void setMax(int max) {
- super.setMax(max);
+ public synchronized void setMin(int min) {
+ super.setMin(min);
+ int range = getMax() - getMin();
- if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) {
+ if ((mKeyProgressIncrement == 0) || (range / mKeyProgressIncrement > 20)) {
+
// It will take the user too long to change this via keys, change it
// to something more reasonable
- setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20)));
+ setKeyProgressIncrement(Math.max(1, Math.round((float) range / 20)));
+ }
+ }
+
+ @Override
+ public synchronized void setMax(int max) {
+ super.setMax(max);
+ int range = getMax() - getMin();
+
+ if ((mKeyProgressIncrement == 0) || (range / mKeyProgressIncrement > 20)) {
+ // It will take the user too long to change this via keys, change it
+ // to something more reasonable
+ setKeyProgressIncrement(Math.max(1, Math.round((float) range / 20)));
}
}
@@ -596,8 +610,10 @@
}
private float getScale() {
- final int max = getMax();
- return max > 0 ? getProgress() / (float) max : 0;
+ int min = getMin();
+ int max = getMax();
+ int range = max - min;
+ return range > 0 ? (getProgress() - min) / (float) range : 0;
}
/**
@@ -691,7 +707,7 @@
*/
void drawTickMarks(Canvas canvas) {
if (mTickMark != null) {
- final int count = getMax();
+ final int count = getMax() - getMin();
if (count > 1) {
final int w = mTickMark.getIntrinsicWidth();
final int h = mTickMark.getIntrinsicHeight();
@@ -847,8 +863,8 @@
}
}
- final int max = getMax();
- progress += scale * max;
+ final int range = getMax() - getMin();
+ progress += scale * range;
setHotspot(x, y);
setProgressInternal(Math.round(progress), true, false);
@@ -922,7 +938,7 @@
if (isEnabled()) {
final int progress = getProgress();
- if (progress > 0) {
+ if (progress > getMin()) {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
}
if (progress < getMax()) {
@@ -960,7 +976,8 @@
if (!canUserSetProgress()) {
return false;
}
- int increment = Math.max(1, Math.round((float) getMax() / 20));
+ int range = getMax() - getMin();
+ int increment = Math.max(1, Math.round((float) range / 20));
if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) {
increment = -increment;
}
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index 18db54e..bc3dfff 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
@@ -29,10 +27,12 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.R;
+
/**
* An abstract base class for spinner widgets. SDK users will probably not
* need to use this class.
- *
+ *
* @attr ref android.R.styleable#AbsSpinner_entries
*/
public abstract class AbsSpinner extends AdapterView<SpinnerAdapter> {
@@ -104,12 +104,12 @@
mAdapter.unregisterDataSetObserver(mDataSetObserver);
resetList();
}
-
+
mAdapter = adapter;
-
+
mOldSelectedPosition = INVALID_POSITION;
mOldSelectedRowId = INVALID_ROW_ID;
-
+
if (mAdapter != null) {
mOldItemCount = mItemCount;
mItemCount = mAdapter.getCount();
@@ -122,14 +122,14 @@
setSelectedPositionInt(position);
setNextSelectedPositionInt(position);
-
+
if (mItemCount == 0) {
// Nothing selected
checkSelectionChanged();
}
-
+
} else {
- checkFocus();
+ checkFocus();
resetList();
// Nothing selected
checkSelectionChanged();
@@ -144,23 +144,23 @@
void resetList() {
mDataChanged = false;
mNeedSync = false;
-
+
removeAllViewsInLayout();
mOldSelectedPosition = INVALID_POSITION;
mOldSelectedRowId = INVALID_ROW_ID;
-
+
setSelectedPositionInt(INVALID_POSITION);
setNextSelectedPositionInt(INVALID_POSITION);
invalidate();
}
- /**
+ /**
* @see android.view.View#measure(int, int)
- *
+ *
* Figure out the dimensions of this Spinner. The width comes from
* the widthMeasureSpec as Spinnners can't have their width set to
* UNSPECIFIED. The height is based on the height of the selected item
- * plus padding.
+ * plus padding.
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
@@ -180,11 +180,11 @@
if (mDataChanged) {
handleDataChanged();
}
-
+
int preferredHeight = 0;
int preferredWidth = 0;
boolean needsMeasuring = true;
-
+
int selectedPosition = getSelectedItemPosition();
if (selectedPosition >= 0 && mAdapter != null && selectedPosition < mAdapter.getCount()) {
// Try looking in the recycler. (Maybe we were measured once already)
@@ -208,14 +208,14 @@
mBlockLayoutRequests = false;
}
measureChild(view, widthMeasureSpec, heightMeasureSpec);
-
+
preferredHeight = getChildHeight(view) + mSpinnerPadding.top + mSpinnerPadding.bottom;
preferredWidth = getChildWidth(view) + mSpinnerPadding.left + mSpinnerPadding.right;
-
+
needsMeasuring = false;
}
}
-
+
if (needsMeasuring) {
// No views -- just use padding
preferredHeight = mSpinnerPadding.top + mSpinnerPadding.bottom;
@@ -238,18 +238,18 @@
int getChildHeight(View child) {
return child.getMeasuredHeight();
}
-
+
int getChildWidth(View child) {
return child.getMeasuredWidth();
}
-
+
@Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
-
+
void recycleAllViews() {
final int childCount = getChildCount();
final AbsSpinner.RecycleBin recycleBin = mRecycler;
@@ -260,7 +260,7 @@
View v = getChildAt(i);
int index = position + i;
recycleBin.put(index, v);
- }
+ }
}
/**
@@ -279,14 +279,14 @@
requestLayout();
invalidate();
}
-
+
/**
* Makes the item at the supplied position selected.
- *
+ *
* @param position Position to select
* @param animate Should the transition be animated
- *
+ *
*/
void setSelectionInt(int position, boolean animate) {
if (position != mOldSelectedPosition) {
@@ -308,11 +308,11 @@
return null;
}
}
-
+
/**
* Override to prevent spamming ourselves with layout requests
* as we place views
- *
+ *
* @see android.view.View#requestLayout()
*/
@Override
@@ -334,7 +334,7 @@
/**
* Maps a point to a position in the list.
- *
+ *
* @param x X in local coordinate
* @param y Y in local coordinate
* @return The position of the item which contains the specified point, or
@@ -378,7 +378,7 @@
SavedState(Parcelable superState) {
super(superState);
}
-
+
/**
* Constructor called from {@link #CREATOR}
*/
@@ -431,7 +431,7 @@
@Override
public void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
-
+
super.onRestoreInstanceState(ss.getSuperState());
if (ss.selectedId >= 0) {
@@ -450,7 +450,7 @@
public void put(int position, View v) {
mScrapHeap.put(position, v);
}
-
+
View get(int position) {
// System.out.print("Looking for " + position);
View result = mScrapHeap.get(position);
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index ac8d578..46269c6 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -39,6 +39,7 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityNodeInfo;
+
import com.android.internal.view.ActionBarPolicy;
import com.android.internal.view.menu.ActionMenuItemView;
import com.android.internal.view.menu.BaseMenuPresenter;
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 4d0a1c8..c4bbdb0 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -31,6 +31,7 @@
import android.view.ViewGroup;
import android.view.ViewHierarchyEncoder;
import android.view.accessibility.AccessibilityEvent;
+
import com.android.internal.view.menu.ActionMenuItemView;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuItemImpl;
@@ -45,7 +46,7 @@
*/
public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvoker, MenuView {
private static final String TAG = "ActionMenuView";
-
+
static final int MIN_CELL_SIZE = 56; // dips
static final int GENERATED_ITEM_PADDING = 4; // dips
@@ -71,7 +72,7 @@
public ActionMenuView(Context context) {
this(context, null);
}
-
+
public ActionMenuView(Context context, AttributeSet attrs) {
super(context, attrs);
setBaselineAligned(false);
@@ -579,7 +580,7 @@
params.gravity = Gravity.CENTER_VERTICAL;
return params;
}
-
+
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index f5c46db..51587a7 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -16,9 +16,6 @@
package android.widget;
-import com.android.internal.R;
-import com.android.internal.view.menu.ShowableListMenu;
-
import android.annotation.StringRes;
import android.content.Context;
import android.content.Intent;
@@ -39,6 +36,9 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ActivityChooserModel.ActivityChooserModelClient;
+import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
+
/**
* This class is a view for choosing an activity for handling a given {@link Intent}.
* <p>
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 7f5e2133..bde5f7f 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -16,15 +16,14 @@
package android.widget;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.BroadcastReceiver;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
-import android.os.Handler;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.AttributeSet;
@@ -258,7 +257,7 @@
}
onTimeChanged();
-
+
invalidate();
}
};
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index 1a1680a..68e6809 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -16,10 +16,6 @@
*/
package android.widget;
-import android.annotation.SystemApi;
-import android.os.UserHandle;
-import com.android.internal.R;
-
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
@@ -31,6 +27,7 @@
import android.content.pm.PermissionInfo;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
+import android.os.UserHandle;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -39,6 +36,8 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.R;
+
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
@@ -57,7 +56,7 @@
* extended information consisting of all groups and permissions.
* To use this view define a LinearLayout or any ViewGroup and add this
* view by instantiating AppSecurityPermissions and invoking getPermissionsView.
- *
+ *
* {@hide}
*/
public class AppSecurityPermissions {
@@ -324,7 +323,7 @@
return getPermissionItemViewOld(context, inflater, grpName,
description, dangerous, icon);
}
-
+
private void getAllUsedPermissions(int sharedUid, Set<MyPermissionInfo> permSet) {
String sharedPkgList[] = mPm.getPackagesForUid(sharedUid);
if(sharedPkgList == null || (sharedPkgList.length == 0)) {
@@ -334,7 +333,7 @@
getPermissionsForPackage(sharedPkg, permSet);
}
}
-
+
private void getPermissionsForPackage(String packageName, Set<MyPermissionInfo> permSet) {
try {
PackageInfo pkgInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS);
@@ -417,7 +416,7 @@
}
}
}
-
+
public int getPermissionCount() {
return getPermissionCount(WHICH_ALL);
}
@@ -570,7 +569,7 @@
}
return false;
}
-
+
private static class PermissionGroupInfoComparator implements Comparator<MyPermissionGroupInfo> {
private final Collator sCollator = Collator.getInstance();
@Override
@@ -578,7 +577,7 @@
return sCollator.compare(a.mLabel, b.mLabel);
}
}
-
+
private static class PermissionInfoComparator implements Comparator<MyPermissionInfo> {
private final Collator sCollator = Collator.getInstance();
PermissionInfoComparator() {
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 6a4e36a..49741d4 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -39,7 +39,9 @@
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
+
import com.android.internal.R;
+
import java.lang.ref.WeakReference;
/**
@@ -362,22 +364,22 @@
* <p>Returns the current width for the auto-complete drop down list. This can
* be a fixed width, or {@link ViewGroup.LayoutParams#MATCH_PARENT} to fill the screen, or
* {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the width of its anchor view.</p>
- *
+ *
* @return the width for the drop down list
- *
+ *
* @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth
*/
public int getDropDownWidth() {
return mPopup.getWidth();
}
-
+
/**
* <p>Sets the current width for the auto-complete drop down list. This can
* be a fixed width, or {@link ViewGroup.LayoutParams#MATCH_PARENT} to fill the screen, or
* {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the width of its anchor view.</p>
- *
+ *
* @param width the width to use
- *
+ *
* @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth
*/
public void setDropDownWidth(int width) {
@@ -411,68 +413,68 @@
public void setDropDownHeight(int height) {
mPopup.setHeight(height);
}
-
+
/**
* <p>Returns the id for the view that the auto-complete drop down list is anchored to.</p>
- *
+ *
* @return the view's id, or {@link View#NO_ID} if none specified
- *
+ *
* @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor
*/
public int getDropDownAnchor() {
return mDropDownAnchorId;
}
-
+
/**
* <p>Sets the view to which the auto-complete drop down list should anchor. The view
* corresponding to this id will not be loaded until the next time it is needed to avoid
* loading a view which is not yet instantiated.</p>
- *
+ *
* @param id the id to anchor the drop down list view to
- *
- * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor
+ *
+ * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor
*/
public void setDropDownAnchor(int id) {
mDropDownAnchorId = id;
mPopup.setAnchorView(null);
}
-
+
/**
* <p>Gets the background of the auto-complete drop-down list.</p>
- *
+ *
* @return the background drawable
- *
+ *
* @attr ref android.R.styleable#PopupWindow_popupBackground
*/
public Drawable getDropDownBackground() {
return mPopup.getBackground();
}
-
+
/**
* <p>Sets the background of the auto-complete drop-down list.</p>
- *
+ *
* @param d the drawable to set as the background
- *
+ *
* @attr ref android.R.styleable#PopupWindow_popupBackground
*/
public void setDropDownBackgroundDrawable(Drawable d) {
mPopup.setBackgroundDrawable(d);
}
-
+
/**
* <p>Sets the background of the auto-complete drop-down list.</p>
- *
+ *
* @param id the id of the drawable to set as the background
- *
+ *
* @attr ref android.R.styleable#PopupWindow_popupBackground
*/
public void setDropDownBackgroundResource(@DrawableRes int id) {
mPopup.setBackgroundDrawable(getContext().getDrawable(id));
}
-
+
/**
* <p>Sets the vertical offset used for the auto-complete drop-down list.</p>
- *
+ *
* @param offset the vertical offset
*
* @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
@@ -480,10 +482,10 @@
public void setDropDownVerticalOffset(int offset) {
mPopup.setVerticalOffset(offset);
}
-
+
/**
* <p>Gets the vertical offset used for the auto-complete drop-down list.</p>
- *
+ *
* @return the vertical offset
*
* @attr ref android.R.styleable#ListPopupWindow_dropDownVerticalOffset
@@ -491,10 +493,10 @@
public int getDropDownVerticalOffset() {
return mPopup.getVerticalOffset();
}
-
+
/**
* <p>Sets the horizontal offset used for the auto-complete drop-down list.</p>
- *
+ *
* @param offset the horizontal offset
*
* @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset
@@ -502,10 +504,10 @@
public void setDropDownHorizontalOffset(int offset) {
mPopup.setHorizontalOffset(offset);
}
-
+
/**
* <p>Gets the horizontal offset used for the auto-complete drop-down list.</p>
- *
+ *
* @return the horizontal offset
*
* @attr ref android.R.styleable#ListPopupWindow_dropDownHorizontalOffset
@@ -567,10 +569,10 @@
public void setDropDownAlwaysVisible(boolean dropDownAlwaysVisible) {
mPopup.setDropDownAlwaysVisible(dropDownAlwaysVisible);
}
-
+
/**
* Checks whether the drop-down is dismissed when a suggestion is clicked.
- *
+ *
* @hide Pending API council approval
*/
public boolean isDropDownDismissedOnCompletion() {
@@ -578,17 +580,17 @@
}
/**
- * Sets whether the drop-down is dismissed when a suggestion is clicked. This is
+ * Sets whether the drop-down is dismissed when a suggestion is clicked. This is
* true by default.
- *
+ *
* @param dropDownDismissedOnCompletion Whether to dismiss the drop-down.
- *
+ *
* @hide Pending API council approval
*/
public void setDropDownDismissedOnCompletion(boolean dropDownDismissedOnCompletion) {
mDropDownDismissedOnCompletion = dropDownDismissedOnCompletion;
}
-
+
/**
* <p>Returns the number of characters the user must type before the drop
* down list is shown.</p>
@@ -720,13 +722,13 @@
/**
* <p>Changes the list of data used for auto completion. The provided list
* must be a filterable list adapter.</p>
- *
+ *
* <p>The caller is still responsible for managing any resources used by the adapter.
* Notably, when the AutoCompleteTextView is closed or released, the adapter is not notified.
* A common case is the use of {@link android.widget.CursorAdapter}, which
* contains a {@link android.database.Cursor} that must be closed. This can be done
- * automatically (see
- * {@link android.app.Activity#startManagingCursor(android.database.Cursor)
+ * automatically (see
+ * {@link android.app.Activity#startManagingCursor(android.database.Cursor)
* startManagingCursor()}),
* or by manually closing the cursor when the AutoCompleteTextView is dismissed.</p>
*
@@ -811,7 +813,7 @@
if (mPopup.onKeyDown(keyCode, event)) {
return true;
}
-
+
if (!isPopupShowing()) {
switch(keyCode) {
case KeyEvent.KEYCODE_DPAD_DOWN:
@@ -924,18 +926,18 @@
protected CharSequence convertSelectionToString(Object selectedItem) {
return mFilter.convertResultToString(selectedItem);
}
-
+
/**
- * <p>Clear the list selection. This may only be temporary, as user input will often bring
+ * <p>Clear the list selection. This may only be temporary, as user input will often bring
* it back.
*/
public void clearListSelection() {
mPopup.clearListSelection();
}
-
+
/**
* Set the position of the dropdown view selection.
- *
+ *
* @param position The position to move the selector to.
*/
public void setListSelection(int position) {
@@ -943,13 +945,13 @@
}
/**
- * Get the position of the dropdown view selection, if there is one. Returns
+ * Get the position of the dropdown view selection, if there is one. Returns
* {@link ListView#INVALID_POSITION ListView.INVALID_POSITION} if there is no dropdown or if
* there is no selection.
- *
- * @return the position of the current selection, if there is one, or
+ *
+ * @return the position of the current selection, if there is one, or
* {@link ListView#INVALID_POSITION ListView.INVALID_POSITION} if not.
- *
+ *
* @see ListView#getSelectedItemPosition()
*/
public int getListSelection() {
@@ -1020,7 +1022,7 @@
dismissDropDown();
}
}
-
+
/**
* Identifies whether the view is currently performing a text completion, so subclasses
* can decide whether to respond to text changed events.
@@ -1172,7 +1174,7 @@
public void showDropDownAfterLayout() {
mPopup.postShow();
}
-
+
/**
* Ensures that the drop down is not obscuring the IME.
* @param visible whether the ime should be in front. If false, the ime is pushed to
@@ -1220,7 +1222,7 @@
* Forces outside touches to be ignored. Normally if {@link #isDropDownAlwaysVisible()} is
* false, we allow outside touch to dismiss the dropdown. If this is set to true, then we
* ignore outside touch even when the drop down is not set to always visible.
- *
+ *
* @hide used only by SearchDialog
*/
public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) {
@@ -1245,7 +1247,7 @@
realCount++;
}
}
-
+
if (realCount != count) {
CompletionInfo[] tmp = new CompletionInfo[realCount];
System.arraycopy(completions, 0, tmp, 0, realCount);
@@ -1340,7 +1342,7 @@
*/
CharSequence fixText(CharSequence invalidText);
}
-
+
/**
* Listener to respond to the AutoCompleteTextView's completion list being dismissed.
* @see AutoCompleteTextView#setOnDismissListener(OnDismissListener)
diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java
index 6ef1576..db50e34 100644
--- a/core/java/android/widget/CalendarView.java
+++ b/core/java/android/widget/CalendarView.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.AttrRes;
import android.annotation.ColorInt;
import android.annotation.DrawableRes;
@@ -36,6 +34,8 @@
import android.util.AttributeSet;
import android.util.Log;
+import com.android.internal.R;
+
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
diff --git a/core/java/android/widget/CalendarViewLegacyDelegate.java b/core/java/android/widget/CalendarViewLegacyDelegate.java
index bcda83f..557d411 100644
--- a/core/java/android/widget/CalendarViewLegacyDelegate.java
+++ b/core/java/android/widget/CalendarViewLegacyDelegate.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.app.Service;
import android.content.Context;
import android.content.res.Configuration;
@@ -38,10 +36,12 @@
import android.view.View;
import android.view.ViewGroup;
-import java.util.Locale;
+import com.android.internal.R;
import libcore.icu.LocaleData;
+import java.util.Locale;
+
/**
* A delegate implementing the legacy CalendarView
*/
diff --git a/core/java/android/widget/CheckBox.java b/core/java/android/widget/CheckBox.java
index 15bbdd2..046f75f 100644
--- a/core/java/android/widget/CheckBox.java
+++ b/core/java/android/widget/CheckBox.java
@@ -19,7 +19,6 @@
import android.content.Context;
import android.util.AttributeSet;
-
/**
* <p>
* A checkbox is a specific type of two-states button that can be either
@@ -44,12 +43,12 @@
*
* <p>See the <a href="{@docRoot}guide/topics/ui/controls/checkbox.html">Checkboxes</a>
* guide.</p>
- *
- * <p><strong>XML attributes</strong></p>
+ *
+ * <p><strong>XML attributes</strong></p>
* <p>
- * See {@link android.R.styleable#CompoundButton CompoundButton Attributes},
- * {@link android.R.styleable#Button Button Attributes},
- * {@link android.R.styleable#TextView TextView Attributes},
+ * See {@link android.R.styleable#CompoundButton CompoundButton Attributes},
+ * {@link android.R.styleable#Button Button Attributes},
+ * {@link android.R.styleable#TextView TextView Attributes},
* {@link android.R.styleable#View View Attributes}
* </p>
*/
@@ -57,7 +56,7 @@
public CheckBox(Context context) {
this(context, null);
}
-
+
public CheckBox(Context context, AttributeSet attrs) {
this(context, attrs, com.android.internal.R.attr.checkboxStyle);
}
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 21595d15..92bfd56 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -16,11 +16,8 @@
package android.widget;
-import android.annotation.NonNull;
-import android.view.ViewHierarchyEncoder;
-import com.android.internal.R;
-
import android.annotation.DrawableRes;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -34,9 +31,12 @@
import android.view.Gravity;
import android.view.RemotableViewMethod;
import android.view.ViewDebug;
+import android.view.ViewHierarchyEncoder;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.R;
+
/**
* An extension to {@link TextView} that supports the {@link Checkable}
* interface and displays.
@@ -394,7 +394,7 @@
y = (getHeight() - height) / 2;
break;
}
-
+
final boolean checkMarkAtStart = isCheckMarkAtStart();
final int width = getWidth();
final int top = y;
@@ -417,7 +417,7 @@
}
}
}
-
+
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java
index adcb012..b9224f3 100644
--- a/core/java/android/widget/Chronometer.java
+++ b/core/java/android/widget/Chronometer.java
@@ -24,7 +24,6 @@
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
import android.widget.RemoteViews.RemoteView;
import com.android.internal.R;
@@ -80,7 +79,7 @@
private OnChronometerTickListener mOnChronometerTickListener;
private StringBuilder mRecycle = new StringBuilder(8);
private boolean mCountDown;
-
+
/**
* Initialize this Chronometer object.
* Sets the base to the current time.
@@ -191,7 +190,7 @@
/**
* Sets the listener to be called when the chronometer changes.
- *
+ *
* @param listener The listener.
*/
public void setOnChronometerTickListener(OnChronometerTickListener listener) {
@@ -209,10 +208,10 @@
/**
* Start counting up. This does not affect the base as set from {@link #setBase}, just
* the view display.
- *
- * Chronometer works by regularly scheduling messages to the handler, even when the
- * Widget is not visible. To make sure resource leaks do not occur, the user should
- * make sure that each start() call has a reciprocal call to {@link #stop}.
+ *
+ * Chronometer works by regularly scheduling messages to the handler, even when the
+ * Widget is not visible. To make sure resource leaks do not occur, the user should
+ * make sure that each start() call has a reciprocal call to {@link #stop}.
*/
public void start() {
mStarted = true;
@@ -222,9 +221,9 @@
/**
* Stop counting up. This does not affect the base as set from {@link #setBase}, just
* the view display.
- *
+ *
* This stops the messages to the handler, effectively releasing resources that would
- * be held as the chronometer is running, via {@link #start}.
+ * be held as the chronometer is running, via {@link #start}.
*/
public void stop() {
mStarted = false;
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index 0357834..dd63fef 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -19,14 +19,11 @@
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.graphics.PorterDuff;
-import android.view.ViewHierarchyEncoder;
-import com.android.internal.R;
-
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,9 +31,12 @@
import android.view.Gravity;
import android.view.SoundEffectConstants;
import android.view.ViewDebug;
+import android.view.ViewHierarchyEncoder;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
+import com.android.internal.R;
+
/**
* <p>
* A button with two states, checked and unchecked. When the button is pressed
@@ -159,7 +159,7 @@
mOnCheckedChangeWidgetListener.onCheckedChanged(this, mChecked);
}
- mBroadcasting = false;
+ mBroadcasting = false;
}
}
@@ -492,7 +492,7 @@
SavedState(Parcelable superState) {
super(superState);
}
-
+
/**
* Constructor called from {@link #CREATOR}
*/
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 80f25d4..517e20cd 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -35,6 +33,8 @@
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
+import com.android.internal.R;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Locale;
diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java
index 1bf0c87..f712685 100755
--- a/core/java/android/widget/DatePickerCalendarDelegate.java
+++ b/core/java/android/widget/DatePickerCalendarDelegate.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -40,6 +38,8 @@
import android.widget.DayPickerView.OnDaySelectedListener;
import android.widget.YearPickerView.OnYearSelectedListener;
+import com.android.internal.R;
+
import java.util.Locale;
/**
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
index 9ecf8a5..702b2a5 100644
--- a/core/java/android/widget/DatePickerSpinnerDelegate.java
+++ b/core/java/android/widget/DatePickerSpinnerDelegate.java
@@ -33,14 +33,14 @@
import android.widget.DatePicker.AbstractDatePickerDelegate;
import android.widget.NumberPicker.OnValueChangeListener;
+import libcore.icu.ICU;
+
import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Locale;
-import libcore.icu.ICU;
-
/**
* A delegate implementing the basic DatePicker
*/
diff --git a/core/java/android/widget/DayPickerPagerAdapter.java b/core/java/android/widget/DayPickerPagerAdapter.java
index f748d3a..8d5bf8f 100644
--- a/core/java/android/widget/DayPickerPagerAdapter.java
+++ b/core/java/android/widget/DayPickerPagerAdapter.java
@@ -16,9 +16,6 @@
package android.widget;
-import android.graphics.Rect;
-import com.android.internal.widget.PagerAdapter;
-
import android.annotation.IdRes;
import android.annotation.LayoutRes;
import android.annotation.NonNull;
@@ -26,6 +23,7 @@
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
+import android.graphics.Rect;
import android.icu.util.Calendar;
import android.util.SparseArray;
import android.view.LayoutInflater;
@@ -33,6 +31,8 @@
import android.view.ViewGroup;
import android.widget.SimpleMonthView.OnDayClickListener;
+import com.android.internal.widget.PagerAdapter;
+
/**
* An adapter for a list of {@link android.widget.SimpleMonthView} items.
*/
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index 0c02a2b..919c1e2 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -18,15 +18,11 @@
import static android.os.Build.VERSION_CODES.N_MR1;
-import android.graphics.Rect;
-import com.android.internal.R;
-import com.android.internal.widget.ViewPager;
-import com.android.internal.widget.ViewPager.OnPageChangeListener;
-
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
+import android.graphics.Rect;
import android.icu.util.Calendar;
import android.util.AttributeSet;
import android.util.MathUtils;
@@ -35,10 +31,14 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
-import java.util.Locale;
+import com.android.internal.R;
+import com.android.internal.widget.ViewPager;
+import com.android.internal.widget.ViewPager.OnPageChangeListener;
import libcore.icu.LocaleData;
+import java.util.Locale;
+
class DayPickerView extends ViewGroup {
private static final int DEFAULT_LAYOUT = R.layout.day_picker_content_material;
private static final int DEFAULT_START_YEAR = 1900;
diff --git a/core/java/android/widget/DayPickerViewPager.java b/core/java/android/widget/DayPickerViewPager.java
index 5f0ae29..94022ae 100644
--- a/core/java/android/widget/DayPickerViewPager.java
+++ b/core/java/android/widget/DayPickerViewPager.java
@@ -16,17 +16,12 @@
package android.widget;
-import android.annotation.Nullable;
import android.content.Context;
-import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
import com.android.internal.util.Predicate;
-import com.android.internal.widget.PagerAdapter;
import com.android.internal.widget.ViewPager;
import java.util.ArrayList;
diff --git a/core/java/android/widget/DialerFilter.java b/core/java/android/widget/DialerFilter.java
index e37e3ba7..8f9c96c 100644
--- a/core/java/android/widget/DialerFilter.java
+++ b/core/java/android/widget/DialerFilter.java
@@ -17,7 +17,7 @@
package android.widget;
import android.content.Context;
-import android.view.KeyEvent;
+import android.graphics.Rect;
import android.text.Editable;
import android.text.InputFilter;
import android.text.Selection;
@@ -28,8 +28,8 @@
import android.text.method.KeyListener;
import android.text.method.TextKeyListener;
import android.util.AttributeSet;
+import android.view.KeyEvent;
import android.view.View;
-import android.graphics.Rect;
/**
* This widget is a layout that contains several specifically-named child views that
@@ -169,7 +169,7 @@
// Only check to see if the digit is valid if the key is a printing key
// in the TextKeyListener. This prevents us from hiding the digits
// line when keys like UP and DOWN are hit.
- // XXX note that KEYCODE_TAB is special-cased here for
+ // XXX note that KEYCODE_TAB is special-cased here for
// devices that share tab and 0 on a single key.
boolean isPrint = event.isPrintingKey();
if (isPrint || keyCode == KeyEvent.KEYCODE_SPACE
diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java
index 1df1643..c503ef2 100644
--- a/core/java/android/widget/DigitalClock.java
+++ b/core/java/android/widget/DigitalClock.java
@@ -23,6 +23,7 @@
import android.provider.Settings;
import android.text.format.DateFormat;
import android.util.AttributeSet;
+
import java.util.Calendar;
/**
diff --git a/core/java/android/widget/DropDownListView.java b/core/java/android/widget/DropDownListView.java
index 69e4218..e9c4728 100644
--- a/core/java/android/widget/DropDownListView.java
+++ b/core/java/android/widget/DropDownListView.java
@@ -17,13 +17,13 @@
package android.widget;
-import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
-
import android.annotation.NonNull;
import android.content.Context;
import android.view.MotionEvent;
import android.view.View;
+import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
+
/**
* Wrapper class for a ListView. This wrapper can hijack the focus to
* make sure the list uses the appropriate drawables and states when
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 9019f31..98d8a13 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -17,14 +17,13 @@
package android.widget;
import android.annotation.ColorInt;
+import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
-
-import android.content.Context;
-import android.graphics.Canvas;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -103,7 +102,7 @@
private int mState = STATE_IDLE;
private float mPullDistance;
-
+
private final Rect mBounds = new Rect();
private final Paint mPaint = new Paint();
private float mRadius;
diff --git a/core/java/android/widget/EditText.java b/core/java/android/widget/EditText.java
index 24d8618..a8d3984 100644
--- a/core/java/android/widget/EditText.java
+++ b/core/java/android/widget/EditText.java
@@ -17,7 +17,6 @@
package android.widget;
import android.content.Context;
-import android.os.Bundle;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index fac36c5..8d9848d 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -16,7 +16,7 @@
package android.widget;
-import com.android.internal.R;
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
import android.content.Context;
import android.content.res.TypedArray;
@@ -27,14 +27,14 @@
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
import android.view.SoundEffectConstants;
import android.view.View;
-import android.view.ContextMenu.ContextMenuInfo;
import android.widget.ExpandableListConnector.PositionMetadata;
-import java.util.ArrayList;
+import com.android.internal.R;
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+import java.util.ArrayList;
/**
* A view that shows items in a vertically scrolling two-level list. This
@@ -68,7 +68,7 @@
* wrap_content since it also can be any length. However, you can use
* wrap_content if the ExpandableListView parent has a specific size, such as
* 100 pixels.
- *
+ *
* @attr ref android.R.styleable#ExpandableListView_groupIndicator
* @attr ref android.R.styleable#ExpandableListView_indicatorLeft
* @attr ref android.R.styleable#ExpandableListView_indicatorRight
@@ -87,7 +87,7 @@
* The packed position represents a group.
*/
public static final int PACKED_POSITION_TYPE_GROUP = 0;
-
+
/**
* The packed position represents a child.
*/
@@ -97,14 +97,14 @@
* The packed position represents a neither/null/no preference.
*/
public static final int PACKED_POSITION_TYPE_NULL = 2;
-
+
/**
* The value for a packed position that represents neither/null/no
* preference. This value is not otherwise possible since a group type
* (first bit 0) should not have a child position filled.
*/
public static final long PACKED_POSITION_VALUE_NULL = 0x00000000FFFFFFFFL;
-
+
/** The mask (in packed position representation) for the child */
private static final long PACKED_POSITION_MASK_CHILD = 0x00000000FFFFFFFFL;
@@ -125,13 +125,13 @@
/** The mask (in integer group position representation) for the group */
private static final long PACKED_POSITION_INT_MASK_GROUP = 0x7FFFFFFF;
-
+
/** Serves as the glue/translator between a ListView and an ExpandableListView */
private ExpandableListConnector mConnector;
-
- /** Gives us Views through group+child positions */
+
+ /** Gives us Views through group+child positions */
private ExpandableListAdapter mAdapter;
-
+
/** Left bound for drawing the indicator. */
private int mIndicatorLeft;
@@ -210,7 +210,7 @@
/** State indicating the child is the last within its group. */
private static final int[] CHILD_LAST_STATE_SET =
{R.attr.state_last};
-
+
/** Drawable to be used as a divider when it is adjacent to any children */
private Drawable mChildDivider;
@@ -367,16 +367,16 @@
}
final int headerViewsCount = getHeaderViewsCount();
-
+
final int lastChildFlPos = mItemCount - getFooterViewsCount() - headerViewsCount - 1;
- final int myB = mBottom;
-
+ final int myB = mBottom;
+
PositionMetadata pos;
View item;
- Drawable indicator;
+ Drawable indicator;
int t, b;
-
+
// Start at a value that is neither child nor group
int lastItemType = ~(ExpandableListPosition.CHILD | ExpandableListPosition.GROUP);
@@ -385,7 +385,7 @@
// The "child" mentioned in the following two lines is this
// View's child, not referring to an expandable list's
// notion of a child (as opposed to a group)
- final int childCount = getChildCount();
+ final int childCount = getChildCount();
for (int i = 0, childFlPos = mFirstPosition - headerViewsCount; i < childCount;
i++, childFlPos++) {
@@ -396,11 +396,11 @@
// This child is footer, so are all subsequent children
break;
}
-
+
item = getChildAt(i);
t = item.getTop();
b = item.getBottom();
-
+
// This item isn't on the screen
if ((b < 0) || (t > myB)) continue;
@@ -435,7 +435,7 @@
indicatorRect.right += mPaddingLeft;
}
- lastItemType = pos.position.type;
+ lastItemType = pos.position.type;
}
if (indicatorRect.left != indicatorRect.right) {
@@ -448,7 +448,7 @@
indicatorRect.top = t;
indicatorRect.bottom = b;// + mDividerHeight;
}
-
+
// Get the indicator (with its state set to the item's state)
indicator = getIndicator(pos);
if (indicator != null) {
@@ -468,24 +468,24 @@
/**
* Gets the indicator for the item at the given position. If the indicator
* is stateful, the state will be given to the indicator.
- *
+ *
* @param pos The flat list position of the item whose indicator
* should be returned.
* @return The indicator in the proper state.
*/
private Drawable getIndicator(PositionMetadata pos) {
Drawable indicator;
-
+
if (pos.position.type == ExpandableListPosition.GROUP) {
indicator = mGroupIndicator;
-
+
if (indicator != null && indicator.isStateful()) {
// Empty check based on availability of data. If the groupMetadata isn't null,
// we do a check on it. Otherwise, the group is collapsed so we consider it
// empty for performance reasons.
boolean isEmpty = (pos.groupMetadata == null) ||
(pos.groupMetadata.lastChildFlPos == pos.groupMetadata.flPos);
-
+
final int stateSetIndex =
(pos.isExpanded() ? 1 : 0) | // Expanded?
(isEmpty ? 2 : 0); // Empty?
@@ -493,7 +493,7 @@
}
} else {
indicator = mChildIndicator;
-
+
if (indicator != null && indicator.isStateful()) {
// No need for a state sets array for the child since it only has two states
final int stateSet[] = pos.position.flatListPos == pos.groupMetadata.lastChildFlPos
@@ -502,15 +502,15 @@
indicator.setState(stateSet);
}
}
-
+
return indicator;
}
-
+
/**
* Sets the drawable that will be drawn adjacent to every child in the list. This will
* be drawn using the same height as the normal divider ({@link #setDivider(Drawable)}) or
* if it does not have an intrinsic height, the height set by {@link #setDividerHeight(int)}.
- *
+ *
* @param childDivider The drawable to use.
*/
public void setChildDivider(Drawable childDivider) {
@@ -520,7 +520,7 @@
@Override
void drawDivider(Canvas canvas, Rect bounds, int childIndex) {
int flatListPosition = childIndex + mFirstPosition;
-
+
// Only proceed as possible child if the divider isn't above all items (if it is above
// all items, then the item below it has to be a group)
if (flatListPosition >= 0) {
@@ -538,7 +538,7 @@
}
pos.recycle();
}
-
+
// Otherwise draw the default divider
super.drawDivider(canvas, bounds, flatListPosition);
}
@@ -589,18 +589,18 @@
public void setAdapter(ExpandableListAdapter adapter) {
// Set member variable
mAdapter = adapter;
-
+
if (adapter != null) {
// Create the connector
mConnector = new ExpandableListConnector(adapter);
} else {
mConnector = null;
}
-
+
// Link the ListView (superclass) to the expandable list data through the connector
super.setAdapter(mConnector);
}
-
+
/**
* Gets the adapter that provides data to this view.
* @return The adapter that provides data to this view.
@@ -608,7 +608,7 @@
public ExpandableListAdapter getExpandableListAdapter() {
return mAdapter;
}
-
+
/**
* @param position An absolute (including header and footer) flat list position.
* @return true if the position corresponds to a header or a footer item.
@@ -621,7 +621,7 @@
/**
* Converts an absolute item flat position into a group/child flat position, shifting according
* to the number of header items.
- *
+ *
* @param flatListPosition The absolute flat position
* @return A group/child flat position as expected by the connector.
*/
@@ -632,7 +632,7 @@
/**
* Converts a group/child flat position into an absolute flat position, that takes into account
* the possible headers.
- *
+ *
* @param flatListPosition The child/group flat position
* @return An absolute flat position.
*/
@@ -647,25 +647,25 @@
// Clicked on a header/footer, so ignore pass it on to super
return super.performItemClick(v, position, id);
}
-
+
// Internally handle the item click
final int adjustedPosition = getFlatPositionForConnector(position);
return handleItemClick(v, adjustedPosition, id);
}
-
+
/**
* This will either expand/collapse groups (if a group was clicked) or pass
* on the click to the proper child (if a child was clicked)
- *
+ *
* @param position The flat list position. This has already been factored to
* remove the header/footer.
* @param id The ListAdapter ID, not the group or child ID.
*/
boolean handleItemClick(View v, int position, long id) {
final PositionMetadata posMetadata = mConnector.getUnflattenedPos(position);
-
+
id = getChildOrGroupId(posMetadata.position);
-
+
boolean returnValue;
if (posMetadata.position.type == ExpandableListPosition.GROUP) {
/* It's a group, so handle collapsing/expanding */
@@ -697,11 +697,11 @@
if (mOnGroupExpandListener != null) {
mOnGroupExpandListener.onGroupExpand(posMetadata.position.groupPos);
}
-
+
final int groupPos = posMetadata.position.groupPos;
final int groupFlatPos = posMetadata.position.flatListPos;
- final int shiftedGroupPosition = groupFlatPos + getHeaderViewsCount();
+ final int shiftedGroupPosition = groupFlatPos + getHeaderViewsCount();
smoothScrollToPosition(shiftedGroupPosition + mAdapter.getChildrenCount(groupPos),
shiftedGroupPosition);
}
@@ -764,17 +764,17 @@
return retValue;
}
-
+
/**
* Collapse a group in the grouped list view
- *
+ *
* @param groupPos position of the group to collapse
* @return True if the group was collapsed, false otherwise (if the group
* was already collapsed, this will return false)
*/
public boolean collapseGroup(int groupPos) {
boolean retValue = mConnector.collapseGroup(groupPos);
-
+
if (mOnGroupCollapseListener != null) {
mOnGroupCollapseListener.onGroupCollapse(groupPos);
}
@@ -787,14 +787,14 @@
/**
* Callback method to be invoked when a group in this expandable list has
* been collapsed.
- *
+ *
* @param groupPosition The group position that was collapsed
*/
void onGroupCollapse(int groupPosition);
}
-
+
private OnGroupCollapseListener mOnGroupCollapseListener;
-
+
public void setOnGroupCollapseListener(
OnGroupCollapseListener onGroupCollapseListener) {
mOnGroupCollapseListener = onGroupCollapseListener;
@@ -805,14 +805,14 @@
/**
* Callback method to be invoked when a group in this expandable list has
* been expanded.
- *
+ *
* @param groupPosition The group position that was expanded
*/
void onGroupExpand(int groupPosition);
}
-
+
private OnGroupExpandListener mOnGroupExpandListener;
-
+
public void setOnGroupExpandListener(
OnGroupExpandListener onGroupExpandListener) {
mOnGroupExpandListener = onGroupExpandListener;
@@ -826,7 +826,7 @@
/**
* Callback method to be invoked when a group in this expandable list has
* been clicked.
- *
+ *
* @param parent The ExpandableListConnector where the click happened
* @param v The view within the expandable list/ListView that was clicked
* @param groupPosition The group position that was clicked
@@ -836,13 +836,13 @@
boolean onGroupClick(ExpandableListView parent, View v, int groupPosition,
long id);
}
-
+
private OnGroupClickListener mOnGroupClickListener;
public void setOnGroupClickListener(OnGroupClickListener onGroupClickListener) {
mOnGroupClickListener = onGroupClickListener;
}
-
+
/**
* Interface definition for a callback to be invoked when a child in this
* expandable list has been clicked.
@@ -851,7 +851,7 @@
/**
* Callback method to be invoked when a child in this expandable list has
* been clicked.
- *
+ *
* @param parent The ExpandableListView where the click happened
* @param v The view within the expandable list/ListView that was clicked
* @param groupPosition The group position that contains the child that
@@ -863,13 +863,13 @@
boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id);
}
-
+
private OnChildClickListener mOnChildClickListener;
public void setOnChildClickListener(OnChildClickListener onChildClickListener) {
mOnChildClickListener = onChildClickListener;
}
-
+
/**
* Converts a flat list position (the raw position of an item (child or group)
* in the list) to a group and/or child position (represented in a
@@ -878,7 +878,7 @@
* {@link ExpandableListView#getPackedPositionType} ,
* {@link ExpandableListView#getPackedPositionChild},
* {@link ExpandableListView#getPackedPositionGroup} to unpack.
- *
+ *
* @param flatListPosition The flat list position to be converted.
* @return The group and/or child position for the given flat list position
* in packed position representation. #PACKED_POSITION_VALUE_NULL if
@@ -895,12 +895,12 @@
pm.recycle();
return packedPos;
}
-
+
/**
* Converts a group and/or child position to a flat list position. This is
* useful in situations where the caller needs to use the underlying
* {@link ListView}'s methods.
- *
+ *
* @param packedPosition The group and/or child positions to be converted in
* packed position representation. Use
* {@link #getPackedPositionForChild(int, int)} or
@@ -920,7 +920,7 @@
/**
* Gets the position of the currently selected group or child (along with
* its type). Can return {@link #PACKED_POSITION_VALUE_NULL} if no selection.
- *
+ *
* @return A packed position containing the currently selected group or
* child's position and type. #PACKED_POSITION_VALUE_NULL if no selection
* or if selection is on a header or a footer item.
@@ -931,11 +931,11 @@
// The case where there is no selection (selectedPos == -1) is also handled here.
return getExpandableListPosition(selectedPos);
}
-
+
/**
* Gets the ID of the currently selected group or child. Can return -1 if no
* selection.
- *
+ *
* @return The ID of the currently selected group or child. -1 if no
* selection.
*/
@@ -944,7 +944,7 @@
if (packedPos == PACKED_POSITION_VALUE_NULL) return -1;
int groupPos = getPackedPositionGroup(packedPos);
-
+
if (getPackedPositionType(packedPos) == PACKED_POSITION_TYPE_GROUP) {
// It's a group
return mAdapter.getGroupId(groupPos);
@@ -953,7 +953,7 @@
return mAdapter.getChildId(groupPos, getPackedPositionChild(packedPos));
}
}
-
+
/**
* Sets the selection to the specified group.
* @param groupPosition The position of the group that should be selected.
@@ -967,12 +967,12 @@
super.setSelection(absoluteFlatPosition);
pm.recycle();
}
-
+
/**
* Sets the selection to the specified child. If the child is in a collapsed
* group, the group will only be expanded and child subsequently selected if
* shouldExpandGroup is set to true, otherwise the method will return false.
- *
+ *
* @param groupPosition The position of the group that contains the child.
* @param childPosition The position of the child within the group.
* @param shouldExpandGroup Whether the child's group should be expanded if
@@ -981,48 +981,48 @@
*/
public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) {
ExpandableListPosition elChildPos = ExpandableListPosition.obtainChildPosition(
- groupPosition, childPosition);
+ groupPosition, childPosition);
PositionMetadata flatChildPos = mConnector.getFlattenedPos(elChildPos);
-
+
if (flatChildPos == null) {
// The child's group isn't expanded
-
+
// Shouldn't expand the group, so return false for we didn't set the selection
- if (!shouldExpandGroup) return false;
+ if (!shouldExpandGroup) return false;
expandGroup(groupPosition);
-
+
flatChildPos = mConnector.getFlattenedPos(elChildPos);
-
+
// Sanity check
if (flatChildPos == null) {
throw new IllegalStateException("Could not find child");
}
}
-
+
int absoluteFlatPosition = getAbsoluteFlatPosition(flatChildPos.position.flatListPos);
super.setSelection(absoluteFlatPosition);
-
+
elChildPos.recycle();
flatChildPos.recycle();
-
+
return true;
}
/**
* Whether the given group is currently expanded.
- *
+ *
* @param groupPosition The group to check.
* @return Whether the group is currently expanded.
*/
public boolean isGroupExpanded(int groupPosition) {
return mConnector.isGroupExpanded(groupPosition);
}
-
+
/**
* Gets the type of a packed position. See
* {@link #getPackedPositionForChild(int, int)}.
- *
+ *
* @param packedPosition The packed position for which to return the type.
* @return The type of the position contained within the packed position,
* either {@link #PACKED_POSITION_TYPE_CHILD}, {@link #PACKED_POSITION_TYPE_GROUP}, or
@@ -1032,7 +1032,7 @@
if (packedPosition == PACKED_POSITION_VALUE_NULL) {
return PACKED_POSITION_TYPE_NULL;
}
-
+
return (packedPosition & PACKED_POSITION_MASK_TYPE) == PACKED_POSITION_MASK_TYPE
? PACKED_POSITION_TYPE_CHILD
: PACKED_POSITION_TYPE_GROUP;
@@ -1041,7 +1041,7 @@
/**
* Gets the group position from a packed position. See
* {@link #getPackedPositionForChild(int, int)}.
- *
+ *
* @param packedPosition The packed position from which the group position
* will be returned.
* @return The group position portion of the packed position. If this does
@@ -1050,7 +1050,7 @@
public static int getPackedPositionGroup(long packedPosition) {
// Null
if (packedPosition == PACKED_POSITION_VALUE_NULL) return -1;
-
+
return (int) ((packedPosition & PACKED_POSITION_MASK_GROUP) >> PACKED_POSITION_SHIFT_GROUP);
}
@@ -1060,7 +1060,7 @@
* To get the group that this child belongs to, use
* {@link #getPackedPositionGroup(long)}. See
* {@link #getPackedPositionForChild(int, int)}.
- *
+ *
* @param packedPosition The packed position from which the child position
* will be returned.
* @return The child position portion of the packed position. If this does
@@ -1069,7 +1069,7 @@
public static int getPackedPositionChild(long packedPosition) {
// Null
if (packedPosition == PACKED_POSITION_VALUE_NULL) return -1;
-
+
// Group since a group type clears this bit
if ((packedPosition & PACKED_POSITION_MASK_TYPE) != PACKED_POSITION_MASK_TYPE) return -1;
@@ -1087,7 +1087,7 @@
* {@link #getPackedPositionChild(long)},
* {@link #getPackedPositionGroup(long)}, and
* {@link #getPackedPositionType(long)}.
- *
+ *
* @param groupPosition The child's parent group's position.
* @param childPosition The child position within the group.
* @return The packed position representation of the child (and parent group).
@@ -1096,20 +1096,20 @@
return (((long)PACKED_POSITION_TYPE_CHILD) << PACKED_POSITION_SHIFT_TYPE)
| ((((long)groupPosition) & PACKED_POSITION_INT_MASK_GROUP)
<< PACKED_POSITION_SHIFT_GROUP)
- | (childPosition & PACKED_POSITION_INT_MASK_CHILD);
+ | (childPosition & PACKED_POSITION_INT_MASK_CHILD);
}
/**
* Returns the packed position representation of a group's position. See
* {@link #getPackedPositionForChild(int, int)}.
- *
+ *
* @param groupPosition The child's parent group's position.
* @return The packed position representation of the group.
*/
public static long getPackedPositionForGroup(int groupPosition) {
// No need to OR a type in because PACKED_POSITION_GROUP == 0
return ((((long)groupPosition) & PACKED_POSITION_INT_MASK_GROUP)
- << PACKED_POSITION_SHIFT_GROUP);
+ << PACKED_POSITION_SHIFT_GROUP);
}
@Override
@@ -1122,12 +1122,12 @@
final int adjustedPosition = getFlatPositionForConnector(flatListPosition);
PositionMetadata pm = mConnector.getUnflattenedPos(adjustedPosition);
ExpandableListPosition pos = pm.position;
-
+
id = getChildOrGroupId(pos);
long packedPosition = pos.getPackedPosition();
pm.recycle();
-
+
return new ExpandableListContextMenuInfo(view, packedPosition, id);
}
@@ -1135,7 +1135,7 @@
* Gets the ID of the group or child at the given <code>position</code>.
* This is useful since there is no ListAdapter ID -> ExpandableListAdapter
* ID conversion mechanism (in some cases, it isn't possible).
- *
+ *
* @param position The position of the child or group whose ID should be
* returned.
*/
@@ -1146,10 +1146,10 @@
return mAdapter.getGroupId(position.groupPos);
}
}
-
+
/**
* Sets the indicator to be drawn next to a child.
- *
+ *
* @param childIndicator The drawable to be used as an indicator. If the
* child is the last child for a group, the state
* {@link android.R.attr#state_last} will be set.
@@ -1157,7 +1157,7 @@
public void setChildIndicator(Drawable childIndicator) {
mChildIndicator = childIndicator;
}
-
+
/**
* Sets the drawing bounds for the child indicator. For either, you can
* specify {@link #CHILD_INDICATOR_INHERIT} to use inherit from the general
@@ -1194,7 +1194,7 @@
/**
* Sets the indicator to be drawn next to a group.
- *
+ *
* @param groupIndicator The drawable to be used as an indicator. If the
* group is empty, the state {@link android.R.attr#state_empty} will be
* set. If the group is expanded, the state
@@ -1211,8 +1211,8 @@
* Sets the drawing bounds for the indicators (at minimum, the group indicator
* is affected by this; the child indicator is affected by this if the
* child indicator bounds are set to inherit).
- *
- * @see #setChildIndicatorBounds(int, int)
+ *
+ * @see #setChildIndicatorBounds(int, int)
* @param left The left position (relative to the left bounds of this View)
* to start drawing the indicator.
* @param right The right position (relative to the left bounds of this
@@ -1248,13 +1248,13 @@
* callback when a context menu is brought up for this AdapterView.
*/
public static class ExpandableListContextMenuInfo implements ContextMenu.ContextMenuInfo {
-
+
public ExpandableListContextMenuInfo(View targetView, long packedPosition, long id) {
this.targetView = targetView;
this.packedPosition = packedPosition;
this.id = id;
}
-
+
/**
* The view for which the context menu is being displayed. This
* will be one of the children Views of this {@link ExpandableListView}.
@@ -1276,10 +1276,10 @@
*/
public long id;
}
-
+
static class SavedState extends BaseSavedState {
ArrayList<ExpandableListConnector.GroupMetadata> expandedGroupMetadataList;
-
+
/**
* Constructor called from {@link ExpandableListView#onSaveInstanceState()}
*/
@@ -1333,7 +1333,7 @@
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
-
+
if (mConnector != null && ss.expandedGroupMetadataList != null) {
mConnector.setExpandedGroupMetadataList(ss.expandedGroupMetadataList);
}
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index b8c74d8..dc8ee01 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,6 +32,8 @@
import android.view.ViewHierarchyEncoder;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
+
import java.util.ArrayList;
/**
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index af2852c..1c15c7a 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -16,6 +16,20 @@
package android.widget;
+import static android.view.Gravity.AXIS_PULL_AFTER;
+import static android.view.Gravity.AXIS_PULL_BEFORE;
+import static android.view.Gravity.AXIS_SPECIFIED;
+import static android.view.Gravity.AXIS_X_SHIFT;
+import static android.view.Gravity.AXIS_Y_SHIFT;
+import static android.view.Gravity.HORIZONTAL_GRAVITY_MASK;
+import static android.view.Gravity.RELATIVE_LAYOUT_DIRECTION;
+import static android.view.Gravity.VERTICAL_GRAVITY_MASK;
+import static android.view.View.MeasureSpec.EXACTLY;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
+import static java.lang.Math.max;
+import static java.lang.Math.min;
+
import android.annotation.IntDef;
import android.content.Context;
import android.content.res.TypedArray;
@@ -32,6 +46,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.RemoteViews.RemoteView;
+
import com.android.internal.R;
import java.lang.annotation.Retention;
@@ -43,12 +58,6 @@
import java.util.List;
import java.util.Map;
-import static android.view.Gravity.*;
-import static android.view.View.MeasureSpec.EXACTLY;
-import static android.view.View.MeasureSpec.makeMeasureSpec;
-import static java.lang.Math.max;
-import static java.lang.Math.min;
-
/**
* A layout that places its children in a rectangular <em>grid</em>.
* <p>
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index b95aa52..20543fb 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -36,9 +36,9 @@
import android.view.ViewRootImpl;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
+import android.view.accessibility.AccessibilityNodeProvider;
import android.view.animation.GridLayoutAnimationController;
import android.widget.RemoteViews.RemoteView;
@@ -54,7 +54,7 @@
*
* <p>See the <a href="{@docRoot}guide/topics/ui/layout/gridview.html">Grid
* View</a> guide.</p>
- *
+ *
* @attr ref android.R.styleable#GridView_horizontalSpacing
* @attr ref android.R.styleable#GridView_verticalSpacing
* @attr ref android.R.styleable#GridView_stretchMode
@@ -71,33 +71,33 @@
/**
* Disables stretching.
- *
- * @see #setStretchMode(int)
+ *
+ * @see #setStretchMode(int)
*/
public static final int NO_STRETCH = 0;
/**
* Stretches the spacing between columns.
- *
- * @see #setStretchMode(int)
+ *
+ * @see #setStretchMode(int)
*/
public static final int STRETCH_SPACING = 1;
/**
* Stretches columns.
- *
- * @see #setStretchMode(int)
+ *
+ * @see #setStretchMode(int)
*/
public static final int STRETCH_COLUMN_WIDTH = 2;
/**
* Stretches the spacing between columns. The spacing is uniform.
- *
- * @see #setStretchMode(int)
+ *
+ * @see #setStretchMode(int)
*/
public static final int STRETCH_SPACING_UNIFORM = 3;
/**
* Creates as many columns as can fit on screen.
- *
- * @see #setNumColumns(int)
+ *
+ * @see #setNumColumns(int)
*/
public static final int AUTO_FIT = -1;
@@ -161,7 +161,7 @@
if (index >= 0) {
setGravity(index);
}
-
+
a.recycle();
}
@@ -192,7 +192,7 @@
}
resetList();
- mRecycler.clear();
+ mRecycler.clear();
mAdapter = adapter;
mOldSelectedPosition = INVALID_POSITION;
@@ -222,7 +222,7 @@
setNextSelectedPositionInt(position);
checkSelectionChanged();
} else {
- checkFocus();
+ checkFocus();
// Nothing selected
checkSelectionChanged();
}
@@ -376,7 +376,7 @@
}
mReferenceView = child;
-
+
if (selectedView != null) {
mReferenceViewInSelectedRow = mReferenceView;
}
@@ -515,7 +515,7 @@
offsetChildrenTopAndBottom(offset);
}
}
- }
+ }
@Override
int findMotionRow(int y) {
@@ -624,7 +624,7 @@
// This is how far the bottom edge of the last view is from the bottom of the
// drawable area
- int bottomOffset = end - lastBottom;
+ int bottomOffset = end - lastBottom;
final View firstChild = getChildAt(0);
final int firstTop = firstChild.getTop();
@@ -636,7 +636,7 @@
// Don't pull the top too far down
bottomOffset = Math.min(bottomOffset, mListPadding.top - firstTop);
}
-
+
// Move everything down
offsetChildrenTopAndBottom(bottomOffset);
if (mFirstPosition > 0) {
@@ -679,7 +679,7 @@
// Don't pull the bottom too far up
topOffset = Math.min(topOffset, lastBottom - end);
}
-
+
// Move everything up
offsetChildrenTopAndBottom(-topOffset);
if (lastPosition < mItemCount - 1) {
@@ -965,7 +965,7 @@
final int stretchMode = mStretchMode;
final int requestedColumnWidth = mRequestedColumnWidth;
boolean didNotInitiallyFit = false;
-
+
if (mRequestedNumColumns == AUTO_FIT) {
if (requestedColumnWidth > 0) {
// Client told us to pick the number of columns
@@ -979,57 +979,57 @@
// We picked the columns
mNumColumns = mRequestedNumColumns;
}
-
+
if (mNumColumns <= 0) {
mNumColumns = 1;
}
switch (stretchMode) {
- case NO_STRETCH:
- // Nobody stretches
- mColumnWidth = requestedColumnWidth;
- mHorizontalSpacing = requestedHorizontalSpacing;
- break;
-
- default:
- int spaceLeftOver = availableSpace - (mNumColumns * requestedColumnWidth) -
- ((mNumColumns - 1) * requestedHorizontalSpacing);
-
- if (spaceLeftOver < 0) {
- didNotInitiallyFit = true;
- }
-
- switch (stretchMode) {
- case STRETCH_COLUMN_WIDTH:
- // Stretch the columns
- mColumnWidth = requestedColumnWidth + spaceLeftOver / mNumColumns;
+ case NO_STRETCH:
+ // Nobody stretches
+ mColumnWidth = requestedColumnWidth;
mHorizontalSpacing = requestedHorizontalSpacing;
break;
- case STRETCH_SPACING:
- // Stretch the spacing between columns
- mColumnWidth = requestedColumnWidth;
- if (mNumColumns > 1) {
- mHorizontalSpacing = requestedHorizontalSpacing +
- spaceLeftOver / (mNumColumns - 1);
- } else {
- mHorizontalSpacing = requestedHorizontalSpacing + spaceLeftOver;
- }
- break;
+ default:
+ int spaceLeftOver = availableSpace - (mNumColumns * requestedColumnWidth)
+ - ((mNumColumns - 1) * requestedHorizontalSpacing);
- case STRETCH_SPACING_UNIFORM:
- // Stretch the spacing between columns
- mColumnWidth = requestedColumnWidth;
- if (mNumColumns > 1) {
- mHorizontalSpacing = requestedHorizontalSpacing +
- spaceLeftOver / (mNumColumns + 1);
- } else {
- mHorizontalSpacing = requestedHorizontalSpacing + spaceLeftOver;
+ if (spaceLeftOver < 0) {
+ didNotInitiallyFit = true;
}
- break;
- }
- break;
+ switch (stretchMode) {
+ case STRETCH_COLUMN_WIDTH:
+ // Stretch the columns
+ mColumnWidth = requestedColumnWidth + spaceLeftOver / mNumColumns;
+ mHorizontalSpacing = requestedHorizontalSpacing;
+ break;
+
+ case STRETCH_SPACING:
+ // Stretch the spacing between columns
+ mColumnWidth = requestedColumnWidth;
+ if (mNumColumns > 1) {
+ mHorizontalSpacing = requestedHorizontalSpacing
+ + spaceLeftOver / (mNumColumns - 1);
+ } else {
+ mHorizontalSpacing = requestedHorizontalSpacing + spaceLeftOver;
+ }
+ break;
+
+ case STRETCH_SPACING_UNIFORM:
+ // Stretch the spacing between columns
+ mColumnWidth = requestedColumnWidth;
+ if (mNumColumns > 1) {
+ mHorizontalSpacing = requestedHorizontalSpacing
+ + spaceLeftOver / (mNumColumns + 1);
+ } else {
+ mHorizontalSpacing = requestedHorizontalSpacing + spaceLeftOver;
+ }
+ break;
+ }
+
+ break;
}
return didNotInitiallyFit;
}
@@ -1052,7 +1052,7 @@
}
widthSize += getVerticalScrollbarWidth();
}
-
+
int childWidth = widthSize - mListPadding.left - mListPadding.right;
boolean didNotInitiallyFit = determineColumns(childWidth);
@@ -1087,7 +1087,7 @@
mRecycler.addScrapView(child, -1);
}
}
-
+
if (heightMode == MeasureSpec.UNSPECIFIED) {
heightSize = mListPadding.top + mListPadding.bottom + childHeight +
getVerticalFadingEdgeLength() * 2;
@@ -1095,7 +1095,7 @@
if (heightMode == MeasureSpec.AT_MOST) {
int ourSize = mListPadding.top + mListPadding.bottom;
-
+
final int numColumns = mNumColumns;
for (int i = 0; i < count; i += numColumns) {
ourSize += childHeight;
@@ -1574,9 +1574,9 @@
/**
* Sets the currently selected item
- *
+ *
* @param position Index (starting at 0) of the data item to be selected.
- *
+ *
* If in touch mode, the item will not be selected but it will still be positioned
* appropriately.
*/
@@ -1609,8 +1609,8 @@
setNextSelectedPositionInt(position);
layoutChildren();
-
- final int next = mStackFromBottom ? mItemCount - 1 - mNextSelectedPosition :
+
+ final int next = mStackFromBottom ? mItemCount - 1 - mNextSelectedPosition :
mNextSelectedPosition;
final int previous = mStackFromBottom ? mItemCount - 1
- previousSelectedPosition : previousSelectedPosition;
@@ -1802,7 +1802,7 @@
invokeOnItemScrollListener();
moved = true;
}
-
+
if (moved) {
awakenScrollBars();
}
@@ -1874,7 +1874,7 @@
if (moved) {
awakenScrollBars();
}
-
+
return moved;
}
@@ -2216,17 +2216,17 @@
requestLayoutIfNecessary();
}
}
-
+
/**
- * Get the number of columns in the grid.
+ * Get the number of columns in the grid.
* Returns {@link #AUTO_FIT} if the Grid has never been laid out.
*
* @attr ref android.R.styleable#GridView_numColumns
- *
+ *
* @see #setNumColumns(int)
*/
@ViewDebug.ExportedProperty
- public int getNumColumns() {
+ public int getNumColumns() {
return mNumColumns;
}
@@ -2259,13 +2259,13 @@
// we are too high, slide all views down to align with bottom
child = getChildAt(childCount - 1);
delta = child.getBottom() - (getHeight() - mListPadding.bottom);
-
+
if (mFirstPosition + childCount < mItemCount) {
// It's OK to have some space below the last item if it is
// part of the vertical spacing
delta += mVerticalSpacing;
}
-
+
if (delta > 0) {
// We only are looking to see if we are too high, not too low
delta = 0;
@@ -2277,14 +2277,14 @@
}
}
}
-
+
@Override
protected int computeVerticalScrollExtent() {
final int count = getChildCount();
if (count > 0) {
final int numColumns = mNumColumns;
final int rowCount = (count + numColumns - 1) / numColumns;
-
+
int extent = rowCount * 100;
View view = getChildAt(0);
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index d9cb269..4d405c5 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -467,6 +467,14 @@
* {@link #setImageBitmap(android.graphics.Bitmap)} and
* {@link android.graphics.BitmapFactory} instead.</p>
*
+ * <p class="note">On devices running SDK < 24, this method will fail to
+ * apply correct density scaling to images loaded from
+ * {@link ContentResolver#SCHEME_CONTENT content} and
+ * {@link ContentResolver#SCHEME_FILE file} schemes. Applications running
+ * on devices with SDK >= 24 <strong>MUST</strong> specify the
+ * {@code targetSdkVersion} in their manifest as 24 or above for density
+ * scaling to be applied to images loaded from these schemes.</p>
+ *
* @param uri the Uri of an image, or {@code null} to clear the content
*/
@android.view.RemotableViewMethod(asyncImpl="setImageURIAsync")
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 6511de8..544e591 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -34,15 +32,17 @@
import android.view.ViewHierarchyEncoder;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * A Layout that arranges its children in a single column or a single row. The direction of
- * the row can be set by calling {@link #setOrientation(int) setOrientation()}.
+ * A Layout that arranges its children in a single column or a single row. The direction of
+ * the row can be set by calling {@link #setOrientation(int) setOrientation()}.
* You can also specify gravity, which specifies the alignment of all the child elements by
- * calling {@link #setGravity(int) setGravity()} or specify that specific children
+ * calling {@link #setGravity(int) setGravity()} or specify that specific children
* grow to fill up any remaining space in the layout by setting the <em>weight</em> member of
* {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}.
* The default orientation is horizontal.
@@ -202,7 +202,7 @@
public LinearLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
-
+
public LinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
@@ -497,7 +497,7 @@
* When true, all children with a weight will be considered having
* the minimum size of the largest child. If false, all children are
* measured normally.
- *
+ *
* @return True to measure children with a weight using the minimum
* size of the largest child, false otherwise.
*
@@ -511,9 +511,9 @@
* When set to true, all children with a weight will be considered having
* the minimum size of the largest child. If false, all children are
* measured normally.
- *
+ *
* Disabled by default.
- *
+ *
* @param enabled True to measure children with a weight using the
* minimum size of the largest child, false otherwise.
*
@@ -589,7 +589,7 @@
/**
* @param i The index of the child that will be used if this layout is
* part of a larger layout that is baseline aligned.
- *
+ *
* @attr ref android.R.styleable#LinearLayout_baselineAlignedChildIndex
*/
@android.view.RemotableViewMethod
@@ -720,14 +720,14 @@
float totalWeight = 0;
final int count = getVirtualChildCount();
-
+
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
boolean matchWidth = false;
boolean skippedMeasure = false;
- final int baselineChildIndex = mBaselineAlignedChildIndex;
+ final int baselineChildIndex = mBaselineAlignedChildIndex;
final boolean useLargestChild = mUseLargestChild;
int largestChildHeight = Integer.MIN_VALUE;
@@ -886,7 +886,7 @@
// Check against our minimum height
heightSize = Math.max(heightSize, getSuggestedMinimumHeight());
-
+
// Reconcile our calculated size with the heightMeasureSpec
int heightSizeAndState = resolveSizeAndState(heightSize, heightMeasureSpec, 0);
heightSize = heightSizeAndState & MEASURED_SIZE_MASK;
@@ -991,12 +991,12 @@
if (!allFillParent && widthMode != MeasureSpec.EXACTLY) {
maxWidth = alternativeMaxWidth;
}
-
+
maxWidth += mPaddingLeft + mPaddingRight;
// Check against our minimum width
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
-
+
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
heightSizeAndState);
@@ -1013,13 +1013,13 @@
final View child = getVirtualChildAt(i);
if (child != null && child.getVisibility() != GONE) {
LinearLayout.LayoutParams lp = ((LinearLayout.LayoutParams)child.getLayoutParams());
-
+
if (lp.width == LayoutParams.MATCH_PARENT) {
// Temporarily force children to reuse their old measured height
// FIXME: this may not be right for something like wrapping text?
int oldHeight = lp.height;
lp.height = child.getMeasuredHeight();
-
+
// Remeasue with new dimensions
measureChildWithMargins(child, uniformMeasureSpec, 0, heightMeasureSpec, 0);
lp.height = oldHeight;
@@ -1037,7 +1037,7 @@
*
* @see #getOrientation()
* @see #setOrientation(int)
- * @see #onMeasure(int, int)
+ * @see #onMeasure(int, int)
*/
void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) {
mTotalLength = 0;
@@ -1049,7 +1049,7 @@
float totalWeight = 0;
final int count = getVirtualChildCount();
-
+
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
@@ -1069,7 +1069,7 @@
final boolean baselineAligned = mBaselineAligned;
final boolean useLargestChild = mUseLargestChild;
-
+
final boolean isExactly = widthMode == MeasureSpec.EXACTLY;
int largestChildWidth = Integer.MIN_VALUE;
@@ -1084,7 +1084,7 @@
mTotalLength += measureNullChild(i);
continue;
}
-
+
if (child.getVisibility() == GONE) {
i += getChildrenSkipCount(child, i);
continue;
@@ -1263,16 +1263,16 @@
// Add in our padding
mTotalLength += mPaddingLeft + mPaddingRight;
-
+
int widthSize = mTotalLength;
-
+
// Check against our minimum width
widthSize = Math.max(widthSize, getSuggestedMinimumWidth());
-
+
// Reconcile our calculated size with the widthMeasureSpec
int widthSizeAndState = resolveSizeAndState(widthSize, widthMeasureSpec, 0);
widthSize = widthSizeAndState & MEASURED_SIZE_MASK;
-
+
// Either expand children with weight to take up available space or
// shrink them if they extend beyond our current bounds. If we skipped
// measurement on any children, we need to measure them now.
@@ -1409,12 +1409,12 @@
if (!allFillParent && heightMode != MeasureSpec.EXACTLY) {
maxHeight = alternativeMaxHeight;
}
-
+
maxHeight += mPaddingTop + mPaddingBottom;
// Check against our minimum height
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
-
+
setMeasuredDimension(widthSizeAndState | (childState&MEASURED_STATE_MASK),
resolveSizeAndState(maxHeight, heightMeasureSpec,
(childState<<MEASURED_HEIGHT_STATE_SHIFT)));
@@ -1434,13 +1434,13 @@
final View child = getVirtualChildAt(i);
if (child != null && child.getVisibility() != GONE) {
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
-
+
if (lp.height == LayoutParams.MATCH_PARENT) {
// Temporarily force children to reuse their old measured width
// FIXME: this may not be right for something like wrapping text?
int oldWidth = lp.width;
lp.width = child.getMeasuredWidth();
-
+
// Remeasure with new dimensions
measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0);
lp.width = oldWidth;
@@ -1541,14 +1541,14 @@
int childTop;
int childLeft;
-
+
// Where right end of child should go
final int width = right - left;
int childRight = width - mPaddingRight;
-
+
// Space available for child
int childSpace = width - paddingLeft - mPaddingRight;
-
+
final int count = getVirtualChildCount();
final int majorGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
@@ -1578,10 +1578,10 @@
} else if (child.getVisibility() != GONE) {
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
-
+
final LinearLayout.LayoutParams lp =
(LinearLayout.LayoutParams) child.getLayoutParams();
-
+
int gravity = lp.gravity;
if (gravity < 0) {
gravity = minorGravity;
@@ -1647,11 +1647,11 @@
int childTop;
int childLeft;
-
+
// Where bottom of child should go
final int height = bottom - top;
- int childBottom = height - mPaddingBottom;
-
+ int childBottom = height - mPaddingBottom;
+
// Space available for child
int childSpace = height - paddingTop - mPaddingBottom;
@@ -1707,12 +1707,12 @@
if (baselineAligned && lp.height != LayoutParams.MATCH_PARENT) {
childBaseline = child.getBaseline();
}
-
+
int gravity = lp.gravity;
if (gravity < 0) {
gravity = minorGravity;
}
-
+
switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
case Gravity.TOP:
childTop = paddingTop + lp.topMargin;
@@ -1764,15 +1764,15 @@
}
}
- private void setChildFrame(View child, int left, int top, int width, int height) {
+ private void setChildFrame(View child, int left, int top, int width, int height) {
child.layout(left, top, left + width, top + height);
}
-
+
/**
* Should the layout be a column or a row.
* @param orientation Pass {@link #HORIZONTAL} or {@link #VERTICAL}. Default
* value is {@link #HORIZONTAL}.
- *
+ *
* @attr ref android.R.styleable#LinearLayout_orientation
*/
public void setOrientation(@OrientationMode int orientation) {
@@ -1784,7 +1784,7 @@
/**
* Returns the current orientation.
- *
+ *
* @return either {@link #HORIZONTAL} or {@link #VERTICAL}
*/
@OrientationMode
@@ -1797,9 +1797,9 @@
* this layout has a VERTICAL orientation, this controls where all the child
* views are placed if there is extra vertical space. If this layout has a
* HORIZONTAL orientation, this controls the alignment of the children.
- *
+ *
* @param gravity See {@link android.view.Gravity}
- *
+ *
* @attr ref android.R.styleable#LinearLayout_gravity
*/
@android.view.RemotableViewMethod
@@ -1845,7 +1845,7 @@
requestLayout();
}
}
-
+
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LinearLayout.LayoutParams(getContext(), attrs);
@@ -1909,7 +1909,7 @@
/**
* Per-child layout information associated with ViewLinearLayout.
- *
+ *
* @attr ref android.R.styleable#LinearLayout_Layout_layout_weight
* @attr ref android.R.styleable#LinearLayout_Layout_layout_gravity
*/
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 6a10743..0bde983 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -16,9 +16,6 @@
package android.widget;
-import com.android.internal.R;
-import com.android.internal.view.menu.ShowableListMenu;
-
import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -42,14 +39,17 @@
import android.view.WindowManager;
import android.widget.AdapterView.OnItemSelectedListener;
+import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
+
/**
* A ListPopupWindow anchors itself to a host view and displays a
* list of choices.
- *
+ *
* <p>ListPopupWindow contains a number of tricky behaviors surrounding
* positioning, scrolling parents to fit the dropdown, interacting
* sanely with the IME if present, and others.
- *
+ *
* @see android.widget.AutoCompleteTextView
* @see android.widget.Spinner
*/
@@ -116,7 +116,7 @@
/**
* The provided prompt view should appear above list content.
- *
+ *
* @see #setPromptPosition(int)
* @see #getPromptPosition()
* @see #setPromptView(View)
@@ -125,7 +125,7 @@
/**
* The provided prompt view should appear below list content.
- *
+ *
* @see #setPromptPosition(int)
* @see #getPromptPosition()
* @see #setPromptView(View)
@@ -138,13 +138,13 @@
* If used to specify a popup height, the popup will fill available space.
*/
public static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT;
-
+
/**
* Alias for {@link ViewGroup.LayoutParams#WRAP_CONTENT}.
* If used to specify a popup width, the popup will use the width of its content.
*/
public static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
-
+
/**
* Mode for {@link #setInputMethodMode(int)}: the requirements for the
* input method should be based on the focusability of the popup. That is
@@ -152,7 +152,7 @@
* it doesn't.
*/
public static final int INPUT_METHOD_FROM_FOCUSABLE = PopupWindow.INPUT_METHOD_FROM_FOCUSABLE;
-
+
/**
* Mode for {@link #setInputMethodMode(int)}: this popup always needs to
* work with an input method, regardless of whether it is focusable. This
@@ -160,7 +160,7 @@
* the input method while it is shown.
*/
public static final int INPUT_METHOD_NEEDED = PopupWindow.INPUT_METHOD_NEEDED;
-
+
/**
* Mode for {@link #setInputMethodMode(int)}: this popup never needs to
* work with an input method, regardless of whether it is focusable. This
@@ -172,7 +172,7 @@
/**
* Create a new, empty popup window capable of displaying items from a ListAdapter.
* Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
- *
+ *
* @param context Context used for contained views.
*/
public ListPopupWindow(@NonNull Context context) {
@@ -182,7 +182,7 @@
/**
* Create a new, empty popup window capable of displaying items from a ListAdapter.
* Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
- *
+ *
* @param context Context used for contained views.
* @param attrs Attributes from inflating parent views used to style the popup.
*/
@@ -193,7 +193,7 @@
/**
* Create a new, empty popup window capable of displaying items from a ListAdapter.
* Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
- *
+ *
* @param context Context used for contained views.
* @param attrs Attributes from inflating parent views used to style the popup.
* @param defStyleAttr Default style attribute to use for popup content.
@@ -206,7 +206,7 @@
/**
* Create a new, empty popup window capable of displaying items from a ListAdapter.
* Backgrounds should be set using {@link #setBackgroundDrawable(Drawable)}.
- *
+ *
* @param context Context used for contained views.
* @param attrs Attributes from inflating parent views used to style the popup.
* @param defStyleAttr Style attribute to read for default styling of popup content.
@@ -248,7 +248,7 @@
if (mAdapter != null) {
adapter.registerDataSetObserver(mObserver);
}
-
+
if (mDropDownList != null) {
mDropDownList.setAdapter(mAdapter);
}
@@ -257,9 +257,9 @@
/**
* Set where the optional prompt view should appear. The default is
* {@link #POSITION_PROMPT_ABOVE}.
- *
+ *
* @param position A position constant declaring where the prompt should be displayed.
- *
+ *
* @see #POSITION_PROMPT_ABOVE
* @see #POSITION_PROMPT_BELOW
*/
@@ -269,7 +269,7 @@
/**
* @return Where the optional prompt view should appear.
- *
+ *
* @see #POSITION_PROMPT_ABOVE
* @see #POSITION_PROMPT_BELOW
*/
@@ -279,11 +279,11 @@
/**
* Set whether this window should be modal when shown.
- *
+ *
* <p>If a popup window is modal, it will receive all touch and key input.
* If the user touches outside the popup window's content area the popup window
* will be dismissed.
- *
+ *
* @param modal {@code true} if the popup window should be modal, {@code false} otherwise.
*/
public void setModal(boolean modal) {
@@ -293,7 +293,7 @@
/**
* Returns whether the popup window will be modal when shown.
- *
+ *
* @return {@code true} if the popup window will be modal, {@code false} otherwise.
*/
public boolean isModal() {
@@ -304,7 +304,7 @@
* Forces outside touches to be ignored. Normally if {@link #isDropDownAlwaysVisible()} is
* false, we allow outside touch to dismiss the dropdown. If this is set to true, then we
* ignore outside touch even when the drop down is not set to always visible.
- *
+ *
* @hide Used only by AutoCompleteTextView to handle some internal special cases.
*/
public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) {
@@ -361,7 +361,7 @@
/**
* Sets a drawable to use as the list item selector.
- *
+ *
* @param selector List selector drawable to use in the popup.
*/
public void setListSelector(Drawable selector) {
@@ -377,7 +377,7 @@
/**
* Sets a drawable to be the background for the popup window.
- *
+ *
* @param d A drawable to set as the background.
*/
public void setBackgroundDrawable(@Nullable Drawable d) {
@@ -386,7 +386,7 @@
/**
* Set an animation style to use when the popup window is shown or dismissed.
- *
+ *
* @param animationStyle Animation style to use.
*/
public void setAnimationStyle(@StyleRes int animationStyle) {
@@ -396,7 +396,7 @@
/**
* Returns the animation style that will be used when the popup window is
* shown or dismissed.
- *
+ *
* @return Animation style that will be used.
*/
public @StyleRes int getAnimationStyle() {
@@ -405,7 +405,7 @@
/**
* Returns the view that will be used to anchor this popup.
- *
+ *
* @return The popup's anchor view
*/
public @Nullable View getAnchorView() {
@@ -415,7 +415,7 @@
/**
* Sets the popup's anchor view. This popup will always be positioned relative to
* the anchor view when shown.
- *
+ *
* @param anchor The view to use as an anchor.
*/
public void setAnchorView(@Nullable View anchor) {
@@ -431,7 +431,7 @@
/**
* Set the horizontal offset of this popup from its anchor view in pixels.
- *
+ *
* @param offset The horizontal offset of the popup from its anchor.
*/
public void setHorizontalOffset(int offset) {
@@ -450,7 +450,7 @@
/**
* Set the vertical offset of this popup from its anchor view in pixels.
- *
+ *
* @param offset The vertical offset of the popup from its anchor.
*/
public void setVerticalOffset(int offset) {
@@ -489,7 +489,7 @@
/**
* Sets the width of the popup window in pixels. Can also be {@link #MATCH_PARENT}
* or {@link #WRAP_CONTENT}.
- *
+ *
* @param width Width of the popup window.
*/
public void setWidth(int width) {
@@ -521,7 +521,7 @@
/**
* Sets the height of the popup window in pixels. Can also be {@link #MATCH_PARENT}.
- *
+ *
* @param height Height of the popup window.
*/
public void setHeight(int height) {
@@ -543,9 +543,9 @@
/**
* Sets a listener to receive events when a list item is clicked.
- *
+ *
* @param clickListener Listener to register
- *
+ *
* @see ListView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener)
*/
public void setOnItemClickListener(@Nullable AdapterView.OnItemClickListener clickListener) {
@@ -554,9 +554,9 @@
/**
* Sets a listener to receive events when a list item is selected.
- *
+ *
* @param selectedListener Listener to register.
- *
+ *
* @see ListView#setOnItemSelectedListener(OnItemSelectedListener)
*/
public void setOnItemSelectedListener(@Nullable OnItemSelectedListener selectedListener) {
@@ -566,7 +566,7 @@
/**
* Set a view to act as a user prompt for this popup window. Where the prompt view will appear
* is controlled by {@link #setPromptPosition(int)}.
- *
+ *
* @param prompt View to use as an informational prompt.
*/
public void setPromptView(@Nullable View prompt) {
@@ -662,7 +662,7 @@
mPopup.setWidth(widthSpec);
mPopup.setHeight(heightSpec);
mPopup.setClipToScreenEnabled(true);
-
+
// use outside touchable to dismiss drop down when touching outside of it, so
// only set this if the dropdown is not always visible
mPopup.setOutsideTouchable(!mForceIgnoreOutsideTouch && !mDropDownAlwaysVisible);
@@ -671,7 +671,7 @@
mPopup.showAsDropDown(getAnchorView(), mDropDownHorizontalOffset,
mDropDownVerticalOffset, mDropDownGravity);
mDropDownList.setSelection(ListView.INVALID_POSITION);
-
+
if (!mModal || mDropDownList.isInTouchMode()) {
clearListSelection();
}
@@ -716,11 +716,11 @@
* Control how the popup operates with an input method: one of
* {@link #INPUT_METHOD_FROM_FOCUSABLE}, {@link #INPUT_METHOD_NEEDED},
* or {@link #INPUT_METHOD_NOT_NEEDED}.
- *
+ *
* <p>If the popup is showing, calling this method will take effect only
* the next time the popup is shown or through a manual call to the {@link #show()}
* method.</p>
- *
+ *
* @see #getInputMethodMode()
* @see #show()
*/
@@ -730,7 +730,7 @@
/**
* Return the current value in {@link #setInputMethodMode(int)}.
- *
+ *
* @see #setInputMethodMode(int)
*/
public int getInputMethodMode() {
@@ -740,7 +740,7 @@
/**
* Set the selected position of the list.
* Only valid when {@link #isShowing()} == {@code true}.
- *
+ *
* @param position List position to set as selected.
*/
public void setSelection(int position) {
@@ -786,7 +786,7 @@
/**
* Perform an item click operation on the specified list adapter position.
- *
+ *
* @param position Adapter position for performing the click
* @return true if the click action could be performed, false if not.
* (e.g. if the popup was not showing, this method would return false.)
@@ -817,7 +817,7 @@
/**
* @return The position of the currently selected item or {@link ListView#INVALID_POSITION}
* if {@link #isShowing()} == {@code false}.
- *
+ *
* @see ListView#getSelectedItemPosition()
*/
public int getSelectedItemPosition() {
@@ -830,7 +830,7 @@
/**
* @return The ID of the currently selected item or {@link ListView#INVALID_ROW_ID}
* if {@link #isShowing()} == {@code false}.
- *
+ *
* @see ListView#getSelectedItemId()
*/
public long getSelectedItemId() {
@@ -843,7 +843,7 @@
/**
* @return The View for the currently selected item or null if
* {@link #isShowing()} == {@code false}.
- *
+ *
* @see ListView#getSelectedView()
*/
public @Nullable View getSelectedView() {
@@ -904,7 +904,7 @@
final boolean below = !mPopup.isAboveAnchor();
final ListAdapter adapter = mAdapter;
-
+
boolean allEnabled;
int firstItem = Integer.MAX_VALUE;
int lastItem = Integer.MIN_VALUE;
@@ -914,9 +914,9 @@
firstItem = allEnabled ? 0 :
mDropDownList.lookForSelectablePosition(0, true);
lastItem = allEnabled ? adapter.getCount() - 1 :
- mDropDownList.lookForSelectablePosition(adapter.getCount() - 1, false);
+ mDropDownList.lookForSelectablePosition(adapter.getCount() - 1, false);
}
-
+
if ((below && keyCode == KeyEvent.KEYCODE_DPAD_UP && curIndex <= firstItem) ||
(!below && keyCode == KeyEvent.KEYCODE_DPAD_DOWN && curIndex >= lastItem)) {
// When the selection is at the top, we block the key
@@ -1132,18 +1132,18 @@
LinearLayout.LayoutParams hintParams = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f
);
-
+
switch (mPromptPosition) {
case POSITION_PROMPT_BELOW:
hintContainer.addView(dropDownView, hintParams);
hintContainer.addView(hintView);
break;
-
+
case POSITION_PROMPT_ABOVE:
hintContainer.addView(hintView);
hintContainer.addView(dropDownView, hintParams);
break;
-
+
default:
Log.e(TAG, "Invalid hint position " + mPromptPosition);
break;
@@ -1249,7 +1249,7 @@
show();
}
}
-
+
@Override
public void onInvalidated() {
dismiss();
@@ -1278,7 +1278,7 @@
final int action = event.getAction();
final int x = (int) event.getX();
final int y = (int) event.getY();
-
+
if (action == MotionEvent.ACTION_DOWN &&
mPopup != null && mPopup.isShowing() &&
(x >= 0 && x < mPopup.getWidth() && y >= 0 && y < mPopup.getHeight())) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index b0f19d7..e88c7ef 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -16,11 +16,6 @@
package android.widget;
-import com.google.android.collect.Lists;
-
-import com.android.internal.R;
-import com.android.internal.util.Predicate;
-
import android.annotation.IdRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -53,6 +48,11 @@
import android.view.accessibility.AccessibilityNodeProvider;
import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
+import com.android.internal.util.Predicate;
+
+import com.google.android.collect.Lists;
+
import java.util.ArrayList;
import java.util.List;
@@ -464,7 +464,7 @@
* data backing this list and for producing a view to represent an
* item in that data set.
*
- * @see #getAdapter()
+ * @see #getAdapter()
*/
@Override
public void setAdapter(ListAdapter adapter) {
@@ -1532,7 +1532,7 @@
adjustViewsUpOrDown();
}
} else if (lastPosition == mItemCount - 1) {
- adjustViewsUpOrDown();
+ adjustViewsUpOrDown();
}
}
}
@@ -1857,7 +1857,7 @@
&& focusLayoutRestoreView.getWindowToken() != null) {
focusLayoutRestoreView.dispatchFinishTemporaryDetach();
}
-
+
mLayoutMode = LAYOUT_NORMAL;
mDataChanged = false;
if (mPositionScrollAfterLayout != null) {
@@ -2109,7 +2109,7 @@
/**
* Makes the item at the supplied position selected.
- *
+ *
* @param position the position of the item to select
*/
@Override
@@ -2960,7 +2960,7 @@
if (startPos < firstPosition) {
startPos = firstPosition;
}
-
+
final int lastVisiblePos = getLastVisiblePosition();
final ListAdapter adapter = getAdapter();
for (int pos = startPos; pos <= lastVisiblePos; pos++) {
@@ -3129,7 +3129,7 @@
/**
* Determine the distance to the nearest edge of a view in a particular
* direction.
- *
+ *
* @param descendant A descendant of this list.
* @return The distance, or 0 if the nearest edge is already on screen.
*/
@@ -3386,7 +3386,7 @@
final int listBottom = mBottom - mTop - effectivePaddingBottom + mScrollY;
if (!mStackFromBottom) {
int bottom = 0;
-
+
// Draw top divider or header for overscroll
final int scrollY = mScrollY;
if (count > 0 && scrollY < 0) {
@@ -3483,7 +3483,7 @@
}
}
}
-
+
if (count > 0 && scrollY > 0) {
if (drawOverscrollFooter) {
final int absListBottom = mBottom;
@@ -3567,7 +3567,7 @@
public int getDividerHeight() {
return mDividerHeight;
}
-
+
/**
* Sets the height of the divider that will be drawn between each item in the list. Calling
* this will override the intrinsic height as set by {@link #setDivider(Drawable)}
@@ -3625,7 +3625,7 @@
public boolean areFooterDividersEnabled() {
return mFooterDividersEnabled;
}
-
+
/**
* Sets the drawable that will be drawn above all other list content.
* This area can become visible when the user overscrolls the list.
@@ -3878,10 +3878,10 @@
/**
* Returns the set of checked items ids. The result is only valid if the
* choice mode has not been set to {@link #CHOICE_MODE_NONE}.
- *
+ *
* @return A new array which contains the id of each checked item in the
* list.
- *
+ *
* @deprecated Use {@link #getCheckedItemIds()} instead.
*/
@Deprecated
diff --git a/core/java/android/widget/MenuItemHoverListener.java b/core/java/android/widget/MenuItemHoverListener.java
index 13f0e6a..835e4cd 100644
--- a/core/java/android/widget/MenuItemHoverListener.java
+++ b/core/java/android/widget/MenuItemHoverListener.java
@@ -1,10 +1,10 @@
package android.widget;
-import com.android.internal.view.menu.MenuBuilder;
-
import android.annotation.NonNull;
import android.view.MenuItem;
+import com.android.internal.view.menu.MenuBuilder;
+
/**
* An interface notified when a menu item is hovered. Useful for cases when hover should trigger
* some behavior at a higher level, like managing the opening and closing of submenus.
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 72b2e31..662e640 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.TestApi;
@@ -32,12 +30,10 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.text.Editable;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
import android.text.TextUtils;
-import android.text.TextWatcher;
import android.text.method.NumberKeyListener;
import android.util.AttributeSet;
import android.util.SparseArray;
@@ -57,6 +53,10 @@
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
+import com.android.internal.R;
+
+import libcore.icu.LocaleData;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -64,8 +64,6 @@
import java.util.List;
import java.util.Locale;
-import libcore.icu.LocaleData;
-
/**
* A widget that enables the user to select a number from a predefined range.
* There are two flavors of this widget and which one is presented to the user
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index 027f874..eb27533 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -16,11 +16,6 @@
package android.widget;
-import com.android.internal.R;
-import com.android.internal.view.menu.MenuBuilder;
-import com.android.internal.view.menu.MenuPopupHelper;
-import com.android.internal.view.menu.ShowableListMenu;
-
import android.annotation.MenuRes;
import android.content.Context;
import android.view.Gravity;
@@ -30,6 +25,11 @@
import android.view.View;
import android.view.View.OnTouchListener;
+import com.android.internal.R;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuPopupHelper;
+import com.android.internal.view.menu.ShowableListMenu;
+
/**
* A PopupMenu displays a {@link Menu} in a modal popup window anchored to a
* {@link View}. The popup will appear below the anchor view if there is room,
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 5e73a63..fc1520b 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -16,7 +16,11 @@
package android.widget;
-import com.android.internal.R;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import static android.view.WindowManager.LayoutParams
+ .PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -50,12 +54,9 @@
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
-import java.lang.ref.WeakReference;
+import com.android.internal.R;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import java.lang.ref.WeakReference;
/**
* <p>
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 3c967ac..266ff75 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.graphics.Rect;
@@ -59,6 +58,7 @@
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
import android.widget.RemoteViews.RemoteView;
+
import com.android.internal.R;
import java.util.ArrayList;
@@ -185,6 +185,7 @@
* @attr ref android.R.styleable#ProgressBar_indeterminateDuration
* @attr ref android.R.styleable#ProgressBar_indeterminateOnly
* @attr ref android.R.styleable#ProgressBar_interpolator
+ * @attr ref android.R.styleable#ProgressBar_min
* @attr ref android.R.styleable#ProgressBar_max
* @attr ref android.R.styleable#ProgressBar_maxHeight
* @attr ref android.R.styleable#ProgressBar_maxWidth
@@ -215,7 +216,10 @@
private int mProgress;
private int mSecondaryProgress;
+ private int mMin;
+ private boolean mMinInitialized;
private int mMax;
+ private boolean mMaxInitialized;
private int mBehavior;
private int mDuration;
@@ -230,7 +234,7 @@
private Drawable mCurrentDrawable;
private ProgressTintInfo mProgressTintInfo;
- Bitmap mSampleTile;
+ int mSampleWidth = 0;
private boolean mNoInvalidate;
private Interpolator mInterpolator;
private RefreshProgressRunnable mRefreshProgressRunnable;
@@ -308,6 +312,7 @@
setInterpolator(context, resID);
}
+ setMin(a.getInt(R.styleable.ProgressBar_min, mMin));
setMax(a.getInt(R.styleable.ProgressBar_max, mMax));
setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));
@@ -505,15 +510,14 @@
}
if (drawable instanceof BitmapDrawable) {
- final BitmapDrawable bitmap = (BitmapDrawable) drawable;
- final Bitmap tileBitmap = bitmap.getBitmap();
- if (mSampleTile == null) {
- mSampleTile = tileBitmap;
- }
-
- final BitmapDrawable clone = (BitmapDrawable) bitmap.getConstantState().newDrawable();
+ final Drawable.ConstantState cs = drawable.getConstantState();
+ final BitmapDrawable clone = (BitmapDrawable) cs.newDrawable(getResources());
clone.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
+ if (mSampleWidth <= 0) {
+ mSampleWidth = clone.getIntrinsicWidth();
+ }
+
if (clip) {
return new ClipDrawable(clone, Gravity.LEFT, ClipDrawable.HORIZONTAL);
} else {
@@ -565,6 +569,7 @@
* </ul>
*/
private void initProgressBar() {
+ mMin = 0;
mMax = 100;
mProgress = 0;
mSecondaryProgress = 0;
@@ -1310,7 +1315,8 @@
private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
boolean callBackToApp, boolean animate) {
- final float scale = mMax > 0 ? progress / (float) mMax : 0;
+ int range = mMax - mMin;
+ final float scale = range > 0 ? (progress - mMin) / (float) range : 0;
final boolean isPrimary = id == R.id.progress;
if (isPrimary && animate) {
@@ -1436,7 +1442,7 @@
return false;
}
- progress = MathUtils.constrain(progress, 0, mMax);
+ progress = MathUtils.constrain(progress, mMin, mMax);
if (progress == mProgress) {
// No change from current.
@@ -1466,8 +1472,8 @@
return;
}
- if (secondaryProgress < 0) {
- secondaryProgress = 0;
+ if (secondaryProgress < mMin) {
+ secondaryProgress = mMin;
}
if (secondaryProgress > mMax) {
@@ -1515,6 +1521,20 @@
}
/**
+ * <p>Return the lower limit of this progress bar's range.</p>
+ *
+ * @return a positive integer
+ *
+ * @see #setMin(int)
+ * @see #getProgress()
+ * @see #getSecondaryProgress()
+ */
+ @ViewDebug.ExportedProperty(category = "progress")
+ public synchronized int getMin() {
+ return mMin;
+ }
+
+ /**
* <p>Return the upper limit of this progress bar's range.</p>
*
* @return a positive integer
@@ -1529,7 +1549,37 @@
}
/**
- * <p>Set the range of the progress bar to 0...<tt>max</tt>.</p>
+ * <p>Set the lower range of the progress bar to <tt>min</tt>.</p>
+ *
+ * @param min the lower range of this progress bar
+ *
+ * @see #getMin()
+ * @see #setProgress(int)
+ * @see #setSecondaryProgress(int)
+ */
+ @android.view.RemotableViewMethod
+ public synchronized void setMin(int min) {
+ if (mMaxInitialized) {
+ if (min > mMax) {
+ min = mMax;
+ }
+ }
+ mMinInitialized = true;
+ if (mMaxInitialized && min != mMin) {
+ mMin = min;
+ postInvalidate();
+
+ if (mProgress < min) {
+ mProgress = min;
+ }
+ refreshProgress(R.id.progress, mProgress, false, false);
+ } else {
+ mMin = min;
+ }
+ }
+
+ /**
+ * <p>Set the upper range of the progress bar <tt>max</tt>.</p>
*
* @param max the upper range of this progress bar
*
@@ -1539,10 +1589,13 @@
*/
@android.view.RemotableViewMethod
public synchronized void setMax(int max) {
- if (max < 0) {
- max = 0;
+ if (mMinInitialized) {
+ if (max < mMin) {
+ max = mMin;
+ }
}
- if (max != mMax) {
+ mMaxInitialized = true;
+ if (mMinInitialized && max != mMax) {
mMax = max;
postInvalidate();
@@ -1550,6 +1603,8 @@
mProgress = max;
}
refreshProgress(R.id.progress, mProgress, false, false);
+ } else {
+ mMax = max;
}
}
@@ -1959,7 +2014,7 @@
@Override
public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
super.onInitializeAccessibilityEventInternal(event);
- event.setItemCount(mMax);
+ event.setItemCount(mMax - mMin);
event.setCurrentItemIndex(mProgress);
}
diff --git a/core/java/android/widget/QuickContactBadge.java b/core/java/android/widget/QuickContactBadge.java
index 8c15cde..8f6b0d5 100644
--- a/core/java/android/widget/QuickContactBadge.java
+++ b/core/java/android/widget/QuickContactBadge.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.content.AsyncQueryHandler;
import android.content.ContentResolver;
import android.content.Context;
@@ -38,6 +36,8 @@
import android.view.View;
import android.view.View.OnClickListener;
+import com.android.internal.R;
+
/**
* Widget used to show an image with the standard QuickContact badge
* and on-click behavior.
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 5a0e1f9..757a4ca 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -16,10 +16,6 @@
package android.widget;
-import android.view.PointerIcon;
-import com.android.internal.R;
-import com.android.internal.widget.ExploreByTouchHelper;
-
import android.animation.ObjectAnimator;
import android.annotation.IntDef;
import android.content.Context;
@@ -43,11 +39,15 @@
import android.util.TypedValue;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import com.android.internal.R;
+import com.android.internal.widget.ExploreByTouchHelper;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Calendar;
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 065feb8..54b57631 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.IdRes;
import android.content.Context;
import android.content.res.TypedArray;
@@ -25,6 +23,8 @@
import android.view.View;
import android.view.ViewGroup;
+import com.android.internal.R;
+
/**
* <p>This class is used to create a multiple-exclusion scope for a set of radio
@@ -39,14 +39,14 @@
* in the XML layout file.</p>
*
* <p><strong>XML Attributes</strong></p>
- * <p>See {@link android.R.styleable#RadioGroup RadioGroup Attributes},
+ * <p>See {@link android.R.styleable#RadioGroup RadioGroup Attributes},
* {@link android.R.styleable#LinearLayout LinearLayout Attributes},
* {@link android.R.styleable#ViewGroup ViewGroup Attributes},
* {@link android.R.styleable#View View Attributes}</p>
* <p>Also see
* {@link android.widget.LinearLayout.LayoutParams LinearLayout.LayoutParams}
* for layout attributes.</p>
- *
+ *
* @see RadioButton
*
*/
@@ -310,7 +310,7 @@
} else {
width = WRAP_CONTENT;
}
-
+
if (a.hasValue(heightAttr)) {
height = a.getLayoutDimension(heightAttr, "layout_height");
} else {
diff --git a/core/java/android/widget/RatingBar.java b/core/java/android/widget/RatingBar.java
index 3ad05b5..3b7fe86 100644
--- a/core/java/android/widget/RatingBar.java
+++ b/core/java/android/widget/RatingBar.java
@@ -22,6 +22,7 @@
import android.graphics.drawable.shapes.Shape;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityNodeInfo;
+
import com.android.internal.R;
/**
@@ -281,10 +282,8 @@
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (mSampleTile != null) {
- // TODO: Once ProgressBar's TODOs are gone, this can be done more
- // cleanly than mSampleTile
- final int width = mSampleTile.getWidth() * mNumStars;
+ if (mSampleWidth > 0) {
+ final int width = mSampleWidth * mNumStars;
setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, 0),
getMeasuredHeight());
}
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index a189d3c..b424101 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -16,20 +16,14 @@
package android.widget;
+import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+
import android.annotation.NonNull;
-import android.util.ArrayMap;
-import com.android.internal.R;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.os.Build;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Pools.SynchronizedPool;
import android.util.SparseArray;
@@ -41,7 +35,13 @@
import android.view.accessibility.AccessibilityEvent;
import android.widget.RemoteViews.RemoteView;
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+import com.android.internal.R;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.SortedSet;
+import java.util.TreeSet;
/**
* A Layout where the positions of the children can be described in relation to each other or to the
@@ -209,7 +209,7 @@
private int mIgnoreGravity;
private SortedSet<View> mTopToBottomLeftToRightSet = null;
-
+
private boolean mDirtyHierarchy;
private View[] mSortedHorizontalChildren;
private View[] mSortedVerticalChildren;
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 2a6e01f..6543d0c 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -59,11 +59,12 @@
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView.OnItemClickListener;
-import libcore.util.Objects;
import com.android.internal.R;
import com.android.internal.util.Preconditions;
+import libcore.util.Objects;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 10abbab..e0f94fd 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -16,13 +16,6 @@
package android.widget;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-
import android.Manifest;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
@@ -48,6 +41,11 @@
import com.android.internal.widget.IRemoteViewsAdapterConnection;
import com.android.internal.widget.IRemoteViewsFactory;
+import java.lang.ref.WeakReference;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+
/**
* An adapter to a RemoteViewsService which fetches and caches RemoteViews
* to be later inflated as child views.
diff --git a/core/java/android/widget/RemoteViewsService.java b/core/java/android/widget/RemoteViewsService.java
index 07bd918..2827f63 100644
--- a/core/java/android/widget/RemoteViewsService.java
+++ b/core/java/android/widget/RemoteViewsService.java
@@ -16,14 +16,14 @@
package android.widget;
-import java.util.HashMap;
-
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import com.android.internal.widget.IRemoteViewsFactory;
+import java.util.HashMap;
+
/**
* The service to be connected to for a remote adapter to request RemoteViews. Users should
* extend the RemoteViewsService to provide the appropriate RemoteViewsFactory's used to
@@ -46,7 +46,7 @@
* An interface for an adapter between a remote collection view (ListView, GridView, etc) and
* the underlying data for that view. The implementor is responsible for making a RemoteView
* for each item in the data set. This interface is a thin wrapper around {@link Adapter}.
- *
+ *
* @see android.widget.Adapter
* @see android.appwidget.AppWidgetManager
*/
diff --git a/core/java/android/widget/ResourceCursorAdapter.java b/core/java/android/widget/ResourceCursorAdapter.java
index 100f919..9732bb1 100644
--- a/core/java/android/widget/ResourceCursorAdapter.java
+++ b/core/java/android/widget/ResourceCursorAdapter.java
@@ -20,9 +20,9 @@
import android.content.res.Resources;
import android.database.Cursor;
import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.LayoutInflater;
/**
@@ -148,7 +148,7 @@
public void setViewResource(int layout) {
mLayout = layout;
}
-
+
/**
* <p>Sets the layout resource of the drop down views.</p>
*
diff --git a/core/java/android/widget/ResourceCursorTreeAdapter.java b/core/java/android/widget/ResourceCursorTreeAdapter.java
index ddce515..0894dba 100644
--- a/core/java/android/widget/ResourceCursorTreeAdapter.java
+++ b/core/java/android/widget/ResourceCursorTreeAdapter.java
@@ -18,9 +18,9 @@
import android.content.Context;
import android.database.Cursor;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.LayoutInflater;
/**
* A fairly simple ExpandableListAdapter that creates views defined in an XML
@@ -32,10 +32,10 @@
private int mChildLayout;
private int mLastChildLayout;
private LayoutInflater mInflater;
-
+
/**
* Constructor.
- *
+ *
* @param context The context where the ListView associated with this
* SimpleListItemFactory is running
* @param cursor The database cursor
@@ -51,18 +51,18 @@
public ResourceCursorTreeAdapter(Context context, Cursor cursor, int collapsedGroupLayout,
int expandedGroupLayout, int childLayout, int lastChildLayout) {
super(cursor, context);
-
+
mCollapsedGroupLayout = collapsedGroupLayout;
mExpandedGroupLayout = expandedGroupLayout;
mChildLayout = childLayout;
mLastChildLayout = lastChildLayout;
-
+
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/**
* Constructor.
- *
+ *
* @param context The context where the ListView associated with this
* SimpleListItemFactory is running
* @param cursor The database cursor
@@ -80,7 +80,7 @@
/**
* Constructor.
- *
+ *
* @param context The context where the ListView associated with this
* SimpleListItemFactory is running
* @param cursor The database cursor
@@ -93,7 +93,7 @@
int childLayout) {
this(context, cursor, groupLayout, groupLayout, childLayout, childLayout);
}
-
+
@Override
public View newChildView(Context context, Cursor cursor, boolean isLastChild,
ViewGroup parent) {
diff --git a/core/java/android/widget/ScrollBarDrawable.java b/core/java/android/widget/ScrollBarDrawable.java
index 11eab2a..2ae38c9 100644
--- a/core/java/android/widget/ScrollBarDrawable.java
+++ b/core/java/android/widget/ScrollBarDrawable.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.widget.ScrollBarUtils;
-
import android.annotation.NonNull;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
@@ -25,6 +23,8 @@
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import com.android.internal.widget.ScrollBarUtils;
+
/**
* This is only used by View for displaying its scroll bars. It should probably
* be moved in to the view package since it is used in that lower-level layer.
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index e696ff7..d8f3379 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -17,18 +17,16 @@
package android.widget;
import android.annotation.NonNull;
-import android.content.res.Configuration;
-import android.os.Build;
-import android.os.Build.VERSION_CODES;
-import android.os.Parcel;
-import android.os.Parcelable;
-import com.android.internal.R;
-
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.StrictMode;
import android.util.AttributeSet;
import android.util.Log;
@@ -47,6 +45,8 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AnimationUtils;
+import com.android.internal.R;
+
import java.util.List;
/**
diff --git a/core/java/android/widget/SeekBar.java b/core/java/android/widget/SeekBar.java
index 5d01d8d..f9aced0 100644
--- a/core/java/android/widget/SeekBar.java
+++ b/core/java/android/widget/SeekBar.java
@@ -46,8 +46,10 @@
* to distinguish user-initiated changes from those that occurred programmatically.
*
* @param seekBar The SeekBar whose progress has changed
- * @param progress The current progress level. This will be in the range 0..max where max
- * was set by {@link ProgressBar#setMax(int)}. (The default value for max is 100.)
+ * @param progress The current progress level. This will be in the range min..max where min
+ * and max were set by {@link ProgressBar#setMin(int)} and
+ * {@link ProgressBar#setMax(int)}, respectively. (The default values for
+ * min is 0 and max is 100.)
* @param fromUser True if the progress change was initiated by the user.
*/
void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser);
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index 3bf9485..9190117 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -20,11 +20,11 @@
import android.annotation.LayoutRes;
import android.content.Context;
import android.content.res.Resources;
+import android.net.Uri;
import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.LayoutInflater;
-import android.net.Uri;
import java.util.ArrayList;
import java.util.List;
@@ -40,7 +40,7 @@
* Binding data to views occurs in two phases. First, if a
* {@link android.widget.SimpleAdapter.ViewBinder} is available,
* {@link ViewBinder#setViewValue(android.view.View, Object, String)}
- * is invoked. If the returned value is true, binding has occurred.
+ * is invoked. If the returned value is true, binding has occurred.
* If the returned value is false, the following views are then tried in order:
* <ul>
* <li> A view that implements Checkable (e.g. CheckBox). The expected bind value is a boolean.
@@ -223,7 +223,7 @@
setViewText((TextView) v, text);
} else if (v instanceof ImageView) {
if (data instanceof Integer) {
- setViewImage((ImageView) v, (Integer) data);
+ setViewImage((ImageView) v, (Integer) data);
} else {
setViewImage((ImageView) v, text);
}
@@ -291,7 +291,7 @@
* @param v ImageView to receive an image
* @param value the value retrieved from the data set
*
- * @see #setViewImage(ImageView, int)
+ * @see #setViewImage(ImageView, int)
*/
public void setViewImage(ImageView v, String value) {
try {
@@ -381,18 +381,18 @@
for (int i = 0; i < count; i++) {
Map<String, ?> h = unfilteredValues.get(i);
if (h != null) {
-
+
int len = mTo.length;
for (int j=0; j<len; j++) {
String str = (String)h.get(mFrom[j]);
-
+
String[] words = str.split(" ");
int wordCount = words.length;
-
+
for (int k = 0; k < wordCount; k++) {
String word = words[k];
-
+
if (word.toLowerCase().startsWith(prefixString)) {
newValues.add(h);
break;
diff --git a/core/java/android/widget/SimpleExpandableListAdapter.java b/core/java/android/widget/SimpleExpandableListAdapter.java
index 015c169..597502b 100644
--- a/core/java/android/widget/SimpleExpandableListAdapter.java
+++ b/core/java/android/widget/SimpleExpandableListAdapter.java
@@ -17,9 +17,9 @@
package android.widget;
import android.content.Context;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.LayoutInflater;
import java.util.List;
import java.util.Map;
@@ -42,18 +42,18 @@
private int mCollapsedGroupLayout;
private String[] mGroupFrom;
private int[] mGroupTo;
-
+
private List<? extends List<? extends Map<String, ?>>> mChildData;
private int mChildLayout;
private int mLastChildLayout;
private String[] mChildFrom;
private int[] mChildTo;
-
+
private LayoutInflater mInflater;
-
+
/**
* Constructor
- *
+ *
* @param context The context where the {@link ExpandableListView}
* associated with this {@link SimpleExpandableListAdapter} is
* running
@@ -98,7 +98,7 @@
/**
* Constructor
- *
+ *
* @param context The context where the {@link ExpandableListView}
* associated with this {@link SimpleExpandableListAdapter} is
* running
@@ -147,7 +147,7 @@
/**
* Constructor
- *
+ *
* @param context The context where the {@link ExpandableListView}
* associated with this {@link SimpleExpandableListAdapter} is
* running
@@ -200,16 +200,16 @@
mCollapsedGroupLayout = collapsedGroupLayout;
mGroupFrom = groupFrom;
mGroupTo = groupTo;
-
+
mChildData = childData;
mChildLayout = childLayout;
mLastChildLayout = lastChildLayout;
mChildFrom = childFrom;
mChildTo = childTo;
-
+
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
-
+
public Object getChild(int groupPosition, int childPosition) {
return mChildData.get(groupPosition).get(childPosition);
}
@@ -239,7 +239,7 @@
public View newChildView(boolean isLastChild, ViewGroup parent) {
return mInflater.inflate((isLastChild) ? mLastChildLayout : mChildLayout, parent, false);
}
-
+
private void bindView(View view, Map<String, ?> data, String[] from, int[] to) {
int len = to.length;
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 8c43782..855d1d2 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -16,10 +16,6 @@
package android.widget;
-import android.view.PointerIcon;
-import com.android.internal.R;
-import com.android.internal.widget.ExploreByTouchHelper;
-
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -43,17 +39,21 @@
import android.util.StateSet;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.View;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-import java.text.NumberFormat;
-import java.util.Locale;
+import com.android.internal.R;
+import com.android.internal.widget.ExploreByTouchHelper;
import libcore.icu.LocaleData;
+import java.text.NumberFormat;
+import java.util.Locale;
+
/**
* A calendar-like view displaying a specified month and the appropriate selectable day numbers
* within the specified month.
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index dc5e5a2..28cc693 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -16,13 +16,9 @@
package android.widget;
-import android.annotation.TestApi;
-import android.view.PointerIcon;
-import com.android.internal.R;
-import com.android.internal.view.menu.ShowableListMenu;
-
import android.annotation.DrawableRes;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.annotation.Widget;
import android.app.AlertDialog;
import android.content.Context;
@@ -42,6 +38,7 @@
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -49,6 +46,9 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.PopupWindow.OnDismissListener;
+import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
+
/**
* A view that displays one child at a time and lets the user pick among them.
* The items in the Spinner come from the {@link Adapter} associated with
@@ -123,7 +123,7 @@
* access the current theme, resources, etc.
* @param mode Constant describing how the user will select choices from
* the spinner.
- *
+ *
* @see #MODE_DIALOG
* @see #MODE_DROPDOWN
*/
@@ -563,7 +563,7 @@
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
-
+
if (mPopup != null && mPopup.isShowing()) {
mPopup.dismiss();
}
@@ -772,7 +772,7 @@
@Override
public boolean performClick() {
boolean handled = super.performClick();
-
+
if (!handled) {
handled = true;
@@ -1011,7 +1011,7 @@
/**
* If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
- * Otherwise, return true.
+ * Otherwise, return true.
*/
public boolean areAllItemsEnabled() {
final ListAdapter adapter = mListAdapter;
@@ -1042,19 +1042,19 @@
public int getViewTypeCount() {
return 1;
}
-
+
public boolean isEmpty() {
return getCount() == 0;
}
}
-
+
/**
* Implements some sort of popup selection interface for selecting a spinner option.
* Allows for different spinner modes.
*/
private interface SpinnerPopup {
public void setAdapter(ListAdapter adapter);
-
+
/**
* Show the popup
*/
@@ -1064,12 +1064,12 @@
* Dismiss the popup
*/
public void dismiss();
-
+
/**
* @return true if the popup is showing, false otherwise.
*/
public boolean isShowing();
-
+
/**
* Set hint text to be displayed to the user. This should provide
* a description of the choice being made.
@@ -1129,7 +1129,7 @@
listView.setTextAlignment(textAlignment);
mPopup.show();
}
-
+
public void onClick(DialogInterface dialog, int which) {
setSelection(which);
if (mOnItemClickListener != null) {
@@ -1168,7 +1168,7 @@
return 0;
}
}
-
+
private class DropdownPopup extends ListPopupWindow implements SpinnerPopup {
private CharSequence mHintText;
private ListAdapter mAdapter;
@@ -1190,7 +1190,7 @@
}
});
}
-
+
@Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
@@ -1200,7 +1200,7 @@
public CharSequence getHintText() {
return mHintText;
}
-
+
public void setPromptText(CharSequence hintText) {
// Hint text is ignored for dropdowns, but maintain it here.
mHintText = hintText;
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index 2bd3143..0e99c02 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -15,8 +15,6 @@
package android.widget;
-import java.lang.ref.WeakReference;
-
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
@@ -45,6 +43,8 @@
import android.view.animation.LinearInterpolator;
import android.widget.RemoteViews.RemoteView;
+import java.lang.ref.WeakReference;
+
@RemoteView
/**
* A view that displays its children in a stack and allows users to discretely swipe
@@ -670,12 +670,12 @@
activeIndex = (swipeGestureType == GESTURE_SLIDE_DOWN) ? 1 : 0;
}
- boolean endOfStack = mLoopViews && adapterCount == 1 &&
- ((mStackMode == ITEMS_SLIDE_UP && swipeGestureType == GESTURE_SLIDE_UP) ||
- (mStackMode == ITEMS_SLIDE_DOWN && swipeGestureType == GESTURE_SLIDE_DOWN));
- boolean beginningOfStack = mLoopViews && adapterCount == 1 &&
- ((mStackMode == ITEMS_SLIDE_DOWN && swipeGestureType == GESTURE_SLIDE_UP) ||
- (mStackMode == ITEMS_SLIDE_UP && swipeGestureType == GESTURE_SLIDE_DOWN));
+ boolean endOfStack = mLoopViews && adapterCount == 1
+ && ((mStackMode == ITEMS_SLIDE_UP && swipeGestureType == GESTURE_SLIDE_UP)
+ || (mStackMode == ITEMS_SLIDE_DOWN && swipeGestureType == GESTURE_SLIDE_DOWN));
+ boolean beginningOfStack = mLoopViews && adapterCount == 1
+ && ((mStackMode == ITEMS_SLIDE_DOWN && swipeGestureType == GESTURE_SLIDE_UP)
+ || (mStackMode == ITEMS_SLIDE_UP && swipeGestureType == GESTURE_SLIDE_DOWN));
int stackMode;
if (mLoopViews && !beginningOfStack && !endOfStack) {
diff --git a/core/java/android/widget/SuggestionsAdapter.java b/core/java/android/widget/SuggestionsAdapter.java
index aad0625..f833d1b 100644
--- a/core/java/android/widget/SuggestionsAdapter.java
+++ b/core/java/android/widget/SuggestionsAdapter.java
@@ -21,8 +21,8 @@
import android.app.SearchableInfo;
import android.content.ComponentName;
import android.content.ContentResolver;
-import android.content.Context;
import android.content.ContentResolver.OpenResourceIdResult;
+import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -39,8 +39,8 @@
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
-import android.view.ViewGroup;
import android.view.View.OnClickListener;
+import android.view.ViewGroup;
import com.android.internal.R;
@@ -111,7 +111,7 @@
mProviderContext = mSearchable.getProviderContext(mContext, activityContext);
mOutsideDrawablesCache = outsideDrawablesCache;
-
+
// mStartSpinnerRunnable = new Runnable() {
// public void run() {
// // mSearchView.setWorking(true); // TODO:
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index d51c5be..fcc1667 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -30,8 +30,8 @@
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
-import android.graphics.Typeface;
import android.graphics.Region.Op;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.StaticLayout;
@@ -46,8 +46,8 @@
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.VelocityTracker;
-import android.view.ViewStructure;
import android.view.ViewConfiguration;
+import android.view.ViewStructure;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
diff --git a/core/java/android/widget/TabHost.java b/core/java/android/widget/TabHost.java
index 583f037..32418cd 100644
--- a/core/java/android/widget/TabHost.java
+++ b/core/java/android/widget/TabHost.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.LocalActivityManager;
@@ -35,6 +33,9 @@
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
+
+import com.android.internal.R;
+
import java.util.ArrayList;
import java.util.List;
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 1f0cb7c..05f7c0a 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -16,10 +16,6 @@
package android.widget;
-import android.view.MotionEvent;
-import android.view.PointerIcon;
-import com.android.internal.R;
-
import android.annotation.DrawableRes;
import android.annotation.Nullable;
import android.content.Context;
@@ -29,11 +25,15 @@
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
+import com.android.internal.R;
+
/**
*
* Displays a list of tab labels representing each page in the parent's tab
diff --git a/core/java/android/widget/TableLayout.java b/core/java/android/widget/TableLayout.java
index eed3c2d..8bb4d16 100644
--- a/core/java/android/widget/TableLayout.java
+++ b/core/java/android/widget/TableLayout.java
@@ -16,14 +16,15 @@
package android.widget;
-import com.android.internal.R;
-
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.SparseBooleanArray;
import android.view.View;
import android.view.ViewGroup;
+
+import com.android.internal.R;
+
import java.util.regex.Pattern;
/**
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 278ceb2..a6a9db4 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -16,6 +16,9 @@
package android.widget;
+import static android.view.ViewDebug.ExportedProperty;
+import static android.widget.RemoteViews.RemoteView;
+
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
@@ -37,13 +40,10 @@
import com.android.internal.R;
-import java.util.Calendar;
-import java.util.TimeZone;
-
import libcore.icu.LocaleData;
-import static android.view.ViewDebug.ExportedProperty;
-import static android.widget.RemoteViews.*;
+import java.util.Calendar;
+import java.util.TimeZone;
/**
* <p><code>TextClock</code> can display the current date and/or time as
@@ -132,7 +132,7 @@
private CharSequence mDescFormat;
- private boolean mAttached;
+ private boolean mRegistered;
private Calendar mTime;
private String mTimeZone;
@@ -252,7 +252,7 @@
}
createTime(mTimeZone);
- // Wait until onAttachedToWindow() to handle the ticker
+ // Wait until registering for events to handle the ticker
chooseFormat(false);
}
@@ -503,7 +503,7 @@
boolean hadSeconds = mHasSeconds;
mHasSeconds = DateFormat.hasSeconds(mFormat);
- if (handleTicker && mAttached && hadSeconds != mHasSeconds) {
+ if (handleTicker && mRegistered && hadSeconds != mHasSeconds) {
if (hadSeconds) getHandler().removeCallbacks(mTicker);
else mTicker.run();
}
@@ -517,11 +517,9 @@
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- if (!mAttached) {
- mAttached = true;
+ public void onVisibilityAggregated(boolean isVisible) {
+ if (!mRegistered && isVisible) {
+ mRegistered = true;
registerReceiver();
registerObserver();
@@ -533,20 +531,13 @@
} else {
onTimeChanged();
}
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
-
- if (mAttached) {
+ } else if (mRegistered && !isVisible) {
unregisterReceiver();
unregisterObserver();
getHandler().removeCallbacks(mTicker);
- mAttached = false;
+ mRegistered = false;
}
}
@@ -569,7 +560,7 @@
}
private void registerObserver() {
- if (isAttachedToWindow()) {
+ if (mRegistered) {
if (mFormatChangeObserver == null) {
mFormatChangeObserver = new FormatChangeObserver(getHandler());
}
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 6a76c5b..e6cd798 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -32,12 +30,14 @@
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
+import com.android.internal.R;
+
+import libcore.icu.LocaleData;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Locale;
-import libcore.icu.LocaleData;
-
/**
* A widget for selecting the time of day, in either 24-hour or AM/PM mode.
* <p>
diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java
index 26e1564..6a68f60 100644
--- a/core/java/android/widget/TimePickerSpinnerDelegate.java
+++ b/core/java/android/widget/TimePickerSpinnerDelegate.java
@@ -16,6 +16,9 @@
package android.widget;
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
+import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+
import android.annotation.TestApi;
import android.content.Context;
import android.content.res.TypedArray;
@@ -29,14 +32,12 @@
import android.view.accessibility.AccessibilityEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
-import com.android.internal.R;
-import java.util.Calendar;
+import com.android.internal.R;
import libcore.icu.LocaleData;
-import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
-import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+import java.util.Calendar;
/**
* A delegate implementing the basic spinner-based TimePicker.
diff --git a/core/java/android/widget/TwoLineListItem.java b/core/java/android/widget/TwoLineListItem.java
index 69ff488..0445ebd 100644
--- a/core/java/android/widget/TwoLineListItem.java
+++ b/core/java/android/widget/TwoLineListItem.java
@@ -20,22 +20,21 @@
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
-import android.widget.RelativeLayout;
/**
- * <p>A view group with two children, intended for use in ListViews. This item has two
- * {@link android.widget.TextView TextViews} elements (or subclasses) with the ID values
+ * <p>A view group with two children, intended for use in ListViews. This item has two
+ * {@link android.widget.TextView TextViews} elements (or subclasses) with the ID values
* {@link android.R.id#text1 text1}
- * and {@link android.R.id#text2 text2}. There is an optional third View element with the
- * ID {@link android.R.id#selectedIcon selectedIcon}, which can be any View subclass
+ * and {@link android.R.id#text2 text2}. There is an optional third View element with the
+ * ID {@link android.R.id#selectedIcon selectedIcon}, which can be any View subclass
* (though it is typically a graphic View, such as {@link android.widget.ImageView ImageView})
- * that can be displayed when a TwoLineListItem has focus. Android supplies a
- * {@link android.R.layout#two_line_list_item standard layout resource for TwoLineListView}
+ * that can be displayed when a TwoLineListItem has focus. Android supplies a
+ * {@link android.R.layout#two_line_list_item standard layout resource for TwoLineListView}
* (which does not include a selected item icon), but you can design your own custom XML
* layout for this object.
- *
+ *
* @attr ref android.R.styleable#TwoLineListItem_mode
- *
+ *
* @deprecated This class can be implemented easily by apps using a {@link RelativeLayout}
* or a {@link LinearLayout}.
*/
@@ -51,7 +50,7 @@
}
public TwoLineListItem(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
+ this(context, attrs, 0);
}
public TwoLineListItem(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -70,11 +69,11 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
-
+
mText1 = (TextView) findViewById(com.android.internal.R.id.text1);
mText2 = (TextView) findViewById(com.android.internal.R.id.text2);
}
-
+
/**
* Returns a handle to the item with ID text1.
* @return A handle to the item with ID text1.
@@ -82,7 +81,7 @@
public TextView getText1() {
return mText1;
}
-
+
/**
* Returns a handle to the item with ID text2.
* @return A handle to the item with ID text2.
diff --git a/core/java/android/widget/ViewFlipper.java b/core/java/android/widget/ViewFlipper.java
index 65af7aa..e769d71 100644
--- a/core/java/android/widget/ViewFlipper.java
+++ b/core/java/android/widget/ViewFlipper.java
@@ -21,7 +21,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.TypedArray;
-import android.os.*;
+import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.RemoteViews.RemoteView;
diff --git a/core/java/android/widget/YearPickerView.java b/core/java/android/widget/YearPickerView.java
index a3f5a67..824fec8 100644
--- a/core/java/android/widget/YearPickerView.java
+++ b/core/java/android/widget/YearPickerView.java
@@ -16,8 +16,6 @@
package android.widget;
-import com.android.internal.R;
-
import android.content.Context;
import android.content.res.Resources;
import android.icu.util.Calendar;
@@ -27,6 +25,8 @@
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
+import com.android.internal.R;
+
/**
* Displays a selectable list of years.
*/
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index fb912a4..69b79971 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -30,11 +30,11 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.WindowManager;
-import android.view.View.OnClickListener;
import android.view.WindowManager.LayoutParams;
/*
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index a5b2a91..3b6073a 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -68,6 +68,7 @@
import android.widget.BaseAdapter;
import android.widget.ListView;
import com.android.internal.R;
+import com.android.internal.app.ResolverActivity.TargetInfo;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.google.android.collect.Lists;
@@ -345,6 +346,12 @@
}
@Override
+ public boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
+ return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE,
+ super.shouldAutoLaunchSingleChoice(target));
+ }
+
+ @Override
public void showTargetDetails(ResolveInfo ri) {
ComponentName name = ri.activityInfo.getComponentName();
boolean pinned = mPinnedSharedPrefs.getBoolean(name.flattenToString(), false);
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 8c5df08..8c2c236 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -379,7 +379,7 @@
public void setState(int state, long now) {
ensureNotDead();
- if (mCurState != state) {
+ if (!mDead && (mCurState != state)) {
//Slog.i(TAG, "Setting state in " + mName + "/" + mPackage + ": " + state);
commitStateTime(now);
mCurState = state;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 0aa3a7e..b60e6b5 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -10787,7 +10787,7 @@
}
int NW = in.readInt();
- if (NW > 100) {
+ if (NW > (MAX_WAKELOCKS_PER_UID+1)) {
throw new ParcelFormatException("File corrupt: too many wake locks " + NW);
}
for (int iw = 0; iw < NW; iw++) {
@@ -10796,7 +10796,7 @@
}
int NS = in.readInt();
- if (NS > 100) {
+ if (NS > (MAX_WAKELOCKS_PER_UID+1)) {
throw new ParcelFormatException("File corrupt: too many syncs " + NS);
}
for (int is = 0; is < NS; is++) {
@@ -10805,7 +10805,7 @@
}
int NJ = in.readInt();
- if (NJ > 100) {
+ if (NJ > (MAX_WAKELOCKS_PER_UID+1)) {
throw new ParcelFormatException("File corrupt: too many job timers " + NJ);
}
for (int ij = 0; ij < NJ; ij++) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 59a3563..12d4be3 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -476,11 +476,11 @@
*/
private static PathClassLoader createSystemServerClassLoader(String systemServerClasspath,
int targetSdkVersion) {
- String librarySearchPath = System.getProperty("java.library.path");
+ String libraryPath = System.getProperty("java.library.path");
return PathClassLoaderFactory.createClassLoader(systemServerClasspath,
- librarySearchPath,
- null /* libraryPermittedPath */,
+ libraryPath,
+ libraryPath,
ClassLoader.getSystemClassLoader(),
targetSdkVersion,
true /* isNamespaceShared */);
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
index 619303f..1abb59b 100644
--- a/core/java/com/android/internal/policy/BackdropFrameRenderer.java
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -110,12 +110,15 @@
int statusBarColor, int navigationBarColor) {
mDecorView = decorView;
mResizingBackgroundDrawable = resizingBackgroundDrawable != null
+ && resizingBackgroundDrawable.getConstantState() != null
? resizingBackgroundDrawable.getConstantState().newDrawable()
: null;
mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable != null
+ && captionBackgroundDrawableDrawable.getConstantState() != null
? captionBackgroundDrawableDrawable.getConstantState().newDrawable()
: null;
mUserCaptionBackgroundDrawable = userCaptionBackgroundDrawable != null
+ && userCaptionBackgroundDrawable.getConstantState() != null
? userCaptionBackgroundDrawable.getConstantState().newDrawable()
: null;
if (mCaptionBackgroundDrawable == null) {
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 644c7e9..4f7b106 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -580,7 +580,13 @@
return;
}
if (grantUriPermission) {
- inputContentInfo.requestPermission();
+ try {
+ inputContentInfo.requestPermission();
+ } catch (Exception e) {
+ Log.e(TAG, "InputConnectionInfo.requestPermission() failed", e);
+ args.callback.setCommitContentResult(false, args.seq);
+ return;
+ }
}
final boolean result =
ic.commitContent(inputContentInfo, flags, (Bundle) args.arg2);
diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java
index df9b0dd..586ece0 100644
--- a/core/java/com/android/internal/widget/LockPatternChecker.java
+++ b/core/java/com/android/internal/widget/LockPatternChecker.java
@@ -4,6 +4,7 @@
import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -29,6 +30,11 @@
* the call. Only non-0 if matched is false.
*/
void onChecked(boolean matched, int throttleTimeoutMs);
+
+ /**
+ * Called when the underlying AsyncTask was cancelled.
+ */
+ default void onCancelled() {}
}
/**
@@ -61,11 +67,19 @@
final OnVerifyCallback callback) {
AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
private int mThrottleTimeout;
+ private List<LockPatternView.Cell> patternCopy;
+
+ @Override
+ protected void onPreExecute() {
+ // Make a copy of the pattern to prevent race conditions.
+ // No need to clone the individual cells because they are immutable.
+ patternCopy = new ArrayList(pattern);
+ }
@Override
protected byte[] doInBackground(Void... args) {
try {
- return utils.verifyPattern(pattern, challenge, userId);
+ return utils.verifyPattern(patternCopy, challenge, userId);
} catch (RequestThrottledException ex) {
mThrottleTimeout = ex.getTimeoutMs();
return null;
@@ -95,11 +109,19 @@
final OnCheckCallback callback) {
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
private int mThrottleTimeout;
+ private List<LockPatternView.Cell> patternCopy;
+
+ @Override
+ protected void onPreExecute() {
+ // Make a copy of the pattern to prevent race conditions.
+ // No need to clone the individual cells because they are immutable.
+ patternCopy = new ArrayList(pattern);
+ }
@Override
protected Boolean doInBackground(Void... args) {
try {
- return utils.checkPattern(pattern, userId, callback::onEarlyMatched);
+ return utils.checkPattern(patternCopy, userId, callback::onEarlyMatched);
} catch (RequestThrottledException ex) {
mThrottleTimeout = ex.getTimeoutMs();
return false;
@@ -110,6 +132,11 @@
protected void onPostExecute(Boolean result) {
callback.onChecked(result, mThrottleTimeout);
}
+
+ @Override
+ protected void onCancelled() {
+ callback.onCancelled();
+ }
};
task.execute();
return task;
@@ -217,6 +244,11 @@
protected void onPostExecute(Boolean result) {
callback.onChecked(result, mThrottleTimeout);
}
+
+ @Override
+ protected void onCancelled() {
+ callback.onCancelled();
+ }
};
task.execute();
return task;
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 4c6350b..7950685 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -19,6 +19,14 @@
LOCAL_CFLAGS += -DENABLE_CPUSETS
endif
+# TODO: Linear blending should be enabled by default, but we are
+# TODO: making it an opt-in while it's a work in progress
+# TODO: The final test should be:
+# TODO: ifneq ($(TARGET_ENABLE_LINEAR_BLENDING),false)
+ifeq ($(TARGET_ENABLE_LINEAR_BLENDING),true)
+ LOCAL_CFLAGS += -DANDROID_ENABLE_LINEAR_BLENDING
+endif
+
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
LOCAL_CFLAGS += -DU_USING_ICU_NAMESPACE=0
@@ -214,6 +222,7 @@
LOCAL_SHARED_LIBRARIES := \
libmemtrack \
libandroidfw \
+ libbase \
libexpat \
libnativehelper \
liblog \
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 18c4ee3..9ed1588 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -16,8 +16,8 @@
#include "android_util_Binder.h"
#include "android_nio_utils.h"
#include "CreateJavaOutputStreamAdaptor.h"
-#include <Caches.h>
#include <hwui/Paint.h>
+#include <hwui/PixelRef.h>
#include <renderthread/RenderProxy.h>
#include "core_jni_helpers.h"
@@ -25,351 +25,103 @@
#include <jni.h>
#include <memory>
#include <string>
-#include <sys/mman.h>
-#include <cutils/ashmem.h>
#define DEBUG_PARCEL 0
#define ASHMEM_BITMAP_MIN_SIZE (128 * (1 << 10))
+static jclass gBitmap_class;
+static jfieldID gBitmap_nativePtr;
+static jmethodID gBitmap_constructorMethodID;
+static jmethodID gBitmap_reinitMethodID;
+static jmethodID gBitmap_getAllocationByteCountMethodID;
+
namespace android {
-class WrappedPixelRef : public SkPixelRef {
+class Bitmap {
public:
- WrappedPixelRef(Bitmap* wrapper, void* storage,
- const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
- : SkPixelRef(info)
- , mBitmap(*wrapper)
- , mStorage(storage) {
- reconfigure(info, rowBytes, ctable);
+ Bitmap(PixelRef* pixelRef)
+ : mPixelRef(pixelRef) { }
+
+ void freePixels() {
+ mInfo = mPixelRef->info();
+ mHasHardwareMipMap = mPixelRef->hasHardwareMipMap();
+ mAllocationSize = mPixelRef->getAllocationByteCount();
+ mRowBytes = mPixelRef->rowBytes();
+ mGenerationId = mPixelRef->getGenerationID();
+ mPixelRef.reset();
}
- ~WrappedPixelRef() {
- // Tell SkRefCnt that everything is as it expects by forcing
- // the refcnt to 1
- internal_dispose_restore_refcnt_to_1();
- SkSafeUnref(mColorTable);
+ bool valid() {
+ return !!mPixelRef;
}
- void reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
- if (kIndex_8_SkColorType != newInfo.colorType()) {
- ctable = nullptr;
+ PixelRef* pixelRef() { return mPixelRef.get(); }
+
+ void assertValid() {
+ LOG_ALWAYS_FATAL_IF(!valid(), "Error, cannot access an invalid/free'd bitmap here!");
+ }
+
+ void getSkBitmap(SkBitmap* outBitmap) {
+ assertValid();
+ mPixelRef->getSkBitmap(outBitmap);
+ }
+
+ bool hasHardwareMipMap() {
+ if (mPixelRef) {
+ return mPixelRef->hasHardwareMipMap();
}
- mRowBytes = rowBytes;
- if (mColorTable != ctable) {
- SkSafeUnref(mColorTable);
- mColorTable = ctable;
- SkSafeRef(mColorTable);
- }
-
- // Need to validate the alpha type to filter against the color type
- // to prevent things like a non-opaque RGB565 bitmap
- SkAlphaType alphaType;
- LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
- newInfo.colorType(), newInfo.alphaType(), &alphaType),
- "Failed to validate alpha type!");
-
- // Dirty hack is dirty
- // TODO: Figure something out here, Skia's current design makes this
- // really hard to work with. Skia really, really wants immutable objects,
- // but with the nested-ref-count hackery going on that's just not
- // feasible without going insane trying to figure it out
- SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info());
- *myInfo = newInfo;
- changeAlphaType(alphaType);
-
- // Docs say to only call this in the ctor, but we're going to call
- // it anyway even if this isn't always the ctor.
- // TODO: Fix this too as part of the above TODO
- setPreLocked(mStorage, mRowBytes, mColorTable);
- }
-
- // Can't mark as override since SkPixelRef::rowBytes isn't virtual
- // but that's OK since we just want BitmapWrapper to be able to rely
- // on calling rowBytes() on an unlocked pixelref, which it will be
- // doing on a WrappedPixelRef type, not a SkPixelRef, so static
- // dispatching will do what we want.
- size_t rowBytes() const { return mRowBytes; }
- SkColorTable* colorTable() const { return mColorTable; }
-
- bool hasHardwareMipMap() const {
return mHasHardwareMipMap;
}
void setHasHardwareMipMap(bool hasMipMap) {
- mHasHardwareMipMap = hasMipMap;
+ assertValid();
+ mPixelRef->setHasHardwareMipMap(hasMipMap);
}
-protected:
- virtual bool onNewLockPixels(LockRec* rec) override {
- rec->fPixels = mStorage;
- rec->fRowBytes = mRowBytes;
- rec->fColorTable = mColorTable;
- return true;
+ void setAlphaType(SkAlphaType alphaType) {
+ assertValid();
+ mPixelRef->setAlphaType(alphaType);
}
- virtual void onUnlockPixels() override {
- // nothing
+ const SkImageInfo& info() {
+ if (mPixelRef) {
+ return mPixelRef->info();
+ }
+ return mInfo;
}
- virtual size_t getAllocatedSizeInBytes() const override {
- return info().getSafeSize(mRowBytes);
+ size_t getAllocationByteCount() const {
+ if (mPixelRef) {
+ return mPixelRef->getAllocationByteCount();
+ }
+ return mAllocationSize;
}
+ size_t rowBytes() const {
+ if (mPixelRef) {
+ return mPixelRef->rowBytes();
+ }
+ return mRowBytes;
+ }
+
+ uint32_t getGenerationID() const {
+ if (mPixelRef) {
+ return mPixelRef->getGenerationID();
+ }
+ return mGenerationId;
+ }
+
+ ~Bitmap() { }
+
private:
- Bitmap& mBitmap;
- void* mStorage;
- size_t mRowBytes = 0;
- SkColorTable* mColorTable = nullptr;
- bool mHasHardwareMipMap = false;
-
- virtual void internal_dispose() const override {
- mBitmap.onStrongRefDestroyed();
- }
+ sk_sp<PixelRef> mPixelRef;
+ SkImageInfo mInfo;
+ bool mHasHardwareMipMap;
+ size_t mAllocationSize;
+ size_t mRowBytes;
+ uint32_t mGenerationId;
};
-Bitmap::Bitmap(JNIEnv* env, jbyteArray storageObj, void* address,
- const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
- : mPixelStorageType(PixelStorageType::Java) {
- env->GetJavaVM(&mPixelStorage.java.jvm);
- mPixelStorage.java.jweakRef = env->NewWeakGlobalRef(storageObj);
- mPixelStorage.java.jstrongRef = nullptr;
- mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
- // Note: this will trigger a call to onStrongRefDestroyed(), but
- // we want the pixel ref to have a ref count of 0 at this point
- mPixelRef->unref();
-}
-
-Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc,
- const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
- : mPixelStorageType(PixelStorageType::External) {
- mPixelStorage.external.address = address;
- mPixelStorage.external.context = context;
- mPixelStorage.external.freeFunc = freeFunc;
- mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
- // Note: this will trigger a call to onStrongRefDestroyed(), but
- // we want the pixel ref to have a ref count of 0 at this point
- mPixelRef->unref();
-}
-
-Bitmap::Bitmap(void* address, int fd, size_t mappedSize,
- const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
- : mPixelStorageType(PixelStorageType::Ashmem) {
- mPixelStorage.ashmem.address = address;
- mPixelStorage.ashmem.fd = fd;
- mPixelStorage.ashmem.size = mappedSize;
- mPixelRef.reset(new WrappedPixelRef(this, address, info, rowBytes, ctable));
- // Note: this will trigger a call to onStrongRefDestroyed(), but
- // we want the pixel ref to have a ref count of 0 at this point
- mPixelRef->unref();
-}
-Bitmap::~Bitmap() {
- doFreePixels();
-}
-
-void Bitmap::freePixels() {
- AutoMutex _lock(mLock);
- if (mPinnedRefCount == 0) {
- doFreePixels();
- mPixelStorageType = PixelStorageType::Invalid;
- }
-}
-
-void Bitmap::doFreePixels() {
- switch (mPixelStorageType) {
- case PixelStorageType::Invalid:
- // already free'd, nothing to do
- break;
- case PixelStorageType::External:
- mPixelStorage.external.freeFunc(mPixelStorage.external.address,
- mPixelStorage.external.context);
- break;
- case PixelStorageType::Ashmem:
- munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
- close(mPixelStorage.ashmem.fd);
- break;
- case PixelStorageType::Java:
- JNIEnv* env = jniEnv();
- LOG_ALWAYS_FATAL_IF(mPixelStorage.java.jstrongRef,
- "Deleting a bitmap wrapper while there are outstanding strong "
- "references! mPinnedRefCount = %d", mPinnedRefCount);
- env->DeleteWeakGlobalRef(mPixelStorage.java.jweakRef);
- break;
- }
-
- if (android::uirenderer::Caches::hasInstance()) {
- android::uirenderer::Caches::getInstance().textureCache.releaseTexture(
- mPixelRef->getStableID());
- }
-}
-
-bool Bitmap::hasHardwareMipMap() {
- return mPixelRef->hasHardwareMipMap();
-}
-
-void Bitmap::setHasHardwareMipMap(bool hasMipMap) {
- mPixelRef->setHasHardwareMipMap(hasMipMap);
-}
-
-int Bitmap::getAshmemFd() const {
- switch (mPixelStorageType) {
- case PixelStorageType::Ashmem:
- return mPixelStorage.ashmem.fd;
- default:
- return -1;
- }
-}
-
-const SkImageInfo& Bitmap::info() const {
- return mPixelRef->info();
-}
-
-size_t Bitmap::rowBytes() const {
- return mPixelRef->rowBytes();
-}
-
-SkPixelRef* Bitmap::peekAtPixelRef() const {
- assertValid();
- return mPixelRef.get();
-}
-
-SkPixelRef* Bitmap::refPixelRef() {
- assertValid();
- android::AutoMutex _lock(mLock);
- return refPixelRefLocked();
-}
-
-SkPixelRef* Bitmap::refPixelRefLocked() {
- mPixelRef->ref();
- if (mPixelRef->unique()) {
- // We just restored this from 0, pin the pixels and inc the strong count
- // Note that there *might be* an incoming onStrongRefDestroyed from whatever
- // last unref'd
- pinPixelsLocked();
- mPinnedRefCount++;
- }
- return mPixelRef.get();
-}
-
-void Bitmap::reconfigure(const SkImageInfo& info, size_t rowBytes,
- SkColorTable* ctable) {
- mPixelRef->reconfigure(info, rowBytes, ctable);
-}
-
-void Bitmap::reconfigure(const SkImageInfo& info) {
- reconfigure(info, info.minRowBytes(), nullptr);
-}
-
-void Bitmap::setAlphaType(SkAlphaType alphaType) {
- if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
- return;
- }
-
- mPixelRef->changeAlphaType(alphaType);
-}
-
-void Bitmap::detachFromJava() {
- bool disposeSelf;
- {
- android::AutoMutex _lock(mLock);
- mAttachedToJava = false;
- disposeSelf = shouldDisposeSelfLocked();
- }
- if (disposeSelf) {
- delete this;
- }
-}
-
-bool Bitmap::shouldDisposeSelfLocked() {
- return mPinnedRefCount == 0 && !mAttachedToJava;
-}
-
-JNIEnv* Bitmap::jniEnv() {
- JNIEnv* env;
- auto success = mPixelStorage.java.jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
- LOG_ALWAYS_FATAL_IF(success != JNI_OK,
- "Failed to get JNIEnv* from JVM: %p", mPixelStorage.java.jvm);
- return env;
-}
-
-void Bitmap::onStrongRefDestroyed() {
- bool disposeSelf = false;
- {
- android::AutoMutex _lock(mLock);
- if (mPinnedRefCount > 0) {
- mPinnedRefCount--;
- if (mPinnedRefCount == 0) {
- unpinPixelsLocked();
- disposeSelf = shouldDisposeSelfLocked();
- }
- }
- }
- if (disposeSelf) {
- delete this;
- }
-}
-
-void Bitmap::pinPixelsLocked() {
- switch (mPixelStorageType) {
- case PixelStorageType::Invalid:
- LOG_ALWAYS_FATAL("Cannot pin invalid pixels!");
- break;
- case PixelStorageType::External:
- case PixelStorageType::Ashmem:
- // Nothing to do
- break;
- case PixelStorageType::Java: {
- JNIEnv* env = jniEnv();
- if (!mPixelStorage.java.jstrongRef) {
- mPixelStorage.java.jstrongRef = reinterpret_cast<jbyteArray>(
- env->NewGlobalRef(mPixelStorage.java.jweakRef));
- if (!mPixelStorage.java.jstrongRef) {
- LOG_ALWAYS_FATAL("Failed to acquire strong reference to pixels");
- }
- }
- break;
- }
- }
-}
-
-void Bitmap::unpinPixelsLocked() {
- switch (mPixelStorageType) {
- case PixelStorageType::Invalid:
- LOG_ALWAYS_FATAL("Cannot unpin invalid pixels!");
- break;
- case PixelStorageType::External:
- case PixelStorageType::Ashmem:
- // Don't need to do anything
- break;
- case PixelStorageType::Java: {
- JNIEnv* env = jniEnv();
- if (mPixelStorage.java.jstrongRef) {
- env->DeleteGlobalRef(mPixelStorage.java.jstrongRef);
- mPixelStorage.java.jstrongRef = nullptr;
- }
- break;
- }
- }
-}
-
-void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
- assertValid();
- android::AutoMutex _lock(mLock);
- // Safe because mPixelRef is a WrappedPixelRef type, otherwise rowBytes()
- // would require locking the pixels first.
- outBitmap->setInfo(mPixelRef->info(), mPixelRef->rowBytes());
- outBitmap->setPixelRef(refPixelRefLocked())->unref();
- outBitmap->setHasHardwareMipMap(hasHardwareMipMap());
-}
-
-void Bitmap::assertValid() const {
- LOG_ALWAYS_FATAL_IF(mPixelStorageType == PixelStorageType::Invalid,
- "Error, cannot access an invalid/free'd bitmap here!");
-}
-
-} // namespace android
-
-using namespace android;
-
// Convenience class that does not take a global ref on the pixels, relying
// on the caller already having a local JNI ref
class LocalScopedBitmap {
@@ -382,7 +134,7 @@
}
void* pixels() {
- return mBitmap->peekAtPixelRef()->pixels();
+ return mBitmap->pixelRef()->pixels();
}
bool valid() {
@@ -393,6 +145,78 @@
Bitmap* mBitmap;
};
+namespace bitmap {
+
+// Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
+static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
+ // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
+ // irrelevant. This just tests to ensure that the SkAlphaType is not
+ // opposite of isPremultiplied.
+ if (isPremultiplied) {
+ SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
+ } else {
+ SkASSERT(info.alphaType() != kPremul_SkAlphaType);
+ }
+}
+
+void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
+ bool isPremultiplied)
+{
+ // The caller needs to have already set the alpha type properly, so the
+ // native SkBitmap stays in sync with the Java Bitmap.
+ assert_premultiplied(info, isPremultiplied);
+
+ env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
+ info.width(), info.height(), isPremultiplied);
+}
+
+int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
+{
+ return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
+}
+
+jobject createBitmap(JNIEnv* env, PixelRef* pixelRef,
+ int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
+ int density) {
+ bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
+ bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
+ // The caller needs to have already set the alpha type properly, so the
+ // native SkBitmap stays in sync with the Java Bitmap.
+ assert_premultiplied(pixelRef->info(), isPremultiplied);
+ Bitmap* bitmap = new Bitmap(pixelRef);
+ jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
+ reinterpret_cast<jlong>(bitmap), pixelRef->width(), pixelRef->height(), density, isMutable,
+ isPremultiplied, ninePatchChunk, ninePatchInsets);
+
+ if (env->ExceptionCheck() != 0) {
+ ALOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ }
+ return obj;
+}
+
+void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap) {
+ LocalScopedBitmap bitmap(bitmapHandle);
+ bitmap->getSkBitmap(outBitmap);
+}
+
+PixelRef* toPixelRef(JNIEnv* env, jobject bitmap) {
+ SkASSERT(env);
+ SkASSERT(bitmap);
+ SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
+ jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
+ LocalScopedBitmap localBitmap(bitmapHandle);
+ localBitmap->assertValid();
+ return localBitmap->pixelRef();
+}
+
+} // namespace bitmap
+
+} // namespace android
+
+using namespace android;
+using namespace android::bitmap;
+
///////////////////////////////////////////////////////////////////////////////
// Conversions to/from SkColor, for get/setPixels, and the create method, which
// is basically like setPixels
@@ -698,8 +522,8 @@
///////////////////////////////////////////////////////////////////////////////
static int getPremulBitmapCreateFlags(bool isMutable) {
- int flags = GraphicsJNI::kBitmapCreateFlag_Premultiplied;
- if (isMutable) flags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
+ int flags = android::bitmap::kBitmapCreateFlag_Premultiplied;
+ if (isMutable) flags |= android::bitmap::kBitmapCreateFlag_Mutable;
return flags;
}
@@ -721,9 +545,10 @@
}
SkBitmap bitmap;
- bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType));
+ bitmap.setInfo(SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType,
+ GraphicsJNI::defaultColorSpace()));
- Bitmap* nativeBitmap = GraphicsJNI::allocateJavaPixelRef(env, &bitmap, NULL);
+ PixelRef* nativeBitmap = GraphicsJNI::allocateHeapPixelRef(&bitmap, NULL);
if (!nativeBitmap) {
return NULL;
}
@@ -733,7 +558,7 @@
0, 0, width, height, bitmap);
}
- return GraphicsJNI::createBitmap(env, nativeBitmap,
+ return createBitmap(env, nativeBitmap,
getPremulBitmapCreateFlags(isMutable));
}
@@ -742,35 +567,34 @@
SkBitmap src;
reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
- SkBitmap result;
- JavaPixelAllocator allocator(env);
+ SkBitmap result;
+ HeapAllocator allocator;
if (!src.copyTo(&result, dstCT, &allocator)) {
return NULL;
}
- Bitmap* bitmap = allocator.getStorageObjAndReset();
- return GraphicsJNI::createBitmap(env, bitmap,
- getPremulBitmapCreateFlags(isMutable));
+ auto pixelRef = allocator.getStorageObjAndReset();
+ return createBitmap(env, pixelRef, getPremulBitmapCreateFlags(isMutable));
}
-static Bitmap* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
+static PixelRef* Bitmap_copyAshmemImpl(JNIEnv* env, SkBitmap& src, SkColorType& dstCT) {
SkBitmap result;
AshmemPixelAllocator allocator(env);
if (!src.copyTo(&result, dstCT, &allocator)) {
return NULL;
}
- Bitmap* bitmap = allocator.getStorageObjAndReset();
- bitmap->peekAtPixelRef()->setImmutable();
- return bitmap;
+ auto pixelRef = allocator.getStorageObjAndReset();
+ pixelRef->setImmutable();
+ return pixelRef;
}
static jobject Bitmap_copyAshmem(JNIEnv* env, jobject, jlong srcHandle) {
SkBitmap src;
reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
SkColorType dstCT = src.colorType();
- Bitmap* bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
- jobject ret = GraphicsJNI::createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
+ auto pixelRef = Bitmap_copyAshmemImpl(env, src, dstCT);
+ jobject ret = createBitmap(env, pixelRef, getPremulBitmapCreateFlags(false));
return ret;
}
@@ -778,13 +602,13 @@
SkBitmap src;
reinterpret_cast<Bitmap*>(srcHandle)->getSkBitmap(&src);
SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
- Bitmap* bitmap = Bitmap_copyAshmemImpl(env, src, dstCT);
- jobject ret = GraphicsJNI::createBitmap(env, bitmap, getPremulBitmapCreateFlags(false));
+ auto pixelRef = Bitmap_copyAshmemImpl(env, src, dstCT);
+ jobject ret = createBitmap(env, pixelRef, getPremulBitmapCreateFlags(false));
return ret;
}
static void Bitmap_destruct(Bitmap* bitmap) {
- bitmap->detachFromJava();
+ delete bitmap;
}
static jlong Bitmap_getNativeFinalizer(JNIEnv*, jobject) {
@@ -798,17 +622,17 @@
}
static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
- jint width, jint height, jint configHandle, jint allocSize,
- jboolean requestPremul) {
+ jint width, jint height, jint configHandle, jboolean requestPremul) {
LocalScopedBitmap bitmap(bitmapHandle);
+ bitmap->assertValid();
SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle);
// ARGB_4444 is a deprecated format, convert automatically to 8888
if (colorType == kARGB_4444_SkColorType) {
colorType = kN32_SkColorType;
}
-
- if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) {
+ size_t requestedSize = width * height * SkColorTypeBytesPerPixel(colorType);
+ if (requestedSize > bitmap->getAllocationByteCount()) {
// done in native as there's no way to get BytesPerPixel in Java
doThrowIAE(env, "Bitmap not large enough to support new configuration");
return;
@@ -823,7 +647,8 @@
// Otherwise respect the premultiplied request.
alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
}
- bitmap->reconfigure(SkImageInfo::Make(width, height, colorType, alphaType));
+ bitmap->pixelRef()->reconfigure(SkImageInfo::Make(width, height, colorType, alphaType,
+ sk_sp<SkColorSpace>(bitmap->info().colorSpace())));
}
// These must match the int values in Bitmap.java
@@ -893,7 +718,7 @@
static jint Bitmap_getGenerationId(JNIEnv* env, jobject, jlong bitmapHandle) {
LocalScopedBitmap bitmap(bitmapHandle);
- return static_cast<jint>(bitmap->peekAtPixelRef()->getGenerationID());
+ return static_cast<jint>(bitmap->getGenerationID());
}
static jboolean Bitmap_isPremultiplied(JNIEnv* env, jobject, jlong bitmapHandle) {
@@ -956,6 +781,7 @@
const bool isMutable = p->readInt32() != 0;
const SkColorType colorType = (SkColorType)p->readInt32();
const SkAlphaType alphaType = (SkAlphaType)p->readInt32();
+ const bool isSRGB = p->readInt32() != 0;
const int width = p->readInt32();
const int height = p->readInt32();
const int rowBytes = p->readInt32();
@@ -972,7 +798,8 @@
std::unique_ptr<SkBitmap> bitmap(new SkBitmap);
- if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType), rowBytes)) {
+ if (!bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType,
+ isSRGB ? SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named) : nullptr), rowBytes)) {
return NULL;
}
@@ -1005,7 +832,7 @@
}
// Map the bitmap in place from the ashmem region if possible otherwise copy.
- Bitmap* nativeBitmap;
+ PixelRef* nativeBitmap;
if (blob.fd() >= 0 && (blob.isMutable() || !isMutable) && (size >= ASHMEM_BITMAP_MIN_SIZE)) {
#if DEBUG_PARCEL
ALOGD("Bitmap.createFromParcel: mapped contents of %s bitmap from %s blob "
@@ -1053,7 +880,7 @@
#endif
// Copy the pixels into a new buffer.
- nativeBitmap = GraphicsJNI::allocateJavaPixelRef(env, bitmap.get(), ctable);
+ nativeBitmap = GraphicsJNI::allocateHeapPixelRef(bitmap.get(), ctable);
SkSafeUnref(ctable);
if (!nativeBitmap) {
blob.release();
@@ -1068,7 +895,7 @@
blob.release();
}
- return GraphicsJNI::createBitmap(env, nativeBitmap,
+ return createBitmap(env, nativeBitmap,
getPremulBitmapCreateFlags(isMutable), NULL, NULL, density);
}
@@ -1084,12 +911,16 @@
android::Parcel* p = android::parcelForJavaObject(env, parcel);
SkBitmap bitmap;
- android::Bitmap* androidBitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
+ auto androidBitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
androidBitmap->getSkBitmap(&bitmap);
+ sk_sp<SkColorSpace> sRGB = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+ bool isSRGB = bitmap.colorSpace() == sRGB.get();
+
p->writeInt32(isMutable);
p->writeInt32(bitmap.colorType());
p->writeInt32(bitmap.alphaType());
+ p->writeInt32(isSRGB); // TODO: We should write the color space (b/32072280)
p->writeInt32(bitmap.width());
p->writeInt32(bitmap.height());
p->writeInt32(bitmap.rowBytes());
@@ -1111,7 +942,7 @@
// Transfer the underlying ashmem region if we have one and it's immutable.
android::status_t status;
- int fd = androidBitmap->getAshmemFd();
+ int fd = androidBitmap->pixelRef()->getAshmemFd();
if (fd >= 0 && !isMutable && p->allowFds()) {
#if DEBUG_PARCEL
ALOGD("Bitmap.writeToParcel: transferring immutable bitmap's ashmem fd as "
@@ -1165,7 +996,7 @@
const android::Paint* paint = reinterpret_cast<android::Paint*>(paintHandle);
SkIPoint offset;
SkBitmap dst;
- JavaPixelAllocator allocator(env);
+ HeapAllocator allocator;
src.extractAlpha(&dst, paint, &allocator, &offset);
// If Skia can't allocate pixels for destination bitmap, it resets
@@ -1181,7 +1012,7 @@
env->ReleaseIntArrayElements(offsetXY, array, 0);
}
- return GraphicsJNI::createBitmap(env, allocator.getStorageObjAndReset(),
+ return createBitmap(env, allocator.getStorageObjAndReset(),
getPremulBitmapCreateFlags(true));
}
@@ -1302,7 +1133,9 @@
reinterpret_cast<Bitmap*>(bm1Handle)->getSkBitmap(&bm1);
if (bm0.width() != bm1.width() ||
bm0.height() != bm1.height() ||
- bm0.colorType() != bm1.colorType()) {
+ bm0.colorType() != bm1.colorType() ||
+ bm0.alphaType() != bm1.alphaType() ||
+ bm0.colorSpace() != bm1.colorSpace()) {
return JNI_FALSE;
}
@@ -1357,7 +1190,7 @@
static jlong Bitmap_refPixelRef(JNIEnv* env, jobject, jlong bitmapHandle) {
LocalScopedBitmap bitmap(bitmapHandle);
- SkPixelRef* pixelRef = bitmap.valid() ? bitmap->peekAtPixelRef() : nullptr;
+ SkPixelRef* pixelRef = bitmap->pixelRef();
SkSafeRef(pixelRef);
return reinterpret_cast<jlong>(pixelRef);
}
@@ -1370,7 +1203,26 @@
android::uirenderer::renderthread::RenderProxy::prepareToDraw(bitmap);
}
+static jint Bitmap_getAllocationByteCount(JNIEnv* env, jobject, jlong bitmapPtr) {
+ LocalScopedBitmap bitmapHandle(bitmapPtr);
+ return static_cast<jint>(bitmapHandle->getAllocationByteCount());
+}
+
///////////////////////////////////////////////////////////////////////////////
+static jclass make_globalref(JNIEnv* env, const char classname[])
+{
+ jclass c = env->FindClass(classname);
+ SkASSERT(c);
+ return (jclass) env->NewGlobalRef(c);
+}
+
+static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
+ const char fieldname[], const char type[])
+{
+ jfieldID id = env->GetFieldID(clazz, fieldname, type);
+ SkASSERT(id);
+ return id;
+}
static const JNINativeMethod gBitmapMethods[] = {
{ "nativeCreate", "([IIIIIIZ)Landroid/graphics/Bitmap;",
@@ -1383,7 +1235,7 @@
(void*)Bitmap_copyAshmemConfig },
{ "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
{ "nativeRecycle", "(J)Z", (void*)Bitmap_recycle },
- { "nativeReconfigure", "(JIIIIZ)V", (void*)Bitmap_reconfigure },
+ { "nativeReconfigure", "(JIIIZ)V", (void*)Bitmap_reconfigure },
{ "nativeCompress", "(JIILjava/io/OutputStream;[B)Z",
(void*)Bitmap_compress },
{ "nativeErase", "(JI)V", (void*)Bitmap_erase },
@@ -1414,10 +1266,16 @@
{ "nativeSameAs", "(JJ)Z", (void*)Bitmap_sameAs },
{ "nativeRefPixelRef", "(J)J", (void*)Bitmap_refPixelRef },
{ "nativePrepareToDraw", "(J)V", (void*)Bitmap_prepareToDraw },
+ { "nativeGetAllocationByteCount", "(J)I", (void*)Bitmap_getAllocationByteCount },
};
int register_android_graphics_Bitmap(JNIEnv* env)
{
+ gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
+ gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
+ gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(JIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
+ gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
+ gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
NELEM(gBitmapMethods));
-}
+}
\ No newline at end of file
diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h
index aaea178..588a99c 100644
--- a/core/jni/android/graphics/Bitmap.h
+++ b/core/jni/android/graphics/Bitmap.h
@@ -20,106 +20,38 @@
#include <SkBitmap.h>
#include <SkColorTable.h>
#include <SkImageInfo.h>
-#include <utils/Mutex.h>
-#include <memory>
+#include <SkPixelRef.h>
namespace android {
-enum class PixelStorageType {
- Invalid,
- External,
- Java,
- Ashmem,
+class PixelRef;
+
+namespace bitmap {
+
+enum BitmapCreateFlags {
+ kBitmapCreateFlag_None = 0x0,
+ kBitmapCreateFlag_Mutable = 0x1,
+ kBitmapCreateFlag_Premultiplied = 0x2,
};
-class WrappedPixelRef;
+jobject createBitmap(JNIEnv* env, PixelRef* bitmap,
+ int bitmapCreateFlags, jbyteArray ninePatchChunk = NULL,
+ jobject ninePatchInsets = NULL, int density = -1);
-typedef void (*FreeFunc)(void* addr, void* context);
-/**
- * Glue-thingy that deals with managing the interaction between the Java
- * Bitmap object & SkBitmap along with trying to map a notion of strong/weak
- * lifecycles onto SkPixelRef which only has strong counts to avoid requiring
- * two GC passes to free the byte[] that backs a Bitmap.
- *
- * Since not all Bitmaps are byte[]-backed it also supports external allocations,
- * which currently is used by screenshots to wrap a gralloc buffer.
- */
-class Bitmap {
-public:
- Bitmap(JNIEnv* env, jbyteArray storageObj, void* address,
- const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
- Bitmap(void* address, void* context, FreeFunc freeFunc,
- const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
- Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
- size_t rowBytes, SkColorTable* ctable);
+void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap);
- const SkImageInfo& info() const;
+PixelRef* toPixelRef(JNIEnv* env, jobject bitmap);
- // Returns nullptr if it is not backed by a jbyteArray
- jbyteArray javaByteArray() const {
- return mPixelStorageType == PixelStorageType::Java
- ? mPixelStorage.java.jstrongRef : nullptr;
- }
+/** Reinitialize a bitmap. bitmap must already have its SkAlphaType set in
+ sync with isPremultiplied
+*/
+void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
+ bool isPremultiplied);
- int width() const { return info().width(); }
- int height() const { return info().height(); }
- size_t rowBytes() const;
- SkPixelRef* peekAtPixelRef() const;
- SkPixelRef* refPixelRef();
- bool valid() const { return mPixelStorageType != PixelStorageType::Invalid; }
+int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap);
- void reconfigure(const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
- void reconfigure(const SkImageInfo& info);
- void setAlphaType(SkAlphaType alphaType);
-
- void getSkBitmap(SkBitmap* outBitmap);
- void detachFromJava();
-
- void freePixels();
-
- bool hasHardwareMipMap();
- void setHasHardwareMipMap(bool hasMipMap);
- int getAshmemFd() const;
-
-private:
- friend class WrappedPixelRef;
-
- ~Bitmap();
- void doFreePixels();
- void onStrongRefDestroyed();
-
- void pinPixelsLocked();
- void unpinPixelsLocked();
- JNIEnv* jniEnv();
- bool shouldDisposeSelfLocked();
- void assertValid() const;
- SkPixelRef* refPixelRefLocked();
-
- android::Mutex mLock;
- int mPinnedRefCount = 0;
- std::unique_ptr<WrappedPixelRef> mPixelRef;
- PixelStorageType mPixelStorageType;
- bool mAttachedToJava = true;
-
- union {
- struct {
- void* address;
- void* context;
- FreeFunc freeFunc;
- } external;
- struct {
- void* address;
- int fd;
- size_t size;
- } ashmem;
- struct {
- JavaVM* jvm;
- jweak jweakRef;
- jbyteArray jstrongRef;
- } java;
- } mPixelStorage;
-};
+} // namespace bitmap
} // namespace android
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 77799d6..5c24585 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -162,7 +162,7 @@
class RecyclingPixelAllocator : public SkBitmap::Allocator {
public:
- RecyclingPixelAllocator(android::Bitmap* bitmap, unsigned int size)
+ RecyclingPixelAllocator(android::PixelRef* bitmap, unsigned int size)
: mBitmap(bitmap), mSize(size) {
}
@@ -190,16 +190,17 @@
}
mBitmap->reconfigure(info, bitmap->rowBytes(), ctable);
- bitmap->setPixelRef(mBitmap->refPixelRef())->unref();
+ mBitmap->ref();
+ bitmap->setPixelRef(mBitmap)->unref();
// since we're already allocated, we lockPixels right away
- // HeapAllocator/JavaPixelAllocator behaves this way too
+ // HeapAllocator behaves this way too
bitmap->lockPixels();
return true;
}
private:
- android::Bitmap* const mBitmap;
+ android::PixelRef* const mBitmap;
const unsigned int mSize;
};
@@ -326,20 +327,20 @@
scaledHeight = static_cast<int>(scaledHeight * scale + 0.5f);
}
- android::Bitmap* reuseBitmap = nullptr;
+ android::PixelRef* reuseBitmap = nullptr;
unsigned int existingBufferSize = 0;
if (javaBitmap != NULL) {
- reuseBitmap = GraphicsJNI::getBitmap(env, javaBitmap);
- if (reuseBitmap->peekAtPixelRef()->isImmutable()) {
+ reuseBitmap = bitmap::toPixelRef(env, javaBitmap);
+ if (reuseBitmap->isImmutable()) {
ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
javaBitmap = NULL;
reuseBitmap = nullptr;
} else {
- existingBufferSize = GraphicsJNI::getBitmapAllocationByteCount(env, javaBitmap);
+ existingBufferSize = bitmap::getBitmapAllocationByteCount(env, javaBitmap);
}
}
- JavaPixelAllocator javaAllocator(env);
+ HeapAllocator defaultAllocator;
RecyclingPixelAllocator recyclingAllocator(reuseBitmap, existingBufferSize);
ScaleCheckingAllocator scaleCheckingAllocator(scale, existingBufferSize);
SkBitmap::HeapAllocator heapAllocator;
@@ -353,10 +354,10 @@
decodeAllocator = &recyclingAllocator;
} else if (willScale) {
// This will allocate pixels using a HeapAllocator, since there will be an extra
- // scaling step that copies these pixels into Java memory.
+ // scaling step.
decodeAllocator = &heapAllocator;
} else {
- decodeAllocator = &javaAllocator;
+ decodeAllocator = &defaultAllocator;
}
// Set the decode colorType. This is necessary because we can't always support
@@ -384,11 +385,8 @@
// Set the alpha type for the decode.
SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied);
- // Enable legacy behavior to avoid any gamma correction. Android's assets are
- // adjusted to expect a non-gamma correct premultiply.
- sk_sp<SkColorSpace> colorSpace = nullptr;
- const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(), decodeColorType,
- alphaType, colorSpace);
+ const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(),
+ decodeColorType, alphaType, GraphicsJNI::defaultColorSpace());
SkImageInfo bitmapInfo = decodeInfo;
if (decodeColorType == kGray_8_SkColorType) {
@@ -412,7 +410,7 @@
// Use SkAndroidCodec to perform the decode.
SkAndroidCodec::AndroidOptions codecOptions;
- codecOptions.fZeroInitialized = (decodeAllocator == &javaAllocator) ?
+ codecOptions.fZeroInitialized = decodeAllocator == &defaultAllocator ?
SkCodec::kYes_ZeroInitialized : SkCodec::kNo_ZeroInitialized;
codecOptions.fColorPtr = colorPtr;
codecOptions.fColorCount = colorCount;
@@ -451,8 +449,10 @@
jobject ninePatchInsets = NULL;
if (peeker.mHasInsets) {
ninePatchInsets = env->NewObject(gInsetStruct_class, gInsetStruct_constructorMethodID,
- peeker.mOpticalInsets[0], peeker.mOpticalInsets[1], peeker.mOpticalInsets[2], peeker.mOpticalInsets[3],
- peeker.mOutlineInsets[0], peeker.mOutlineInsets[1], peeker.mOutlineInsets[2], peeker.mOutlineInsets[3],
+ peeker.mOpticalInsets[0], peeker.mOpticalInsets[1],
+ peeker.mOpticalInsets[2], peeker.mOpticalInsets[3],
+ peeker.mOutlineInsets[0], peeker.mOutlineInsets[1],
+ peeker.mOutlineInsets[2], peeker.mOutlineInsets[3],
peeker.mOutlineRadius, peeker.mOutlineAlpha, scale);
if (ninePatchInsets == NULL) {
return nullObjectReturn("nine patch insets == null");
@@ -477,7 +477,7 @@
if (javaBitmap != nullptr) {
outputAllocator = &recyclingAllocator;
} else {
- outputAllocator = &javaAllocator;
+ outputAllocator = &defaultAllocator;
}
SkColorType scaledColorType = colorTypeForScaledOutput(decodingBitmap.colorType());
@@ -494,11 +494,11 @@
}
SkPaint paint;
- // kSrc_Mode instructs us to overwrite the unininitialized pixels in
+ // kSrc_Mode instructs us to overwrite the uninitialized pixels in
// outputBitmap. Otherwise we would blend by default, which is not
// what we want.
paint.setXfermodeMode(SkXfermode::kSrc_Mode);
- paint.setFilterQuality(kLow_SkFilterQuality);
+ paint.setFilterQuality(kLow_SkFilterQuality); // bilinear filtering
SkCanvas canvas(outputBitmap);
canvas.scale(sx, sy);
@@ -529,18 +529,18 @@
bool isPremultiplied = !requireUnpremultiplied;
if (javaBitmap != nullptr) {
- GraphicsJNI::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied);
+ bitmap::reinitBitmap(env, javaBitmap, outputBitmap.info(), isPremultiplied);
outputBitmap.notifyPixelsChanged();
// If a java bitmap was passed in for reuse, pass it back
return javaBitmap;
}
int bitmapCreateFlags = 0x0;
- if (isMutable) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Mutable;
- if (isPremultiplied) bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
+ if (isMutable) bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Mutable;
+ if (isPremultiplied) bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
// now create the java bitmap
- return GraphicsJNI::createBitmap(env, javaAllocator.getStorageObjAndReset(),
+ return bitmap::createBitmap(env, defaultAllocator.getStorageObjAndReset(),
bitmapCreateFlags, ninePatchChunk, ninePatchInsets, -1);
}
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 970001a..7d0915b 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -148,26 +148,26 @@
}
// Recycle a bitmap if possible.
- android::Bitmap* recycledBitmap = nullptr;
+ android::PixelRef* recycledBitmap = nullptr;
size_t recycledBytes = 0;
if (javaBitmap) {
- recycledBitmap = GraphicsJNI::getBitmap(env, javaBitmap);
- if (recycledBitmap->peekAtPixelRef()->isImmutable()) {
+ recycledBitmap = bitmap::toPixelRef(env, javaBitmap);
+ if (recycledBitmap->isImmutable()) {
ALOGW("Warning: Reusing an immutable bitmap as an image decoder target.");
}
- recycledBytes = GraphicsJNI::getBitmapAllocationByteCount(env, javaBitmap);
+ recycledBytes = bitmap::getBitmapAllocationByteCount(env, javaBitmap);
}
// Set up the pixel allocator
SkBRDAllocator* allocator = nullptr;
RecyclingClippingPixelAllocator recycleAlloc(recycledBitmap, recycledBytes);
- JavaPixelAllocator javaAlloc(env);
+ HeapAllocator heapAlloc;
if (javaBitmap) {
allocator = &recycleAlloc;
// We are required to match the color type of the recycled bitmap.
colorType = recycledBitmap->info().colorType();
} else {
- allocator = &javaAlloc;
+ allocator = &heapAlloc;
}
// Decode the region.
@@ -198,9 +198,9 @@
int bitmapCreateFlags = 0;
if (!requireUnpremul) {
- bitmapCreateFlags |= GraphicsJNI::kBitmapCreateFlag_Premultiplied;
+ bitmapCreateFlags |= android::bitmap::kBitmapCreateFlag_Premultiplied;
}
- return GraphicsJNI::createBitmap(env, javaAlloc.getStorageObjAndReset(), bitmapCreateFlags);
+ return android::bitmap::createBitmap(env, heapAlloc.getStorageObjAndReset(), bitmapCreateFlags);
}
static jint nativeGetHeight(JNIEnv* env, jobject, jlong brdHandle) {
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index c6a51e8..82b70fc 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -157,12 +157,6 @@
static jfieldID gPointF_xFieldID;
static jfieldID gPointF_yFieldID;
-static jclass gBitmap_class;
-static jfieldID gBitmap_nativePtr;
-static jmethodID gBitmap_constructorMethodID;
-static jmethodID gBitmap_reinitMethodID;
-static jmethodID gBitmap_getAllocationByteCountMethodID;
-
static jclass gBitmapConfig_class;
static jfieldID gBitmapConfig_nativeInstanceID;
@@ -342,24 +336,15 @@
return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]);
}
-android::Bitmap* GraphicsJNI::getBitmap(JNIEnv* env, jobject bitmap) {
- SkASSERT(env);
- SkASSERT(bitmap);
- SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
- jlong bitmapHandle = env->GetLongField(bitmap, gBitmap_nativePtr);
- android::Bitmap* b = reinterpret_cast<android::Bitmap*>(bitmapHandle);
- SkASSERT(b);
- return b;
-}
-
void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) {
- getBitmap(env, bitmap)->getSkBitmap(outBitmap);
+ android::bitmap::toPixelRef(env, bitmap)->getSkBitmap(outBitmap);
}
SkPixelRef* GraphicsJNI::refSkPixelRef(JNIEnv* env, jobject bitmap) {
- return getBitmap(env, bitmap)->refPixelRef();
+ SkPixelRef* pixelRef = android::bitmap::toPixelRef(env, bitmap);
+ pixelRef->ref();
+ return pixelRef;
}
-
SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) {
SkASSERT(env);
if (NULL == jconfig) {
@@ -394,51 +379,6 @@
///////////////////////////////////////////////////////////////////////////////////////////
-// Assert that bitmap's SkAlphaType is consistent with isPremultiplied.
-static void assert_premultiplied(const SkImageInfo& info, bool isPremultiplied) {
- // kOpaque_SkAlphaType and kIgnore_SkAlphaType mean that isPremultiplied is
- // irrelevant. This just tests to ensure that the SkAlphaType is not
- // opposite of isPremultiplied.
- if (isPremultiplied) {
- SkASSERT(info.alphaType() != kUnpremul_SkAlphaType);
- } else {
- SkASSERT(info.alphaType() != kPremul_SkAlphaType);
- }
-}
-
-jobject GraphicsJNI::createBitmap(JNIEnv* env, android::Bitmap* bitmap,
- int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
- int density) {
- bool isMutable = bitmapCreateFlags & kBitmapCreateFlag_Mutable;
- bool isPremultiplied = bitmapCreateFlags & kBitmapCreateFlag_Premultiplied;
- // The caller needs to have already set the alpha type properly, so the
- // native SkBitmap stays in sync with the Java Bitmap.
- assert_premultiplied(bitmap->info(), isPremultiplied);
-
- jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
- reinterpret_cast<jlong>(bitmap), bitmap->javaByteArray(),
- bitmap->width(), bitmap->height(), density, isMutable, isPremultiplied,
- ninePatchChunk, ninePatchInsets);
- hasException(env); // For the side effect of logging.
- return obj;
-}
-
-void GraphicsJNI::reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
- bool isPremultiplied)
-{
- // The caller needs to have already set the alpha type properly, so the
- // native SkBitmap stays in sync with the Java Bitmap.
- assert_premultiplied(info, isPremultiplied);
-
- env->CallVoidMethod(javaBitmap, gBitmap_reinitMethodID,
- info.width(), info.height(), isPremultiplied);
-}
-
-int GraphicsJNI::getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
-{
- return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
-}
-
jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
{
SkASSERT(bitmap != NULL);
@@ -483,37 +423,28 @@
return true;
}
-android::Bitmap* GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
- SkColorTable* ctable) {
+android::PixelRef* GraphicsJNI::allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
const SkImageInfo& info = bitmap->info();
if (info.colorType() == kUnknown_SkColorType) {
- doThrowIAE(env, "unknown bitmap configuration");
- return NULL;
+ LOG_ALWAYS_FATAL("unknown bitmap configuration");
+ return nullptr;
}
size_t size;
if (!computeAllocationSize(*bitmap, &size)) {
- return NULL;
+ return nullptr;
}
// we must respect the rowBytes value already set on the bitmap instead of
// attempting to compute our own.
const size_t rowBytes = bitmap->rowBytes();
- jbyteArray arrayObj = (jbyteArray) env->CallObjectMethod(gVMRuntime,
- gVMRuntime_newNonMovableArray,
- gByte_class, size);
- if (env->ExceptionCheck() != 0) {
- return NULL;
+ void* addr = calloc(size, 1);
+ if (!addr) {
+ return nullptr;
}
- SkASSERT(arrayObj);
- jbyte* addr = (jbyte*) env->CallLongMethod(gVMRuntime, gVMRuntime_addressOf, arrayObj);
- if (env->ExceptionCheck() != 0) {
- return NULL;
- }
- SkASSERT(addr);
- android::Bitmap* wrapper = new android::Bitmap(env, arrayObj, (void*) addr,
- info, rowBytes, ctable);
+
+ auto wrapper = new android::PixelRef(addr, size, info, rowBytes, ctable);
wrapper->getSkBitmap(bitmap);
// since we're already allocated, we lockPixels right away
// HeapAllocator behaves this way too
@@ -576,7 +507,7 @@
return true;
}
-android::Bitmap* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+android::PixelRef* GraphicsJNI::allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
SkColorTable* ctable) {
int fd;
@@ -613,7 +544,7 @@
return nullptr;
}
- android::Bitmap* wrapper = new android::Bitmap(addr, fd, size, info, rowBytes, ctable);
+ auto wrapper = new android::PixelRef(addr, fd, size, info, rowBytes, ctable);
wrapper->getSkBitmap(bitmap);
// since we're already allocated, we lockPixels right away
// HeapAllocator behaves this way too
@@ -622,7 +553,7 @@
return wrapper;
}
-android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+android::PixelRef* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly) {
const SkImageInfo& info = bitmap->info();
if (info.colorType() == kUnknown_SkColorType) {
@@ -644,7 +575,7 @@
// attempting to compute our own.
const size_t rowBytes = bitmap->rowBytes();
- android::Bitmap* wrapper = new android::Bitmap(addr, fd, size, info, rowBytes, ctable);
+ auto wrapper = new android::PixelRef(addr, fd, size, info, rowBytes, ctable);
wrapper->getSkBitmap(bitmap);
if (readOnly) {
bitmap->pixelRef()->setImmutable();
@@ -656,30 +587,24 @@
return wrapper;
}
+sk_sp<SkColorSpace> GraphicsJNI::defaultColorSpace() {
+#ifdef ANDROID_ENABLE_LINEAR_BLENDING
+ return SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+#else
+ return nullptr;
+#endif
+}
+
///////////////////////////////////////////////////////////////////////////////
-
-JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env) {
- LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mJavaVM) != JNI_OK,
- "env->GetJavaVM failed");
-}
-
-JavaPixelAllocator::~JavaPixelAllocator() {
- if (mStorage) {
- mStorage->detachFromJava();
- }
-}
-
-bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
- JNIEnv* env = vm2env(mJavaVM);
-
- mStorage = GraphicsJNI::allocateJavaPixelRef(env, bitmap, ctable);
- return mStorage != nullptr;
+bool HeapAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
+ mStorage.reset(GraphicsJNI::allocateHeapPixelRef(bitmap, ctable));
+ return !!mStorage;
}
////////////////////////////////////////////////////////////////////////////////
RecyclingClippingPixelAllocator::RecyclingClippingPixelAllocator(
- android::Bitmap* recycledBitmap, size_t recycledBytes)
+ android::PixelRef* recycledBitmap, size_t recycledBytes)
: mRecycledBitmap(recycledBitmap)
, mRecycledBytes(recycledBytes)
, mSkiaBitmap(nullptr)
@@ -722,7 +647,8 @@
// skbug.com/4538: We also need to make sure that the rowBytes on the pixel ref
// match the rowBytes on the bitmap.
bitmap->setInfo(bitmap->info(), rowBytes);
- bitmap->setPixelRef(mRecycledBitmap->refPixelRef())->unref();
+ mRecycledBitmap->ref();
+ bitmap->setPixelRef(mRecycledBitmap)->unref();
// Make sure that the recycled bitmap has the correct alpha type.
mRecycledBitmap->setAlphaType(bitmap->alphaType());
@@ -749,7 +675,8 @@
void RecyclingClippingPixelAllocator::copyIfNecessary() {
if (mNeedsCopy) {
- SkPixelRef* recycledPixels = mRecycledBitmap->refPixelRef();
+ mRecycledBitmap->ref();
+ SkPixelRef* recycledPixels = mRecycledBitmap;
void* dst = recycledPixels->pixels();
const size_t dstRowBytes = mRecycledBitmap->rowBytes();
const size_t bytesToCopy = std::min(mRecycledBitmap->info().minRowBytes(),
@@ -774,16 +701,10 @@
"env->GetJavaVM failed");
}
-AshmemPixelAllocator::~AshmemPixelAllocator() {
- if (mStorage) {
- mStorage->detachFromJava();
- }
-}
-
bool AshmemPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
JNIEnv* env = vm2env(mJavaVM);
- mStorage = GraphicsJNI::allocateAshmemPixelRef(env, bitmap, ctable);
- return mStorage != nullptr;
+ mStorage.reset(GraphicsJNI::allocateAshmemPixelRef(env, bitmap, ctable));
+ return !!mStorage;
}
////////////////////////////////////////////////////////////////////////////////
@@ -828,11 +749,6 @@
gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F");
gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F");
- gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
- gBitmap_nativePtr = getFieldIDCheck(env, gBitmap_class, "mNativePtr", "J");
- gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>", "(J[BIIIZZ[BLandroid/graphics/NinePatch$InsetStruct;)V");
- gBitmap_reinitMethodID = env->GetMethodID(gBitmap_class, "reinit", "(IIZ)V");
- gBitmap_getAllocationByteCountMethodID = env->GetMethodID(gBitmap_class, "getAllocationByteCount", "()I");
gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(J)V");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 89636db..e5af525 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -10,8 +10,10 @@
#include "SkMallocPixelRef.h"
#include "SkPoint.h"
#include "SkRect.h"
+#include "SkColorSpace.h"
#include <jni.h>
#include <hwui/Canvas.h>
+#include <hwui/PixelRef.h>
class SkBitmapRegionDecoder;
class SkCanvas;
@@ -23,12 +25,6 @@
class GraphicsJNI {
public:
- enum BitmapCreateFlags {
- kBitmapCreateFlag_None = 0x0,
- kBitmapCreateFlag_Mutable = 0x1,
- kBitmapCreateFlag_Premultiplied = 0x2,
- };
-
// returns true if an exception is set (and dumps it out to the Log)
static bool hasException(JNIEnv*);
@@ -51,7 +47,6 @@
static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf);
static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas);
- static android::Bitmap* getBitmap(JNIEnv*, jobject bitmap);
static void getSkBitmap(JNIEnv*, jobject bitmap, SkBitmap* outBitmap);
static SkPixelRef* refSkPixelRef(JNIEnv*, jobject bitmap);
static SkRegion* getNativeRegion(JNIEnv*, jobject region);
@@ -73,33 +68,16 @@
*/
static SkColorType getNativeBitmapColorType(JNIEnv*, jobject jconfig);
- /*
- * Create a java Bitmap object given the native bitmap
- * bitmap's SkAlphaType must already be in sync with bitmapCreateFlags.
- */
- static jobject createBitmap(JNIEnv* env, android::Bitmap* bitmap,
- int bitmapCreateFlags, jbyteArray ninePatchChunk = NULL,
- jobject ninePatchInsets = NULL, int density = -1);
-
- /** Reinitialize a bitmap. bitmap must already have its SkAlphaType set in
- sync with isPremultiplied
- */
- static void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
- bool isPremultiplied);
-
- static int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap);
-
static jobject createRegion(JNIEnv* env, SkRegion* region);
static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap);
- static android::Bitmap* allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
+ static android::PixelRef* allocateHeapPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
+
+ static android::PixelRef* allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
SkColorTable* ctable);
- static android::Bitmap* allocateAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
- SkColorTable* ctable);
-
- static android::Bitmap* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
+ static android::PixelRef* mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
SkColorTable* ctable, int fd, void* addr, size_t size, bool readOnly);
/**
@@ -117,38 +95,27 @@
static bool SetPixels(JNIEnv* env, jintArray colors, int srcOffset,
int srcStride, int x, int y, int width, int height,
const SkBitmap& dstBitmap);
+
+ static sk_sp<SkColorSpace> defaultColorSpace();
};
-/** Allocator which allocates the backing buffer in the Java heap.
- * Instances can only be used to perform a single allocation, which helps
- * ensure that the allocated buffer is properly accounted for with a
- * reference in the heap (or a JNI global reference).
- */
-class JavaPixelAllocator : public SkBRDAllocator {
+class HeapAllocator : public SkBRDAllocator {
public:
- explicit JavaPixelAllocator(JNIEnv* env);
- ~JavaPixelAllocator();
+ HeapAllocator() { };
+ ~HeapAllocator() { };
virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) override;
/**
* Fetches the backing allocation object. Must be called!
*/
- android::Bitmap* getStorageObjAndReset() {
- android::Bitmap* result = mStorage;
- mStorage = NULL;
- return result;
+ android::PixelRef* getStorageObjAndReset() {
+ return mStorage.release();
};
- /**
- * Indicates that this allocator allocates zero initialized
- * memory.
- */
SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kYes_ZeroInitialized; }
-
private:
- JavaVM* mJavaVM;
- android::Bitmap* mStorage = nullptr;
+ sk_sp<android::PixelRef> mStorage;
};
/**
@@ -181,7 +148,7 @@
class RecyclingClippingPixelAllocator : public SkBRDAllocator {
public:
- RecyclingClippingPixelAllocator(android::Bitmap* recycledBitmap,
+ RecyclingClippingPixelAllocator(android::PixelRef* recycledBitmap,
size_t recycledBytes);
~RecyclingClippingPixelAllocator();
@@ -206,7 +173,7 @@
SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kNo_ZeroInitialized; }
private:
- android::Bitmap* mRecycledBitmap;
+ android::PixelRef* mRecycledBitmap;
const size_t mRecycledBytes;
SkBitmap* mSkiaBitmap;
bool mNeedsCopy;
@@ -215,17 +182,15 @@
class AshmemPixelAllocator : public SkBitmap::Allocator {
public:
explicit AshmemPixelAllocator(JNIEnv* env);
- ~AshmemPixelAllocator();
+ ~AshmemPixelAllocator() { };
virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable);
- android::Bitmap* getStorageObjAndReset() {
- android::Bitmap* result = mStorage;
- mStorage = NULL;
- return result;
+ android::PixelRef* getStorageObjAndReset() {
+ return mStorage.release();
};
private:
JavaVM* mJavaVM;
- android::Bitmap* mStorage = nullptr;
+ sk_sp<android::PixelRef> mStorage;
};
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index b0f3bb4..f8bb77a 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2006, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** 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
+** 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
+** 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.
*/
@@ -25,14 +25,25 @@
namespace android {
+static_assert(sizeof(SkMatrix) == 40, "Unexpected sizeof(SkMatrix), "
+ "update size in Matrix.java#NATIVE_ALLOCATION_SIZE and here");
+static_assert(SK_SCALAR_IS_FLOAT, "SK_SCALAR_IS_FLOAT is false, "
+ "only float scalar is supported");
+
class SkMatrixGlue {
public:
- static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
+ // ---------------- Regular JNI -----------------------------
+
+ static void finalizer(jlong objHandle) {
SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
delete obj;
}
+ static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
+ return static_cast<jlong>(reinterpret_cast<uintptr_t>(&finalizer));
+ }
+
static jlong create(JNIEnv* env, jobject clazz, jlong srcHandle) {
const SkMatrix* src = reinterpret_cast<SkMatrix*>(srcHandle);
SkMatrix* obj = new SkMatrix();
@@ -43,156 +54,39 @@
return reinterpret_cast<jlong>(obj);
}
- static jboolean isIdentity(JNIEnv* env, jobject clazz, jlong objHandle) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- return obj->isIdentity() ? JNI_TRUE : JNI_FALSE;
- }
+ // ---------------- @FastNative -----------------------------
- static jboolean isAffine(JNIEnv* env, jobject clazz, jlong objHandle) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- return obj->asAffine(NULL) ? JNI_TRUE : JNI_FALSE;
- }
-
- static jboolean rectStaysRect(JNIEnv* env, jobject clazz, jlong objHandle) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- return obj->rectStaysRect() ? JNI_TRUE : JNI_FALSE;
- }
-
- static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->reset();
- }
- static void set(JNIEnv* env, jobject clazz, jlong objHandle, jlong otherHandle) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
- *obj = *other;
- }
- static void setTranslate(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->setTranslate(dx, dy);
- }
- static void setScale__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy, jfloat px, jfloat py) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->setScale(sx, sy, px, py);
- }
- static void setScale__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->setScale(sx, sy);
- }
- static void setRotate__FFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees, jfloat px, jfloat py) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->setRotate(degrees, px, py);
- }
- static void setRotate__F(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->setRotate(degrees);
- }
- static void setSinCos__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sinValue, jfloat cosValue, jfloat px, jfloat py) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->setSinCos(sinValue, cosValue, px, py);
- }
- static void setSinCos__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sinValue, jfloat cosValue) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->setSinCos(sinValue, cosValue);
- }
- static void setSkew__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat kx, jfloat ky, jfloat px, jfloat py) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->setSkew(kx, ky, px, py);
- }
- static void setSkew__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat kx, jfloat ky) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->setSkew(kx, ky);
- }
- static void setConcat(JNIEnv* env, jobject clazz, jlong objHandle, jlong aHandle, jlong bHandle) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- SkMatrix* a = reinterpret_cast<SkMatrix*>(aHandle);
- SkMatrix* b = reinterpret_cast<SkMatrix*>(bHandle);
- obj->setConcat(*a, *b);
- }
-
- static void preTranslate(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->preTranslate(dx, dy);
- }
-
- static void preScale__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy, jfloat px, jfloat py) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->preScale(sx, sy, px, py);
- }
-
- static void preScale__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->preScale(sx, sy);
- }
-
- static void preRotate__FFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees, jfloat px, jfloat py) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->preRotate(degrees, px, py);
- }
-
- static void preRotate__F(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->preRotate(degrees);
- }
-
- static void preSkew__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat kx, jfloat ky, jfloat px, jfloat py) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->preSkew(kx, ky, px, py);
- }
-
- static void preSkew__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat kx, jfloat ky) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->preSkew(kx, ky);
- }
-
- static void preConcat(JNIEnv* env, jobject clazz, jlong objHandle, jlong otherHandle) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
- obj->preConcat(*other);
- }
-
- static void postTranslate(JNIEnv* env, jobject clazz, jlong objHandle, jfloat dx, jfloat dy) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->postTranslate(dx, dy);
- }
-
- static void postScale__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy, jfloat px, jfloat py) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->postScale(sx, sy, px, py);
- }
-
- static void postScale__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->postScale(sx, sy);
- }
-
- static void postRotate__FFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees, jfloat px, jfloat py) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->postRotate(degrees, px, py);
- }
-
- static void postRotate__F(JNIEnv* env, jobject clazz, jlong objHandle, jfloat degrees) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->postRotate(degrees);
- }
-
- static void postSkew__FFFF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat kx, jfloat ky, jfloat px, jfloat py) {
- SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
- obj->postSkew(kx, ky, px, py);
- }
-
- static void postSkew__FF(JNIEnv* env, jobject clazz, jlong matrixHandle, jfloat kx, jfloat ky) {
+ static void mapPoints(JNIEnv* env, jobject clazz, jlong matrixHandle,
+ jfloatArray dst, jint dstIndex, jfloatArray src, jint srcIndex,
+ jint ptCount, jboolean isPts) {
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
- matrix->postSkew(kx, ky);
+ SkASSERT(ptCount >= 0);
+ AutoJavaFloatArray autoSrc(env, src, srcIndex + (ptCount << 1),
+ kRO_JNIAccess);
+ AutoJavaFloatArray autoDst(env, dst, dstIndex + (ptCount << 1),
+ kRW_JNIAccess);
+ float* srcArray = autoSrc.ptr() + srcIndex;
+ float* dstArray = autoDst.ptr() + dstIndex;
+ if (isPts)
+ matrix->mapPoints((SkPoint*) dstArray, (const SkPoint*) srcArray,
+ ptCount);
+ else
+ matrix->mapVectors((SkVector*) dstArray, (const SkVector*) srcArray,
+ ptCount);
}
- static void postConcat(JNIEnv* env, jobject clazz, jlong matrixHandle, jlong otherHandle) {
+ static jboolean mapRect__RectFRectF(JNIEnv* env, jobject clazz,
+ jlong matrixHandle, jobjectArray dst, jobject src) {
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
- SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
- matrix->postConcat(*other);
+ SkRect dst_, src_;
+ GraphicsJNI::jrectf_to_rect(env, src, &src_);
+ jboolean rectStaysRect = matrix->mapRect(&dst_, src_);
+ GraphicsJNI::rect_to_jrectf(dst_, env, dst);
+ return rectStaysRect ? JNI_TRUE : JNI_FALSE;
}
- static jboolean setRectToRect(JNIEnv* env, jobject clazz, jlong matrixHandle, jobject src, jobject dst, jint stfHandle) {
+ static jboolean setRectToRect(JNIEnv* env, jobject clazz,
+ jlong matrixHandle, jobject src, jobject dst, jint stfHandle) {
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
SkMatrix::ScaleToFit stf = static_cast<SkMatrix::ScaleToFit>(stfHandle);
SkRect src_;
@@ -202,150 +96,290 @@
return matrix->setRectToRect(src_, dst_, stf) ? JNI_TRUE : JNI_FALSE;
}
- static jboolean setPolyToPoly(JNIEnv* env, jobject clazz, jlong matrixHandle,
- jfloatArray jsrc, jint srcIndex,
- jfloatArray jdst, jint dstIndex, jint ptCount) {
+ static jboolean setPolyToPoly(JNIEnv* env, jobject clazz,
+ jlong matrixHandle, jfloatArray jsrc, jint srcIndex,
+ jfloatArray jdst, jint dstIndex, jint ptCount) {
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
SkASSERT(srcIndex >= 0);
SkASSERT(dstIndex >= 0);
- SkASSERT((unsigned)ptCount <= 4);
+ SkASSERT((unsigned )ptCount <= 4);
- AutoJavaFloatArray autoSrc(env, jsrc, srcIndex + (ptCount << 1), kRO_JNIAccess);
- AutoJavaFloatArray autoDst(env, jdst, dstIndex + (ptCount << 1), kRW_JNIAccess);
+ AutoJavaFloatArray autoSrc(env, jsrc, srcIndex + (ptCount << 1),
+ kRO_JNIAccess);
+ AutoJavaFloatArray autoDst(env, jdst, dstIndex + (ptCount << 1),
+ kRW_JNIAccess);
float* src = autoSrc.ptr() + srcIndex;
float* dst = autoDst.ptr() + dstIndex;
bool result;
-#ifdef SK_SCALAR_IS_FLOAT
- result = matrix->setPolyToPoly((const SkPoint*)src, (const SkPoint*)dst,
- ptCount);
-#else
- SkASSERT(false);
-#endif
+ result = matrix->setPolyToPoly((const SkPoint*) src,
+ (const SkPoint*) dst, ptCount);
return result ? JNI_TRUE : JNI_FALSE;
}
- static jboolean invert(JNIEnv* env, jobject clazz, jlong matrixHandle, jlong inverseHandle) {
+ static void getValues(JNIEnv* env, jobject clazz, jlong matrixHandle,
+ jfloatArray values) {
+ SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
+ AutoJavaFloatArray autoValues(env, values, 9, kRW_JNIAccess);
+ float* dst = autoValues.ptr();
+ for (int i = 0; i < 9; i++) {
+ dst[i] = matrix->get(i);
+ }
+ }
+
+ static void setValues(JNIEnv* env, jobject clazz, jlong matrixHandle,
+ jfloatArray values) {
+ SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
+ AutoJavaFloatArray autoValues(env, values, 9, kRO_JNIAccess);
+ const float* src = autoValues.ptr();
+
+ for (int i = 0; i < 9; i++) {
+ matrix->set(i, src[i]);
+ }
+ }
+
+ // ---------------- @CriticalNative -----------------------------
+
+ static jboolean isIdentity(jlong objHandle) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ return obj->isIdentity() ? JNI_TRUE : JNI_FALSE;
+ }
+
+ static jboolean isAffine(jlong objHandle) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ return obj->asAffine(NULL) ? JNI_TRUE : JNI_FALSE;
+ }
+
+ static jboolean rectStaysRect(jlong objHandle) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ return obj->rectStaysRect() ? JNI_TRUE : JNI_FALSE;
+ }
+
+ static void reset(jlong objHandle) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->reset();
+ }
+
+ static void set(jlong objHandle, jlong otherHandle) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
+ *obj = *other;
+ }
+
+ static void setTranslate(jlong objHandle, jfloat dx, jfloat dy) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->setTranslate(dx, dy);
+ }
+
+ static void setScale__FFFF(jlong objHandle, jfloat sx, jfloat sy, jfloat px,
+ jfloat py) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->setScale(sx, sy, px, py);
+ }
+
+ static void setScale__FF(jlong objHandle, jfloat sx, jfloat sy) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->setScale(sx, sy);
+ }
+
+ static void setRotate__FFF(jlong objHandle, jfloat degrees, jfloat px,
+ jfloat py) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->setRotate(degrees, px, py);
+ }
+
+ static void setRotate__F(jlong objHandle, jfloat degrees) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->setRotate(degrees);
+ }
+
+ static void setSinCos__FFFF(jlong objHandle, jfloat sinValue,
+ jfloat cosValue, jfloat px, jfloat py) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->setSinCos(sinValue, cosValue, px, py);
+ }
+
+ static void setSinCos__FF(jlong objHandle, jfloat sinValue,
+ jfloat cosValue) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->setSinCos(sinValue, cosValue);
+ }
+
+ static void setSkew__FFFF(jlong objHandle, jfloat kx, jfloat ky, jfloat px,
+ jfloat py) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->setSkew(kx, ky, px, py);
+ }
+
+ static void setSkew__FF(jlong objHandle, jfloat kx, jfloat ky) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->setSkew(kx, ky);
+ }
+
+ static void setConcat(jlong objHandle, jlong aHandle, jlong bHandle) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ SkMatrix* a = reinterpret_cast<SkMatrix*>(aHandle);
+ SkMatrix* b = reinterpret_cast<SkMatrix*>(bHandle);
+ obj->setConcat(*a, *b);
+ }
+
+ static void preTranslate(jlong objHandle, jfloat dx, jfloat dy) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->preTranslate(dx, dy);
+ }
+
+ static void preScale__FFFF(jlong objHandle, jfloat sx, jfloat sy, jfloat px,
+ jfloat py) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->preScale(sx, sy, px, py);
+ }
+
+ static void preScale__FF(jlong objHandle, jfloat sx, jfloat sy) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->preScale(sx, sy);
+ }
+
+ static void preRotate__FFF(jlong objHandle, jfloat degrees, jfloat px,
+ jfloat py) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->preRotate(degrees, px, py);
+ }
+
+ static void preRotate__F(jlong objHandle, jfloat degrees) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->preRotate(degrees);
+ }
+
+ static void preSkew__FFFF(jlong objHandle, jfloat kx, jfloat ky, jfloat px,
+ jfloat py) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->preSkew(kx, ky, px, py);
+ }
+
+ static void preSkew__FF(jlong objHandle, jfloat kx, jfloat ky) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->preSkew(kx, ky);
+ }
+
+ static void preConcat(jlong objHandle, jlong otherHandle) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
+ obj->preConcat(*other);
+ }
+
+ static void postTranslate(jlong objHandle, jfloat dx, jfloat dy) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->postTranslate(dx, dy);
+ }
+
+ static void postScale__FFFF(jlong objHandle, jfloat sx, jfloat sy,
+ jfloat px, jfloat py) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->postScale(sx, sy, px, py);
+ }
+
+ static void postScale__FF(jlong objHandle, jfloat sx, jfloat sy) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->postScale(sx, sy);
+ }
+
+ static void postRotate__FFF(jlong objHandle, jfloat degrees, jfloat px,
+ jfloat py) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->postRotate(degrees, px, py);
+ }
+
+ static void postRotate__F(jlong objHandle, jfloat degrees) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->postRotate(degrees);
+ }
+
+ static void postSkew__FFFF(jlong objHandle, jfloat kx, jfloat ky, jfloat px,
+ jfloat py) {
+ SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
+ obj->postSkew(kx, ky, px, py);
+ }
+
+ static void postSkew__FF(jlong matrixHandle, jfloat kx, jfloat ky) {
+ SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
+ matrix->postSkew(kx, ky);
+ }
+
+ static void postConcat(jlong matrixHandle, jlong otherHandle) {
+ SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
+ SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
+ matrix->postConcat(*other);
+ }
+
+ static jboolean invert(jlong matrixHandle, jlong inverseHandle) {
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
SkMatrix* inverse = reinterpret_cast<SkMatrix*>(inverseHandle);
return matrix->invert(inverse);
}
- static void mapPoints(JNIEnv* env, jobject clazz, jlong matrixHandle,
- jfloatArray dst, jint dstIndex,
- jfloatArray src, jint srcIndex,
- jint ptCount, jboolean isPts) {
- SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
- SkASSERT(ptCount >= 0);
- AutoJavaFloatArray autoSrc(env, src, srcIndex + (ptCount << 1), kRO_JNIAccess);
- AutoJavaFloatArray autoDst(env, dst, dstIndex + (ptCount << 1), kRW_JNIAccess);
- float* srcArray = autoSrc.ptr() + srcIndex;
- float* dstArray = autoDst.ptr() + dstIndex;
-#ifdef SK_SCALAR_IS_FLOAT
- if (isPts)
- matrix->mapPoints((SkPoint*)dstArray, (const SkPoint*)srcArray,
- ptCount);
- else
- matrix->mapVectors((SkVector*)dstArray, (const SkVector*)srcArray,
- ptCount);
-#else
- SkASSERT(false);
-#endif
- }
-
- static jboolean mapRect__RectFRectF(JNIEnv* env, jobject clazz, jlong matrixHandle, jobjectArray dst, jobject src) {
- SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
- SkRect dst_, src_;
- GraphicsJNI::jrectf_to_rect(env, src, &src_);
- jboolean rectStaysRect = matrix->mapRect(&dst_, src_);
- GraphicsJNI::rect_to_jrectf(dst_, env, dst);
- return rectStaysRect ? JNI_TRUE : JNI_FALSE;
- }
-
- static jfloat mapRadius(JNIEnv* env, jobject clazz, jlong matrixHandle, jfloat radius) {
+ static jfloat mapRadius(jlong matrixHandle, jfloat radius) {
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
float result;
result = SkScalarToFloat(matrix->mapRadius(radius));
return static_cast<jfloat>(result);
}
- static void getValues(JNIEnv* env, jobject clazz, jlong matrixHandle, jfloatArray values) {
- SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
- AutoJavaFloatArray autoValues(env, values, 9, kRW_JNIAccess);
- float* dst = autoValues.ptr();
-#ifdef SK_SCALAR_IS_FLOAT
- for (int i = 0; i < 9; i++) {
- dst[i] = matrix->get(i);
- }
-#else
- SkASSERT(false);
-#endif
- }
- static void setValues(JNIEnv* env, jobject clazz, jlong matrixHandle, jfloatArray values) {
- SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
- AutoJavaFloatArray autoValues(env, values, 9, kRO_JNIAccess);
- const float* src = autoValues.ptr();
-
-#ifdef SK_SCALAR_IS_FLOAT
- for (int i = 0; i < 9; i++) {
- matrix->set(i, src[i]);
- }
-#else
- SkASSERT(false);
-#endif
- }
-
- static jboolean equals(JNIEnv* env, jobject clazz, jlong aHandle, jlong bHandle) {
+ static jboolean equals(jlong aHandle, jlong bHandle) {
const SkMatrix* a = reinterpret_cast<SkMatrix*>(aHandle);
const SkMatrix* b = reinterpret_cast<SkMatrix*>(bHandle);
return *a == *b;
}
- };
+};
static const JNINativeMethod methods[] = {
- {"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer},
- {"native_create","(J)J", (void*) SkMatrixGlue::create},
+ {"nGetNativeFinalizer", "()J", (void*) SkMatrixGlue::getNativeFinalizer},
+ {"nCreate","(J)J", (void*) SkMatrixGlue::create},
- {"native_isIdentity","!(J)Z", (void*) SkMatrixGlue::isIdentity},
- {"native_isAffine","!(J)Z", (void*) SkMatrixGlue::isAffine},
- {"native_rectStaysRect","!(J)Z", (void*) SkMatrixGlue::rectStaysRect},
- {"native_reset","!(J)V", (void*) SkMatrixGlue::reset},
- {"native_set","!(JJ)V", (void*) SkMatrixGlue::set},
- {"native_setTranslate","!(JFF)V", (void*) SkMatrixGlue::setTranslate},
- {"native_setScale","!(JFFFF)V", (void*) SkMatrixGlue::setScale__FFFF},
- {"native_setScale","!(JFF)V", (void*) SkMatrixGlue::setScale__FF},
- {"native_setRotate","!(JFFF)V", (void*) SkMatrixGlue::setRotate__FFF},
- {"native_setRotate","!(JF)V", (void*) SkMatrixGlue::setRotate__F},
- {"native_setSinCos","!(JFFFF)V", (void*) SkMatrixGlue::setSinCos__FFFF},
- {"native_setSinCos","!(JFF)V", (void*) SkMatrixGlue::setSinCos__FF},
- {"native_setSkew","!(JFFFF)V", (void*) SkMatrixGlue::setSkew__FFFF},
- {"native_setSkew","!(JFF)V", (void*) SkMatrixGlue::setSkew__FF},
- {"native_setConcat","!(JJJ)V", (void*) SkMatrixGlue::setConcat},
- {"native_preTranslate","!(JFF)V", (void*) SkMatrixGlue::preTranslate},
- {"native_preScale","!(JFFFF)V", (void*) SkMatrixGlue::preScale__FFFF},
- {"native_preScale","!(JFF)V", (void*) SkMatrixGlue::preScale__FF},
- {"native_preRotate","!(JFFF)V", (void*) SkMatrixGlue::preRotate__FFF},
- {"native_preRotate","!(JF)V", (void*) SkMatrixGlue::preRotate__F},
- {"native_preSkew","!(JFFFF)V", (void*) SkMatrixGlue::preSkew__FFFF},
- {"native_preSkew","!(JFF)V", (void*) SkMatrixGlue::preSkew__FF},
- {"native_preConcat","!(JJ)V", (void*) SkMatrixGlue::preConcat},
- {"native_postTranslate","!(JFF)V", (void*) SkMatrixGlue::postTranslate},
- {"native_postScale","!(JFFFF)V", (void*) SkMatrixGlue::postScale__FFFF},
- {"native_postScale","!(JFF)V", (void*) SkMatrixGlue::postScale__FF},
- {"native_postRotate","!(JFFF)V", (void*) SkMatrixGlue::postRotate__FFF},
- {"native_postRotate","!(JF)V", (void*) SkMatrixGlue::postRotate__F},
- {"native_postSkew","!(JFFFF)V", (void*) SkMatrixGlue::postSkew__FFFF},
- {"native_postSkew","!(JFF)V", (void*) SkMatrixGlue::postSkew__FF},
- {"native_postConcat","!(JJ)V", (void*) SkMatrixGlue::postConcat},
- {"native_setRectToRect","!(JLandroid/graphics/RectF;Landroid/graphics/RectF;I)Z", (void*) SkMatrixGlue::setRectToRect},
- {"native_setPolyToPoly","!(J[FI[FII)Z", (void*) SkMatrixGlue::setPolyToPoly},
- {"native_invert","!(JJ)Z", (void*) SkMatrixGlue::invert},
- {"native_mapPoints","!(J[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints},
- {"native_mapRect","!(JLandroid/graphics/RectF;Landroid/graphics/RectF;)Z", (void*) SkMatrixGlue::mapRect__RectFRectF},
- {"native_mapRadius","!(JF)F", (void*) SkMatrixGlue::mapRadius},
- {"native_getValues","!(J[F)V", (void*) SkMatrixGlue::getValues},
- {"native_setValues","!(J[F)V", (void*) SkMatrixGlue::setValues},
- {"native_equals", "!(JJ)Z", (void*) SkMatrixGlue::equals}
+ // ------- @FastNative below here ---------------
+ {"nMapPoints","(J[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints},
+ {"nMapRect","(JLandroid/graphics/RectF;Landroid/graphics/RectF;)Z",
+ (void*) SkMatrixGlue::mapRect__RectFRectF},
+ {"nSetRectToRect","(JLandroid/graphics/RectF;Landroid/graphics/RectF;I)Z",
+ (void*) SkMatrixGlue::setRectToRect},
+ {"nSetPolyToPoly","(J[FI[FII)Z", (void*) SkMatrixGlue::setPolyToPoly},
+ {"nGetValues","(J[F)V", (void*) SkMatrixGlue::getValues},
+ {"nSetValues","(J[F)V", (void*) SkMatrixGlue::setValues},
+
+ // ------- @CriticalNative below here ---------------
+ {"nIsIdentity","(J)Z", (void*) SkMatrixGlue::isIdentity},
+ {"nIsAffine","(J)Z", (void*) SkMatrixGlue::isAffine},
+ {"nRectStaysRect","(J)Z", (void*) SkMatrixGlue::rectStaysRect},
+ {"nReset","(J)V", (void*) SkMatrixGlue::reset},
+ {"nSet","(JJ)V", (void*) SkMatrixGlue::set},
+ {"nSetTranslate","(JFF)V", (void*) SkMatrixGlue::setTranslate},
+ {"nSetScale","(JFFFF)V", (void*) SkMatrixGlue::setScale__FFFF},
+ {"nSetScale","(JFF)V", (void*) SkMatrixGlue::setScale__FF},
+ {"nSetRotate","(JFFF)V", (void*) SkMatrixGlue::setRotate__FFF},
+ {"nSetRotate","(JF)V", (void*) SkMatrixGlue::setRotate__F},
+ {"nSetSinCos","(JFFFF)V", (void*) SkMatrixGlue::setSinCos__FFFF},
+ {"nSetSinCos","(JFF)V", (void*) SkMatrixGlue::setSinCos__FF},
+ {"nSetSkew","(JFFFF)V", (void*) SkMatrixGlue::setSkew__FFFF},
+ {"nSetSkew","(JFF)V", (void*) SkMatrixGlue::setSkew__FF},
+ {"nSetConcat","(JJJ)V", (void*) SkMatrixGlue::setConcat},
+ {"nPreTranslate","(JFF)V", (void*) SkMatrixGlue::preTranslate},
+ {"nPreScale","(JFFFF)V", (void*) SkMatrixGlue::preScale__FFFF},
+ {"nPreScale","(JFF)V", (void*) SkMatrixGlue::preScale__FF},
+ {"nPreRotate","(JFFF)V", (void*) SkMatrixGlue::preRotate__FFF},
+ {"nPreRotate","(JF)V", (void*) SkMatrixGlue::preRotate__F},
+ {"nPreSkew","(JFFFF)V", (void*) SkMatrixGlue::preSkew__FFFF},
+ {"nPreSkew","(JFF)V", (void*) SkMatrixGlue::preSkew__FF},
+ {"nPreConcat","(JJ)V", (void*) SkMatrixGlue::preConcat},
+ {"nPostTranslate","(JFF)V", (void*) SkMatrixGlue::postTranslate},
+ {"nPostScale","(JFFFF)V", (void*) SkMatrixGlue::postScale__FFFF},
+ {"nPostScale","(JFF)V", (void*) SkMatrixGlue::postScale__FF},
+ {"nPostRotate","(JFFF)V", (void*) SkMatrixGlue::postRotate__FFF},
+ {"nPostRotate","(JF)V", (void*) SkMatrixGlue::postRotate__F},
+ {"nPostSkew","(JFFFF)V", (void*) SkMatrixGlue::postSkew__FFFF},
+ {"nPostSkew","(JFF)V", (void*) SkMatrixGlue::postSkew__FF},
+ {"nPostConcat","(JJ)V", (void*) SkMatrixGlue::postConcat},
+ {"nInvert","(JJ)Z", (void*) SkMatrixGlue::invert},
+ {"nMapRadius","(JF)F", (void*) SkMatrixGlue::mapRadius},
+ {"nEquals", "(JJ)Z", (void*) SkMatrixGlue::equals}
};
static jfieldID sNativeInstanceField;
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 315dd6b..4b1530a 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -105,392 +105,80 @@
return reinterpret_cast<jlong>(obj);
}
- static void reset(JNIEnv* env, jobject clazz, jlong objHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- obj->reset();
- defaultSettingsForAndroid(obj);
- }
+ static int breakText(JNIEnv* env, const Paint& paint, Typeface* typeface, const jchar text[],
+ int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
+ const bool forwardScan) {
+ size_t measuredCount = 0;
+ float measured = 0;
- static void assign(JNIEnv* env, jobject clazz, jlong dstPaintHandle, jlong srcPaintHandle) {
- Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle);
- const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle);
- *dst = *src;
- }
+ std::unique_ptr<float[]> advancesArray(new float[count]);
+ MinikinUtils::measureText(&paint, bidiFlags, typeface, text, 0, count, count,
+ advancesArray.get());
- // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
- static const uint32_t sFilterBitmapFlag = 0x02;
-
- static jint getFlags(JNIEnv* env, jobject, jlong paintHandle) {
- Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
- uint32_t result = nativePaint->getFlags();
- result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
- if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) {
- result |= sFilterBitmapFlag;
+ for (int i = 0; i < count; i++) {
+ // traverse in the given direction
+ int index = forwardScan ? i : (count - i - 1);
+ float width = advancesArray[index];
+ if (measured + width > maxWidth) {
+ break;
+ }
+ // properly handle clusters when scanning backwards
+ if (forwardScan || width != 0.0f) {
+ measuredCount = i + 1;
+ }
+ measured += width;
}
- return static_cast<jint>(result);
- }
- static void setFlags(JNIEnv* env, jobject, jlong paintHandle, jint flags) {
- Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
- // Instead of modifying 0x02, change the filter level.
- nativePaint->setFilterQuality(flags & sFilterBitmapFlag
- ? kLow_SkFilterQuality
- : kNone_SkFilterQuality);
- // Don't pass through filter flag, which is no longer stored in paint's flags.
- flags &= ~sFilterBitmapFlag;
- // Use the existing value for 0x02.
- const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
- flags |= existing0x02Flag;
- nativePaint->setFlags(flags);
- }
-
- static jint getHinting(JNIEnv* env, jobject, jlong paintHandle) {
- return reinterpret_cast<Paint*>(paintHandle)->getHinting()
- == Paint::kNo_Hinting ? 0 : 1;
- }
-
- static void setHinting(JNIEnv* env, jobject, jlong paintHandle, jint mode) {
- reinterpret_cast<Paint*>(paintHandle)->setHinting(
- mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
- }
-
- static void setAntiAlias(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
- reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa);
- }
-
- static void setLinearText(JNIEnv* env, jobject, jlong paintHandle, jboolean linearText) {
- reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText);
- }
-
- static void setSubpixelText(JNIEnv* env, jobject, jlong paintHandle, jboolean subpixelText) {
- reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText);
- }
-
- static void setUnderlineText(JNIEnv* env, jobject, jlong paintHandle, jboolean underlineText) {
- reinterpret_cast<Paint*>(paintHandle)->setUnderlineText(underlineText);
- }
-
- static void setStrikeThruText(JNIEnv* env, jobject, jlong paintHandle, jboolean strikeThruText) {
- reinterpret_cast<Paint*>(paintHandle)->setStrikeThruText(strikeThruText);
- }
-
- static void setFakeBoldText(JNIEnv* env, jobject, jlong paintHandle, jboolean fakeBoldText) {
- reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText);
- }
-
- static void setFilterBitmap(JNIEnv* env, jobject, jlong paintHandle, jboolean filterBitmap) {
- reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
- filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
- }
-
- static void setDither(JNIEnv* env, jobject, jlong paintHandle, jboolean dither) {
- reinterpret_cast<Paint*>(paintHandle)->setDither(dither);
- }
-
- static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- return static_cast<jint>(obj->getStyle());
- }
-
- static void setStyle(JNIEnv* env, jobject clazz, jlong objHandle, jint styleHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- Paint::Style style = static_cast<Paint::Style>(styleHandle);
- obj->setStyle(style);
- }
-
- static jint getColor(JNIEnv* env, jobject, jlong paintHandle) {
- int color;
- color = reinterpret_cast<Paint*>(paintHandle)->getColor();
- return static_cast<jint>(color);
- }
-
- static jint getAlpha(JNIEnv* env, jobject, jlong paintHandle) {
- int alpha;
- alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
- return static_cast<jint>(alpha);
- }
-
- static void setColor(JNIEnv* env, jobject, jlong paintHandle, jint color) {
- reinterpret_cast<Paint*>(paintHandle)->setColor(color);
- }
-
- static void setAlpha(JNIEnv* env, jobject, jlong paintHandle, jint a) {
- reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
- }
-
- static jfloat getStrokeWidth(JNIEnv* env, jobject, jlong paintHandle) {
- return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth());
- }
-
- static void setStrokeWidth(JNIEnv* env, jobject, jlong paintHandle, jfloat width) {
- reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width);
- }
-
- static jfloat getStrokeMiter(JNIEnv* env, jobject, jlong paintHandle) {
- return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter());
- }
-
- static void setStrokeMiter(JNIEnv* env, jobject, jlong paintHandle, jfloat miter) {
- reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter);
- }
-
- static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- return static_cast<jint>(obj->getStrokeCap());
- }
-
- static void setStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle, jint capHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- Paint::Cap cap = static_cast<Paint::Cap>(capHandle);
- obj->setStrokeCap(cap);
- }
-
- static jint getStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- return static_cast<jint>(obj->getStrokeJoin());
- }
-
- static void setStrokeJoin(JNIEnv* env, jobject clazz, jlong objHandle, jint joinHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- Paint::Join join = (Paint::Join) joinHandle;
- obj->setStrokeJoin(join);
- }
-
- static jboolean getFillPath(JNIEnv* env, jobject clazz, jlong objHandle, jlong srcHandle, jlong dstHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
- SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
- return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
- }
-
- static jlong setShader(JNIEnv* env, jobject clazz, jlong objHandle, jlong shaderHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
- return reinterpret_cast<jlong>(obj->setShader(shader));
- }
-
- static jlong setColorFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong filterHandle) {
- Paint* obj = reinterpret_cast<Paint *>(objHandle);
- SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(filterHandle);
- return reinterpret_cast<jlong>(obj->setColorFilter(filter));
- }
-
- static void setXfermode(JNIEnv* env, jobject clazz, jlong paintHandle, jint xfermodeHandle) {
- // validate that the Java enum values match our expectations
- static_assert(0 == SkXfermode::kClear_Mode, "xfermode_mismatch");
- static_assert(1 == SkXfermode::kSrc_Mode, "xfermode_mismatch");
- static_assert(2 == SkXfermode::kDst_Mode, "xfermode_mismatch");
- static_assert(3 == SkXfermode::kSrcOver_Mode, "xfermode_mismatch");
- static_assert(4 == SkXfermode::kDstOver_Mode, "xfermode_mismatch");
- static_assert(5 == SkXfermode::kSrcIn_Mode, "xfermode_mismatch");
- static_assert(6 == SkXfermode::kDstIn_Mode, "xfermode_mismatch");
- static_assert(7 == SkXfermode::kSrcOut_Mode, "xfermode_mismatch");
- static_assert(8 == SkXfermode::kDstOut_Mode, "xfermode_mismatch");
- static_assert(9 == SkXfermode::kSrcATop_Mode, "xfermode_mismatch");
- static_assert(10 == SkXfermode::kDstATop_Mode, "xfermode_mismatch");
- static_assert(11 == SkXfermode::kXor_Mode, "xfermode_mismatch");
- static_assert(16 == SkXfermode::kDarken_Mode, "xfermode_mismatch");
- static_assert(17 == SkXfermode::kLighten_Mode, "xfermode_mismatch");
- static_assert(13 == SkXfermode::kModulate_Mode, "xfermode_mismatch");
- static_assert(14 == SkXfermode::kScreen_Mode, "xfermode_mismatch");
- static_assert(12 == SkXfermode::kPlus_Mode, "xfermode_mismatch");
- static_assert(15 == SkXfermode::kOverlay_Mode, "xfermode_mismatch");
-
- SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- paint->setXfermodeMode(mode);
- }
-
- static jlong setPathEffect(JNIEnv* env, jobject clazz, jlong objHandle, jlong effectHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- SkPathEffect* effect = reinterpret_cast<SkPathEffect*>(effectHandle);
- return reinterpret_cast<jlong>(obj->setPathEffect(effect));
- }
-
- static jlong setMaskFilter(JNIEnv* env, jobject clazz, jlong objHandle, jlong maskfilterHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- SkMaskFilter* maskfilter = reinterpret_cast<SkMaskFilter*>(maskfilterHandle);
- return reinterpret_cast<jlong>(obj->setMaskFilter(maskfilter));
- }
-
- static jlong setTypeface(JNIEnv* env, jobject clazz, jlong objHandle, jlong typefaceHandle) {
- // TODO: in Paint refactoring, set typeface on android Paint, not Paint
- return NULL;
- }
-
- static jlong setRasterizer(JNIEnv* env, jobject clazz, jlong objHandle, jlong rasterizerHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- SkAutoTUnref<SkRasterizer> rasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle));
- return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer));
- }
-
- static jint getTextAlign(JNIEnv* env, jobject clazz, jlong objHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- return static_cast<jint>(obj->getTextAlign());
- }
-
- static void setTextAlign(JNIEnv* env, jobject clazz, jlong objHandle, jint alignHandle) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- Paint::Align align = static_cast<Paint::Align>(alignHandle);
- obj->setTextAlign(align);
- }
-
- static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- ScopedUtfChars localesChars(env, locales);
- jint minikinLangListId = minikin::FontStyle::registerLanguageList(localesChars.c_str());
- obj->setMinikinLangListId(minikinLangListId);
- return minikinLangListId;
- }
-
- static void setTextLocalesByMinikinLangListId(JNIEnv* env, jobject clazz, jlong objHandle,
- jint minikinLangListId) {
- Paint* obj = reinterpret_cast<Paint*>(objHandle);
- obj->setMinikinLangListId(minikinLangListId);
- }
-
- static jboolean isElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle) {
- Paint* obj = reinterpret_cast<Paint*>(paintHandle);
- return obj->getFontVariant() == minikin::VARIANT_ELEGANT;
- }
-
- static void setElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
- Paint* obj = reinterpret_cast<Paint*>(paintHandle);
- obj->setFontVariant(aa ? minikin::VARIANT_ELEGANT : minikin::VARIANT_DEFAULT);
- }
-
- static jfloat getTextSize(JNIEnv* env, jobject, jlong paintHandle) {
- return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize());
- }
-
- static void setTextSize(JNIEnv* env, jobject, jlong paintHandle, jfloat textSize) {
- reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize);
- }
-
- static jfloat getTextScaleX(JNIEnv* env, jobject, jlong paintHandle) {
- return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX());
- }
-
- static void setTextScaleX(JNIEnv* env, jobject, jlong paintHandle, jfloat scaleX) {
- reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX);
- }
-
- static jfloat getTextSkewX(JNIEnv* env, jobject, jlong paintHandle) {
- return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX());
- }
-
- static void setTextSkewX(JNIEnv* env, jobject, jlong paintHandle, jfloat skewX) {
- reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX);
- }
-
- static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) {
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- return paint->getLetterSpacing();
- }
-
- static void setLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat letterSpacing) {
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- paint->setLetterSpacing(letterSpacing);
- }
-
- static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- if (!settings) {
- paint->setFontFeatureSettings(std::string());
- } else {
- ScopedUtfChars settingsChars(env, settings);
- paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
+ if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
+ AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
+ jfloat* array = autoMeasured.ptr();
+ array[0] = measured;
}
+ return measuredCount;
}
- static jint getHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- return paint->getHyphenEdit();
- }
+ static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle,
+ jcharArray jtext, jint index, jint count, jfloat maxWidth, jint bidiFlags,
+ jfloatArray jmeasuredWidth) {
+ NPE_CHECK_RETURN_ZERO(env, jtext);
- static void setHyphenEdit(JNIEnv* env, jobject clazz, jlong paintHandle, jint hyphen) {
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- paint->setHyphenEdit((uint32_t)hyphen);
- }
-
- static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle,
- Paint::FontMetrics *metrics) {
- const int kElegantTop = 2500;
- const int kElegantBottom = -1000;
- const int kElegantAscent = 1900;
- const int kElegantDescent = -500;
- const int kElegantLeading = 0;
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
- typeface = Typeface::resolveDefault(typeface);
- minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
- float saveSkewX = paint->getTextSkewX();
- bool savefakeBold = paint->isFakeBoldText();
- MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
- SkScalar spacing = paint->getFontMetrics(metrics);
- // The populateSkPaint call may have changed fake bold / text skew
- // because we want to measure with those effects applied, so now
- // restore the original settings.
- paint->setTextSkewX(saveSkewX);
- paint->setFakeBoldText(savefakeBold);
- if (paint->getFontVariant() == minikin::VARIANT_ELEGANT) {
- SkScalar size = paint->getTextSize();
- metrics->fTop = -size * kElegantTop / 2048;
- metrics->fBottom = -size * kElegantBottom / 2048;
- metrics->fAscent = -size * kElegantAscent / 2048;
- metrics->fDescent = -size * kElegantDescent / 2048;
- metrics->fLeading = size * kElegantLeading / 2048;
- spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
+
+ bool forwardTextDirection;
+ if (count < 0) {
+ forwardTextDirection = false;
+ count = -count;
}
- return spacing;
- }
-
- static jfloat ascent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
- Paint::FontMetrics metrics;
- getMetricsInternal(paintHandle, typefaceHandle, &metrics);
- return SkScalarToFloat(metrics.fAscent);
- }
-
- static jfloat descent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
- Paint::FontMetrics metrics;
- getMetricsInternal(paintHandle, typefaceHandle, &metrics);
- return SkScalarToFloat(metrics.fDescent);
- }
-
- static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle,
- jlong typefaceHandle, jobject metricsObj) {
- Paint::FontMetrics metrics;
- SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics);
-
- if (metricsObj) {
- SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
- env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
- env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
- env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
- env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
- env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
+ else {
+ forwardTextDirection = true;
}
- return SkScalarToFloat(spacing);
+
+ if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
+ doThrowAIOOBE(env);
+ return 0;
+ }
+
+ const jchar* text = env->GetCharArrayElements(jtext, nullptr);
+ count = breakText(env, *paint, typeface, text + index, count, maxWidth,
+ bidiFlags, jmeasuredWidth, forwardTextDirection);
+ env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
+ JNI_ABORT);
+ return count;
}
- static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle,
- jlong typefaceHandle, jobject metricsObj) {
- Paint::FontMetrics metrics;
+ static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
+ jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
+ NPE_CHECK_RETURN_ZERO(env, jtext);
- getMetricsInternal(paintHandle, typefaceHandle, &metrics);
- int ascent = SkScalarRoundToInt(metrics.fAscent);
- int descent = SkScalarRoundToInt(metrics.fDescent);
- int leading = SkScalarRoundToInt(metrics.fLeading);
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
- if (metricsObj) {
- SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
- env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
- env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
- env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
- env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
- env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
- }
- return descent - ascent + leading;
+ int count = env->GetStringLength(jtext);
+ const jchar* text = env->GetStringChars(jtext, nullptr);
+ count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards);
+ env->ReleaseStringChars(jtext, text);
+ return count;
}
static jfloat doTextAdvances(JNIEnv *env, Paint *paint, Typeface* typeface,
@@ -530,7 +218,7 @@
jint bidiFlags, jfloatArray advances, jint advancesIndex) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
- jchar* textArray = env->GetCharArrayElements(text, NULL);
+ jchar* textArray = env->GetCharArrayElements(text, nullptr);
jfloat result = doTextAdvances(env, paint, typeface, textArray + contextIndex,
index - contextIndex, count, contextCount, bidiFlags, advances, advancesIndex);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
@@ -543,7 +231,7 @@
jfloatArray advances, jint advancesIndex) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
- const jchar* textArray = env->GetStringChars(text, NULL);
+ const jchar* textArray = env->GetStringChars(text, nullptr);
jfloat result = doTextAdvances(env, paint, typeface, textArray + contextStart,
start - contextStart, end - start, contextEnd - contextStart, bidiFlags,
advances, advancesIndex);
@@ -562,7 +250,7 @@
static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text,
jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- jchar* textArray = env->GetCharArrayElements(text, NULL);
+ jchar* textArray = env->GetCharArrayElements(text, nullptr);
jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir,
offset, cursorOpt);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
@@ -572,7 +260,7 @@
static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text,
jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- const jchar* textArray = env->GetStringChars(text, NULL);
+ const jchar* textArray = env->GetStringChars(text, nullptr);
jint result = doTextRunCursor(env, paint, textArray, contextStart,
contextEnd - contextStart, dir, offset, cursorOpt);
env->ReleaseStringChars(text, textArray);
@@ -635,7 +323,7 @@
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
- const jchar* textArray = env->GetCharArrayElements(text, NULL);
+ const jchar* textArray = env->GetCharArrayElements(text, nullptr);
getTextPath(env, paint, typeface, textArray + index, count, bidiFlags, x, y, path);
env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
}
@@ -646,103 +334,11 @@
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
- const jchar* textArray = env->GetStringChars(text, NULL);
+ const jchar* textArray = env->GetStringChars(text, nullptr);
getTextPath(env, paint, typeface, textArray + start, end - start, bidiFlags, x, y, path);
env->ReleaseStringChars(text, textArray);
}
- static void setShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle, jfloat radius,
- jfloat dx, jfloat dy, jint color) {
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- if (radius <= 0) {
- paint->setLooper(NULL);
- }
- else {
- SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
- paint->setLooper(SkBlurDrawLooper::Create((SkColor)color, sigma, dx, dy))->unref();
- }
- }
-
- static jboolean hasShadowLayer(JNIEnv* env, jobject clazz, jlong paintHandle) {
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- return paint->getLooper() && paint->getLooper()->asABlurShadow(NULL);
- }
-
- static int breakText(JNIEnv* env, const Paint& paint, Typeface* typeface, const jchar text[],
- int count, float maxWidth, jint bidiFlags, jfloatArray jmeasured,
- const bool forwardScan) {
- size_t measuredCount = 0;
- float measured = 0;
-
- std::unique_ptr<float[]> advancesArray(new float[count]);
- MinikinUtils::measureText(&paint, bidiFlags, typeface, text, 0, count, count,
- advancesArray.get());
-
- for (int i = 0; i < count; i++) {
- // traverse in the given direction
- int index = forwardScan ? i : (count - i - 1);
- float width = advancesArray[index];
- if (measured + width > maxWidth) {
- break;
- }
- // properly handle clusters when scanning backwards
- if (forwardScan || width != 0.0f) {
- measuredCount = i + 1;
- }
- measured += width;
- }
-
- if (jmeasured && env->GetArrayLength(jmeasured) > 0) {
- AutoJavaFloatArray autoMeasured(env, jmeasured, 1);
- jfloat* array = autoMeasured.ptr();
- array[0] = measured;
- }
- return measuredCount;
- }
-
- static jint breakTextC(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray jtext,
- jint index, jint count, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
- NPE_CHECK_RETURN_ZERO(env, jtext);
-
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-
- bool forwardTextDirection;
- if (count < 0) {
- forwardTextDirection = false;
- count = -count;
- }
- else {
- forwardTextDirection = true;
- }
-
- if ((index < 0) || (index + count > env->GetArrayLength(jtext))) {
- doThrowAIOOBE(env);
- return 0;
- }
-
- const jchar* text = env->GetCharArrayElements(jtext, NULL);
- count = breakText(env, *paint, typeface, text + index, count, maxWidth,
- bidiFlags, jmeasuredWidth, forwardTextDirection);
- env->ReleaseCharArrayElements(jtext, const_cast<jchar*>(text),
- JNI_ABORT);
- return count;
- }
-
- static jint breakTextS(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring jtext,
- jboolean forwards, jfloat maxWidth, jint bidiFlags, jfloatArray jmeasuredWidth) {
- NPE_CHECK_RETURN_ZERO(env, jtext);
-
- Paint* paint = reinterpret_cast<Paint*>(paintHandle);
- Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
-
- int count = env->GetStringLength(jtext);
- const jchar* text = env->GetStringChars(jtext, NULL);
- count = breakText(env, *paint, typeface, text, count, maxWidth, bidiFlags, jmeasuredWidth, forwards);
- env->ReleaseStringChars(jtext, text);
- return count;
- }
-
static void doTextBounds(JNIEnv* env, const jchar* text, int count, jobject bounds,
const Paint& paint, Typeface* typeface, jint bidiFlags) {
SkRect r;
@@ -764,7 +360,7 @@
jstring text, jint start, jint end, jint bidiFlags, jobject bounds) {
const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
- const jchar* textArray = env->GetStringChars(text, NULL);
+ const jchar* textArray = env->GetStringChars(text, nullptr);
doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
env->ReleaseStringChars(text, textArray);
}
@@ -773,12 +369,28 @@
jcharArray text, jint index, jint count, jint bidiFlags, jobject bounds) {
const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
- const jchar* textArray = env->GetCharArrayElements(text, NULL);
+ const jchar* textArray = env->GetCharArrayElements(text, nullptr);
doTextBounds(env, textArray + index, count, bounds, *paint, typeface, bidiFlags);
env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
JNI_ABORT);
}
+ // Returns true if the given string is exact one pair of regional indicators.
+ static bool isFlag(const jchar* str, size_t length) {
+ const jchar RI_LEAD_SURROGATE = 0xD83C;
+ const jchar RI_TRAIL_SURROGATE_MIN = 0xDDE6;
+ const jchar RI_TRAIL_SURROGATE_MAX = 0xDDFF;
+
+ if (length != 4) {
+ return false;
+ }
+ if (str[0] != RI_LEAD_SURROGATE || str[2] != RI_LEAD_SURROGATE) {
+ return false;
+ }
+ return RI_TRAIL_SURROGATE_MIN <= str[1] && str[1] <= RI_TRAIL_SURROGATE_MAX &&
+ RI_TRAIL_SURROGATE_MIN <= str[3] && str[3] <= RI_TRAIL_SURROGATE_MAX;
+ }
+
static jboolean layoutContainsNotdef(const minikin::Layout& layout) {
for (size_t i = 0; i < layout.nGlyphs(); i++) {
if (layout.getGlyphId(i) == 0) {
@@ -803,22 +415,6 @@
return count;
}
- // Returns true if the given string is exact one pair of regional indicators.
- static bool isFlag(const jchar* str, size_t length) {
- const jchar RI_LEAD_SURROGATE = 0xD83C;
- const jchar RI_TRAIL_SURROGATE_MIN = 0xDDE6;
- const jchar RI_TRAIL_SURROGATE_MAX = 0xDDFF;
-
- if (length != 4) {
- return false;
- }
- if (str[0] != RI_LEAD_SURROGATE || str[2] != RI_LEAD_SURROGATE) {
- return false;
- }
- return RI_TRAIL_SURROGATE_MIN <= str[1] && str[1] <= RI_TRAIL_SURROGATE_MAX &&
- RI_TRAIL_SURROGATE_MIN <= str[3] && str[3] <= RI_TRAIL_SURROGATE_MAX;
- }
-
static jboolean hasGlyph(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle,
jint bidiFlags, jstring string) {
const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
@@ -913,7 +509,7 @@
jint contextEnd, jboolean isRtl, jint offset) {
const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
- jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL);
+ jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, nullptr);
jfloat result = doRunAdvance(paint, typeface, textArray + contextStart,
start - contextStart, end - start, contextEnd - contextStart, isRtl,
offset - contextStart);
@@ -935,7 +531,7 @@
jint contextEnd, jboolean isRtl, jfloat advance) {
const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
- jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, NULL);
+ jchar* textArray = (jchar*) env->GetPrimitiveArrayCritical(text, nullptr);
jint result = doOffsetForAdvance(paint, typeface, textArray + contextStart,
start - contextStart, end - start, contextEnd - contextStart, isRtl, advance);
result += contextStart;
@@ -943,76 +539,422 @@
return result;
}
+ // ------------------ @FastNative ---------------------------
+
+ static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ ScopedUtfChars localesChars(env, locales);
+ jint minikinLangListId = minikin::FontStyle::registerLanguageList(localesChars.c_str());
+ obj->setMinikinLangListId(minikinLangListId);
+ return minikinLangListId;
+ }
+
+ static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ if (!settings) {
+ paint->setFontFeatureSettings(std::string());
+ } else {
+ ScopedUtfChars settingsChars(env, settings);
+ paint->setFontFeatureSettings(std::string(settingsChars.c_str(), settingsChars.size()));
+ }
+ }
+
+ static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle,
+ Paint::FontMetrics *metrics) {
+ const int kElegantTop = 2500;
+ const int kElegantBottom = -1000;
+ const int kElegantAscent = 1900;
+ const int kElegantDescent = -500;
+ const int kElegantLeading = 0;
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ Typeface* typeface = reinterpret_cast<Typeface*>(typefaceHandle);
+ typeface = Typeface::resolveDefault(typeface);
+ minikin::FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
+ float saveSkewX = paint->getTextSkewX();
+ bool savefakeBold = paint->isFakeBoldText();
+ MinikinFontSkia::populateSkPaint(paint, baseFont.font, baseFont.fakery);
+ SkScalar spacing = paint->getFontMetrics(metrics);
+ // The populateSkPaint call may have changed fake bold / text skew
+ // because we want to measure with those effects applied, so now
+ // restore the original settings.
+ paint->setTextSkewX(saveSkewX);
+ paint->setFakeBoldText(savefakeBold);
+ if (paint->getFontVariant() == minikin::VARIANT_ELEGANT) {
+ SkScalar size = paint->getTextSize();
+ metrics->fTop = -size * kElegantTop / 2048;
+ metrics->fBottom = -size * kElegantBottom / 2048;
+ metrics->fAscent = -size * kElegantAscent / 2048;
+ metrics->fDescent = -size * kElegantDescent / 2048;
+ metrics->fLeading = size * kElegantLeading / 2048;
+ spacing = metrics->fDescent - metrics->fAscent + metrics->fLeading;
+ }
+ return spacing;
+ }
+
+ static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle,
+ jlong typefaceHandle, jobject metricsObj) {
+ Paint::FontMetrics metrics;
+ SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+
+ if (metricsObj) {
+ SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
+ env->SetFloatField(metricsObj, gFontMetrics_fieldID.top, SkScalarToFloat(metrics.fTop));
+ env->SetFloatField(metricsObj, gFontMetrics_fieldID.ascent, SkScalarToFloat(metrics.fAscent));
+ env->SetFloatField(metricsObj, gFontMetrics_fieldID.descent, SkScalarToFloat(metrics.fDescent));
+ env->SetFloatField(metricsObj, gFontMetrics_fieldID.bottom, SkScalarToFloat(metrics.fBottom));
+ env->SetFloatField(metricsObj, gFontMetrics_fieldID.leading, SkScalarToFloat(metrics.fLeading));
+ }
+ return SkScalarToFloat(spacing);
+ }
+
+ static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle,
+ jlong typefaceHandle, jobject metricsObj) {
+ Paint::FontMetrics metrics;
+
+ getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+ int ascent = SkScalarRoundToInt(metrics.fAscent);
+ int descent = SkScalarRoundToInt(metrics.fDescent);
+ int leading = SkScalarRoundToInt(metrics.fLeading);
+
+ if (metricsObj) {
+ SkASSERT(env->IsInstanceOf(metricsObj, gFontMetricsInt_class));
+ env->SetIntField(metricsObj, gFontMetricsInt_fieldID.top, SkScalarFloorToInt(metrics.fTop));
+ env->SetIntField(metricsObj, gFontMetricsInt_fieldID.ascent, ascent);
+ env->SetIntField(metricsObj, gFontMetricsInt_fieldID.descent, descent);
+ env->SetIntField(metricsObj, gFontMetricsInt_fieldID.bottom, SkScalarCeilToInt(metrics.fBottom));
+ env->SetIntField(metricsObj, gFontMetricsInt_fieldID.leading, leading);
+ }
+ return descent - ascent + leading;
+ }
+
+
+ // ------------------ @CriticalNative ---------------------------
+
+ static void reset(jlong objHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ obj->reset();
+ defaultSettingsForAndroid(obj);
+ }
+
+ static void assign(jlong dstPaintHandle, jlong srcPaintHandle) {
+ Paint* dst = reinterpret_cast<Paint*>(dstPaintHandle);
+ const Paint* src = reinterpret_cast<Paint*>(srcPaintHandle);
+ *dst = *src;
+ }
+
+ // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
+ static const uint32_t sFilterBitmapFlag = 0x02;
+
+ static jint getFlags(jlong paintHandle) {
+ Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
+ uint32_t result = nativePaint->getFlags();
+ result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
+ if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) {
+ result |= sFilterBitmapFlag;
+ }
+ return static_cast<jint>(result);
+ }
+
+ static void setFlags(jlong paintHandle, jint flags) {
+ Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
+ // Instead of modifying 0x02, change the filter level.
+ nativePaint->setFilterQuality(flags & sFilterBitmapFlag
+ ? kLow_SkFilterQuality
+ : kNone_SkFilterQuality);
+ // Don't pass through filter flag, which is no longer stored in paint's flags.
+ flags &= ~sFilterBitmapFlag;
+ // Use the existing value for 0x02.
+ const uint32_t existing0x02Flag = nativePaint->getFlags() & sFilterBitmapFlag;
+ flags |= existing0x02Flag;
+ nativePaint->setFlags(flags);
+ }
+
+ static jint getHinting(jlong paintHandle) {
+ return reinterpret_cast<Paint*>(paintHandle)->getHinting()
+ == Paint::kNo_Hinting ? 0 : 1;
+ }
+
+ static void setHinting(jlong paintHandle, jint mode) {
+ reinterpret_cast<Paint*>(paintHandle)->setHinting(
+ mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
+ }
+
+ static void setAntiAlias(jlong paintHandle, jboolean aa) {
+ reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa);
+ }
+
+ static void setLinearText(jlong paintHandle, jboolean linearText) {
+ reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText);
+ }
+
+ static void setSubpixelText(jlong paintHandle, jboolean subpixelText) {
+ reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText);
+ }
+
+ static void setUnderlineText(jlong paintHandle, jboolean underlineText) {
+ reinterpret_cast<Paint*>(paintHandle)->setUnderlineText(underlineText);
+ }
+
+ static void setStrikeThruText(jlong paintHandle, jboolean strikeThruText) {
+ reinterpret_cast<Paint*>(paintHandle)->setStrikeThruText(strikeThruText);
+ }
+
+ static void setFakeBoldText(jlong paintHandle, jboolean fakeBoldText) {
+ reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText);
+ }
+
+ static void setFilterBitmap(jlong paintHandle, jboolean filterBitmap) {
+ reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
+ filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
+ }
+
+ static void setDither(jlong paintHandle, jboolean dither) {
+ reinterpret_cast<Paint*>(paintHandle)->setDither(dither);
+ }
+
+ static jint getStyle(jlong objHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ return static_cast<jint>(obj->getStyle());
+ }
+
+ static void setStyle(jlong objHandle, jint styleHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ Paint::Style style = static_cast<Paint::Style>(styleHandle);
+ obj->setStyle(style);
+ }
+
+ static jint getColor(jlong paintHandle) {
+ int color;
+ color = reinterpret_cast<Paint*>(paintHandle)->getColor();
+ return static_cast<jint>(color);
+ }
+
+ static jint getAlpha(jlong paintHandle) {
+ int alpha;
+ alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
+ return static_cast<jint>(alpha);
+ }
+
+ static void setColor(jlong paintHandle, jint color) {
+ reinterpret_cast<Paint*>(paintHandle)->setColor(color);
+ }
+
+ static void setAlpha(jlong paintHandle, jint a) {
+ reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
+ }
+
+ static jfloat getStrokeWidth(jlong paintHandle) {
+ return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth());
+ }
+
+ static void setStrokeWidth(jlong paintHandle, jfloat width) {
+ reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width);
+ }
+
+ static jfloat getStrokeMiter(jlong paintHandle) {
+ return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter());
+ }
+
+ static void setStrokeMiter(jlong paintHandle, jfloat miter) {
+ reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter);
+ }
+
+ static jint getStrokeCap(jlong objHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ return static_cast<jint>(obj->getStrokeCap());
+ }
+
+ static void setStrokeCap(jlong objHandle, jint capHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ Paint::Cap cap = static_cast<Paint::Cap>(capHandle);
+ obj->setStrokeCap(cap);
+ }
+
+ static jint getStrokeJoin(jlong objHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ return static_cast<jint>(obj->getStrokeJoin());
+ }
+
+ static void setStrokeJoin(jlong objHandle, jint joinHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ Paint::Join join = (Paint::Join) joinHandle;
+ obj->setStrokeJoin(join);
+ }
+
+ static jboolean getFillPath(jlong objHandle, jlong srcHandle, jlong dstHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ SkPath* src = reinterpret_cast<SkPath*>(srcHandle);
+ SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
+ return obj->getFillPath(*src, dst) ? JNI_TRUE : JNI_FALSE;
+ }
+
+ static jlong setShader(jlong objHandle, jlong shaderHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
+ return reinterpret_cast<jlong>(obj->setShader(shader));
+ }
+
+ static jlong setColorFilter(jlong objHandle, jlong filterHandle) {
+ Paint* obj = reinterpret_cast<Paint *>(objHandle);
+ SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(filterHandle);
+ return reinterpret_cast<jlong>(obj->setColorFilter(filter));
+ }
+
+ static void setXfermode(jlong paintHandle, jint xfermodeHandle) {
+ // validate that the Java enum values match our expectations
+ static_assert(0 == SkXfermode::kClear_Mode, "xfermode_mismatch");
+ static_assert(1 == SkXfermode::kSrc_Mode, "xfermode_mismatch");
+ static_assert(2 == SkXfermode::kDst_Mode, "xfermode_mismatch");
+ static_assert(3 == SkXfermode::kSrcOver_Mode, "xfermode_mismatch");
+ static_assert(4 == SkXfermode::kDstOver_Mode, "xfermode_mismatch");
+ static_assert(5 == SkXfermode::kSrcIn_Mode, "xfermode_mismatch");
+ static_assert(6 == SkXfermode::kDstIn_Mode, "xfermode_mismatch");
+ static_assert(7 == SkXfermode::kSrcOut_Mode, "xfermode_mismatch");
+ static_assert(8 == SkXfermode::kDstOut_Mode, "xfermode_mismatch");
+ static_assert(9 == SkXfermode::kSrcATop_Mode, "xfermode_mismatch");
+ static_assert(10 == SkXfermode::kDstATop_Mode, "xfermode_mismatch");
+ static_assert(11 == SkXfermode::kXor_Mode, "xfermode_mismatch");
+ static_assert(16 == SkXfermode::kDarken_Mode, "xfermode_mismatch");
+ static_assert(17 == SkXfermode::kLighten_Mode, "xfermode_mismatch");
+ static_assert(13 == SkXfermode::kModulate_Mode, "xfermode_mismatch");
+ static_assert(14 == SkXfermode::kScreen_Mode, "xfermode_mismatch");
+ static_assert(12 == SkXfermode::kPlus_Mode, "xfermode_mismatch");
+ static_assert(15 == SkXfermode::kOverlay_Mode, "xfermode_mismatch");
+
+ SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(xfermodeHandle);
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ paint->setXfermodeMode(mode);
+ }
+
+ static jlong setPathEffect(jlong objHandle, jlong effectHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ SkPathEffect* effect = reinterpret_cast<SkPathEffect*>(effectHandle);
+ return reinterpret_cast<jlong>(obj->setPathEffect(effect));
+ }
+
+ static jlong setMaskFilter(jlong objHandle, jlong maskfilterHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ SkMaskFilter* maskfilter = reinterpret_cast<SkMaskFilter*>(maskfilterHandle);
+ return reinterpret_cast<jlong>(obj->setMaskFilter(maskfilter));
+ }
+
+ static jlong setTypeface(jlong objHandle, jlong typefaceHandle) {
+ // TODO: in Paint refactoring, set typeface on android Paint, not Paint
+ return 0;
+ }
+
+ static jlong setRasterizer(jlong objHandle, jlong rasterizerHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ SkAutoTUnref<SkRasterizer> rasterizer(GraphicsJNI::refNativeRasterizer(rasterizerHandle));
+ return reinterpret_cast<jlong>(obj->setRasterizer(rasterizer));
+ }
+
+ static jint getTextAlign(jlong objHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ return static_cast<jint>(obj->getTextAlign());
+ }
+
+ static void setTextAlign(jlong objHandle, jint alignHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ Paint::Align align = static_cast<Paint::Align>(alignHandle);
+ obj->setTextAlign(align);
+ }
+
+ static void setTextLocalesByMinikinLangListId(jlong objHandle,
+ jint minikinLangListId) {
+ Paint* obj = reinterpret_cast<Paint*>(objHandle);
+ obj->setMinikinLangListId(minikinLangListId);
+ }
+
+ static jboolean isElegantTextHeight(jlong paintHandle) {
+ Paint* obj = reinterpret_cast<Paint*>(paintHandle);
+ return obj->getFontVariant() == minikin::VARIANT_ELEGANT;
+ }
+
+ static void setElegantTextHeight(jlong paintHandle, jboolean aa) {
+ Paint* obj = reinterpret_cast<Paint*>(paintHandle);
+ obj->setFontVariant(aa ? minikin::VARIANT_ELEGANT : minikin::VARIANT_DEFAULT);
+ }
+
+ static jfloat getTextSize(jlong paintHandle) {
+ return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize());
+ }
+
+ static void setTextSize(jlong paintHandle, jfloat textSize) {
+ reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize);
+ }
+
+ static jfloat getTextScaleX(jlong paintHandle) {
+ return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX());
+ }
+
+ static void setTextScaleX(jlong paintHandle, jfloat scaleX) {
+ reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX);
+ }
+
+ static jfloat getTextSkewX(jlong paintHandle) {
+ return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX());
+ }
+
+ static void setTextSkewX(jlong paintHandle, jfloat skewX) {
+ reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX);
+ }
+
+ static jfloat getLetterSpacing(jlong paintHandle) {
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ return paint->getLetterSpacing();
+ }
+
+ static void setLetterSpacing(jlong paintHandle, jfloat letterSpacing) {
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ paint->setLetterSpacing(letterSpacing);
+ }
+
+ static jint getHyphenEdit(jlong paintHandle, jint hyphen) {
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ return paint->getHyphenEdit();
+ }
+
+ static void setHyphenEdit(jlong paintHandle, jint hyphen) {
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ paint->setHyphenEdit((uint32_t)hyphen);
+ }
+
+ static jfloat ascent(jlong paintHandle, jlong typefaceHandle) {
+ Paint::FontMetrics metrics;
+ getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+ return SkScalarToFloat(metrics.fAscent);
+ }
+
+ static jfloat descent(jlong paintHandle, jlong typefaceHandle) {
+ Paint::FontMetrics metrics;
+ getMetricsInternal(paintHandle, typefaceHandle, &metrics);
+ return SkScalarToFloat(metrics.fDescent);
+ }
+
+ static void setShadowLayer(jlong paintHandle, jfloat radius,
+ jfloat dx, jfloat dy, jint color) {
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ if (radius <= 0) {
+ paint->setLooper(nullptr);
+ }
+ else {
+ SkScalar sigma = android::uirenderer::Blur::convertRadiusToSigma(radius);
+ paint->setLooper(SkBlurDrawLooper::Create((SkColor)color, sigma, dx, dy))->unref();
+ }
+ }
+
+ static jboolean hasShadowLayer(jlong paintHandle) {
+ Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+ return paint->getLooper() && paint->getLooper()->asABlurShadow(nullptr);
+ }
+
}; // namespace PaintGlue
static const JNINativeMethod methods[] = {
{"nGetNativeFinalizer", "()J", (void*) PaintGlue::getNativeFinalizer},
{"nInit","()J", (void*) PaintGlue::init},
{"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
-
- {"nReset","!(J)V", (void*) PaintGlue::reset},
- {"nSet","!(JJ)V", (void*) PaintGlue::assign},
- {"nGetFlags","!(J)I", (void*) PaintGlue::getFlags},
- {"nSetFlags","!(JI)V", (void*) PaintGlue::setFlags},
- {"nGetHinting","!(J)I", (void*) PaintGlue::getHinting},
- {"nSetHinting","!(JI)V", (void*) PaintGlue::setHinting},
- {"nSetAntiAlias","!(JZ)V", (void*) PaintGlue::setAntiAlias},
- {"nSetSubpixelText","!(JZ)V", (void*) PaintGlue::setSubpixelText},
- {"nSetLinearText","!(JZ)V", (void*) PaintGlue::setLinearText},
- {"nSetUnderlineText","!(JZ)V", (void*) PaintGlue::setUnderlineText},
- {"nSetStrikeThruText","!(JZ)V", (void*) PaintGlue::setStrikeThruText},
- {"nSetFakeBoldText","!(JZ)V", (void*) PaintGlue::setFakeBoldText},
- {"nSetFilterBitmap","!(JZ)V", (void*) PaintGlue::setFilterBitmap},
- {"nSetDither","!(JZ)V", (void*) PaintGlue::setDither},
- {"nGetStyle","!(J)I", (void*) PaintGlue::getStyle},
- {"nSetStyle","!(JI)V", (void*) PaintGlue::setStyle},
- {"nGetColor","!(J)I", (void*) PaintGlue::getColor},
- {"nSetColor","!(JI)V", (void*) PaintGlue::setColor},
- {"nGetAlpha","!(J)I", (void*) PaintGlue::getAlpha},
- {"nSetAlpha","!(JI)V", (void*) PaintGlue::setAlpha},
- {"nGetStrokeWidth","!(J)F", (void*) PaintGlue::getStrokeWidth},
- {"nSetStrokeWidth","!(JF)V", (void*) PaintGlue::setStrokeWidth},
- {"nGetStrokeMiter","!(J)F", (void*) PaintGlue::getStrokeMiter},
- {"nSetStrokeMiter","!(JF)V", (void*) PaintGlue::setStrokeMiter},
- {"nGetStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
- {"nSetStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
- {"nGetStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
- {"nSetStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
- {"nGetFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
- {"nSetShader","!(JJ)J", (void*) PaintGlue::setShader},
- {"nSetColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
- {"nSetXfermode","!(JI)V", (void*) PaintGlue::setXfermode},
- {"nSetPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
- {"nSetMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
- {"nSetTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
- {"nSetRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
- {"nGetTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
- {"nSetTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
- {"nSetTextLocales","!(JLjava/lang/String;)I", (void*) PaintGlue::setTextLocales},
- {"nSetTextLocalesByMinikinLangListId","!(JI)V",
- (void*) PaintGlue::setTextLocalesByMinikinLangListId},
- {"nIsElegantTextHeight","!(J)Z", (void*) PaintGlue::isElegantTextHeight},
- {"nSetElegantTextHeight","!(JZ)V", (void*) PaintGlue::setElegantTextHeight},
- {"nGetTextSize","!(J)F", (void*) PaintGlue::getTextSize},
- {"nSetTextSize","!(JF)V", (void*) PaintGlue::setTextSize},
- {"nGetTextScaleX","!(J)F", (void*) PaintGlue::getTextScaleX},
- {"nSetTextScaleX","!(JF)V", (void*) PaintGlue::setTextScaleX},
- {"nGetTextSkewX","!(J)F", (void*) PaintGlue::getTextSkewX},
- {"nSetTextSkewX","!(JF)V", (void*) PaintGlue::setTextSkewX},
- {"nGetLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
- {"nSetLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
- {"nSetFontFeatureSettings","(JLjava/lang/String;)V",
- (void*) PaintGlue::setFontFeatureSettings},
- {"nGetHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit},
- {"nSetHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit},
- {"nAscent","!(JJ)F", (void*) PaintGlue::ascent},
- {"nDescent","!(JJ)F", (void*) PaintGlue::descent},
-
- {"nGetFontMetrics", "!(JJLandroid/graphics/Paint$FontMetrics;)F",
- (void*)PaintGlue::getFontMetrics},
- {"nGetFontMetricsInt", "!(JJLandroid/graphics/Paint$FontMetricsInt;)I",
- (void*)PaintGlue::getFontMetricsInt},
-
{"nBreakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
{"nBreakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
{"nGetTextAdvances","(JJ[CIIIII[FI)F",
@@ -1034,8 +976,74 @@
{"nGetOffsetForAdvance", "(JJ[CIIIIZF)I",
(void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I},
- {"nSetShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
- {"nHasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
+ // --------------- @FastNative ----------------------
+
+ {"nSetTextLocales","(JLjava/lang/String;)I", (void*) PaintGlue::setTextLocales},
+ {"nSetFontFeatureSettings","(JLjava/lang/String;)V",
+ (void*) PaintGlue::setFontFeatureSettings},
+ {"nGetFontMetrics", "(JJLandroid/graphics/Paint$FontMetrics;)F",
+ (void*)PaintGlue::getFontMetrics},
+ {"nGetFontMetricsInt", "(JJLandroid/graphics/Paint$FontMetricsInt;)I",
+ (void*)PaintGlue::getFontMetricsInt},
+
+ // --------------- @CriticalNative ------------------
+
+ {"nReset","(J)V", (void*) PaintGlue::reset},
+ {"nSet","(JJ)V", (void*) PaintGlue::assign},
+ {"nGetFlags","(J)I", (void*) PaintGlue::getFlags},
+ {"nSetFlags","(JI)V", (void*) PaintGlue::setFlags},
+ {"nGetHinting","(J)I", (void*) PaintGlue::getHinting},
+ {"nSetHinting","(JI)V", (void*) PaintGlue::setHinting},
+ {"nSetAntiAlias","(JZ)V", (void*) PaintGlue::setAntiAlias},
+ {"nSetSubpixelText","(JZ)V", (void*) PaintGlue::setSubpixelText},
+ {"nSetLinearText","(JZ)V", (void*) PaintGlue::setLinearText},
+ {"nSetUnderlineText","(JZ)V", (void*) PaintGlue::setUnderlineText},
+ {"nSetStrikeThruText","(JZ)V", (void*) PaintGlue::setStrikeThruText},
+ {"nSetFakeBoldText","(JZ)V", (void*) PaintGlue::setFakeBoldText},
+ {"nSetFilterBitmap","(JZ)V", (void*) PaintGlue::setFilterBitmap},
+ {"nSetDither","(JZ)V", (void*) PaintGlue::setDither},
+ {"nGetStyle","(J)I", (void*) PaintGlue::getStyle},
+ {"nSetStyle","(JI)V", (void*) PaintGlue::setStyle},
+ {"nGetColor","(J)I", (void*) PaintGlue::getColor},
+ {"nSetColor","(JI)V", (void*) PaintGlue::setColor},
+ {"nGetAlpha","(J)I", (void*) PaintGlue::getAlpha},
+ {"nSetAlpha","(JI)V", (void*) PaintGlue::setAlpha},
+ {"nGetStrokeWidth","(J)F", (void*) PaintGlue::getStrokeWidth},
+ {"nSetStrokeWidth","(JF)V", (void*) PaintGlue::setStrokeWidth},
+ {"nGetStrokeMiter","(J)F", (void*) PaintGlue::getStrokeMiter},
+ {"nSetStrokeMiter","(JF)V", (void*) PaintGlue::setStrokeMiter},
+ {"nGetStrokeCap","(J)I", (void*) PaintGlue::getStrokeCap},
+ {"nSetStrokeCap","(JI)V", (void*) PaintGlue::setStrokeCap},
+ {"nGetStrokeJoin","(J)I", (void*) PaintGlue::getStrokeJoin},
+ {"nSetStrokeJoin","(JI)V", (void*) PaintGlue::setStrokeJoin},
+ {"nGetFillPath","(JJJ)Z", (void*) PaintGlue::getFillPath},
+ {"nSetShader","(JJ)J", (void*) PaintGlue::setShader},
+ {"nSetColorFilter","(JJ)J", (void*) PaintGlue::setColorFilter},
+ {"nSetXfermode","(JI)V", (void*) PaintGlue::setXfermode},
+ {"nSetPathEffect","(JJ)J", (void*) PaintGlue::setPathEffect},
+ {"nSetMaskFilter","(JJ)J", (void*) PaintGlue::setMaskFilter},
+ {"nSetTypeface","(JJ)J", (void*) PaintGlue::setTypeface},
+ {"nSetRasterizer","(JJ)J", (void*) PaintGlue::setRasterizer},
+ {"nGetTextAlign","(J)I", (void*) PaintGlue::getTextAlign},
+ {"nSetTextAlign","(JI)V", (void*) PaintGlue::setTextAlign},
+ {"nSetTextLocalesByMinikinLangListId","(JI)V",
+ (void*) PaintGlue::setTextLocalesByMinikinLangListId},
+ {"nIsElegantTextHeight","(J)Z", (void*) PaintGlue::isElegantTextHeight},
+ {"nSetElegantTextHeight","(JZ)V", (void*) PaintGlue::setElegantTextHeight},
+ {"nGetTextSize","(J)F", (void*) PaintGlue::getTextSize},
+ {"nSetTextSize","(JF)V", (void*) PaintGlue::setTextSize},
+ {"nGetTextScaleX","(J)F", (void*) PaintGlue::getTextScaleX},
+ {"nSetTextScaleX","(JF)V", (void*) PaintGlue::setTextScaleX},
+ {"nGetTextSkewX","(J)F", (void*) PaintGlue::getTextSkewX},
+ {"nSetTextSkewX","(JF)V", (void*) PaintGlue::setTextSkewX},
+ {"nGetLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing},
+ {"nSetLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing},
+ {"nGetHyphenEdit", "(J)I", (void*) PaintGlue::getHyphenEdit},
+ {"nSetHyphenEdit", "(JI)V", (void*) PaintGlue::setHyphenEdit},
+ {"nAscent","(JJ)F", (void*) PaintGlue::ascent},
+ {"nDescent","(JJ)F", (void*) PaintGlue::descent},
+ {"nSetShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer},
+ {"nHasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer}
};
int register_android_graphics_Paint(JNIEnv* env) {
diff --git a/core/jni/android_app_admin_SecurityLog.cpp b/core/jni/android_app_admin_SecurityLog.cpp
index da47c4c..e8ca793 100644
--- a/core/jni/android_app_admin_SecurityLog.cpp
+++ b/core/jni/android_app_admin_SecurityLog.cpp
@@ -19,7 +19,7 @@
#include "JNIHelp.h"
#include "core_jni_helpers.h"
#include "jni.h"
-#include "log/logger.h"
+#include <private/android_logger.h>
// The size of the tag number comes out of the payload size.
#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index d5a7a90..43f7ca5 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -341,9 +341,8 @@
jlong paintHandle, jint dstDensity, jint srcDensity) {
Canvas* canvas = get_canvas(canvasHandle);
- Bitmap* bitmap = reinterpret_cast<Bitmap*>(bitmapHandle);
SkBitmap skiaBitmap;
- bitmap->getSkBitmap(&skiaBitmap);
+ bitmap::toSkBitmap(bitmapHandle, &skiaBitmap);
const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
@@ -443,9 +442,8 @@
jboolean hasAlpha, jlong paintHandle) {
// Note: If hasAlpha is false, kRGB_565_SkColorType will be used, which will
// correct the alphaType to kOpaque_SkAlphaType.
- SkImageInfo info = SkImageInfo::Make(width, height,
- hasAlpha ? kN32_SkColorType : kRGB_565_SkColorType,
- kPremul_SkAlphaType);
+ SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType,
+ GraphicsJNI::defaultColorSpace());
SkBitmap bitmap;
bitmap.setInfo(info);
if (!GraphicsJNI::allocatePixels(env, &bitmap, NULL)) {
@@ -575,59 +573,61 @@
static const JNINativeMethod gMethods[] = {
{"getNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
{"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
- {"native_setBitmap", "!(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
- {"native_isOpaque","!(J)Z", (void*) CanvasJNI::isOpaque},
- {"native_getWidth","!(J)I", (void*) CanvasJNI::getWidth},
- {"native_getHeight","!(J)I", (void*) CanvasJNI::getHeight},
- {"native_setHighContrastText","!(JZ)V", (void*) CanvasJNI::setHighContrastText},
- {"native_save","!(JI)I", (void*) CanvasJNI::save},
- {"native_saveLayer","!(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
- {"native_saveLayerAlpha","!(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
- {"native_getSaveCount","!(J)I", (void*) CanvasJNI::getSaveCount},
- {"native_restore","!(JZ)V", (void*) CanvasJNI::restore},
- {"native_restoreToCount","!(JIZ)V", (void*) CanvasJNI::restoreToCount},
- {"native_getCTM", "!(JJ)V", (void*)CanvasJNI::getCTM},
- {"native_setMatrix","!(JJ)V", (void*) CanvasJNI::setMatrix},
- {"native_concat","!(JJ)V", (void*) CanvasJNI::concat},
- {"native_rotate","!(JF)V", (void*) CanvasJNI::rotate},
- {"native_scale","!(JFF)V", (void*) CanvasJNI::scale},
- {"native_skew","!(JFF)V", (void*) CanvasJNI::skew},
- {"native_translate","!(JFF)V", (void*) CanvasJNI::translate},
- {"native_getClipBounds","!(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
- {"native_quickReject","!(JJ)Z", (void*) CanvasJNI::quickRejectPath},
- {"native_quickReject","!(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
- {"native_clipRect","!(JFFFFI)Z", (void*) CanvasJNI::clipRect},
- {"native_clipPath","!(JJI)Z", (void*) CanvasJNI::clipPath},
- {"native_clipRegion","!(JJI)Z", (void*) CanvasJNI::clipRegion},
- {"native_drawColor","!(JII)V", (void*) CanvasJNI::drawColor},
- {"native_drawPaint","!(JJ)V", (void*) CanvasJNI::drawPaint},
- {"native_drawPoint", "!(JFFJ)V", (void*) CanvasJNI::drawPoint},
- {"native_drawPoints", "!(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
- {"native_drawLine", "!(JFFFFJ)V", (void*) CanvasJNI::drawLine},
- {"native_drawLines", "!(J[FIIJ)V", (void*) CanvasJNI::drawLines},
- {"native_drawRect","!(JFFFFJ)V", (void*) CanvasJNI::drawRect},
- {"native_drawRegion", "!(JJJ)V", (void*) CanvasJNI::drawRegion },
- {"native_drawRoundRect","!(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
- {"native_drawCircle","!(JFFFJ)V", (void*) CanvasJNI::drawCircle},
- {"native_drawOval","!(JFFFFJ)V", (void*) CanvasJNI::drawOval},
- {"native_drawArc","!(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
- {"native_drawPath","!(JJJ)V", (void*) CanvasJNI::drawPath},
- {"nativeDrawVertices", "!(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
- {"native_drawNinePatch", "!(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
+ {"freeCaches", "()V", (void*) CanvasJNI::freeCaches},
+ {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches},
{"native_drawBitmap","(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
- {"nativeDrawBitmapMatrix", "!(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
{"native_drawBitmap","(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
{"native_drawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
- {"nativeDrawBitmapMesh", "!(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
- {"native_drawText","!(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
- {"native_drawText","!(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
- {"native_drawTextRun","!(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
- {"native_drawTextRun","!(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
- {"native_drawTextOnPath","!(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
- {"native_drawTextOnPath","!(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
- {"nativeSetDrawFilter", "!(JJ)V", (void*) CanvasJNI::setDrawFilter},
- {"freeCaches", "()V", (void*) CanvasJNI::freeCaches},
- {"freeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches}
+
+ // ------------ @FastNative ----------------
+ {"native_setBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
+ {"native_isOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
+ {"native_getWidth","(J)I", (void*) CanvasJNI::getWidth},
+ {"native_getHeight","(J)I", (void*) CanvasJNI::getHeight},
+ {"native_setHighContrastText","(JZ)V", (void*) CanvasJNI::setHighContrastText},
+ {"native_save","(JI)I", (void*) CanvasJNI::save},
+ {"native_saveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
+ {"native_saveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
+ {"native_getSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
+ {"native_restore","(JZ)V", (void*) CanvasJNI::restore},
+ {"native_restoreToCount","(JIZ)V", (void*) CanvasJNI::restoreToCount},
+ {"native_getCTM", "(JJ)V", (void*)CanvasJNI::getCTM},
+ {"native_setMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
+ {"native_concat","(JJ)V", (void*) CanvasJNI::concat},
+ {"native_rotate","(JF)V", (void*) CanvasJNI::rotate},
+ {"native_scale","(JFF)V", (void*) CanvasJNI::scale},
+ {"native_skew","(JFF)V", (void*) CanvasJNI::skew},
+ {"native_translate","(JFF)V", (void*) CanvasJNI::translate},
+ {"native_getClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
+ {"native_quickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
+ {"native_quickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
+ {"native_clipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
+ {"native_clipPath","(JJI)Z", (void*) CanvasJNI::clipPath},
+ {"native_clipRegion","(JJI)Z", (void*) CanvasJNI::clipRegion},
+ {"native_drawColor","(JII)V", (void*) CanvasJNI::drawColor},
+ {"native_drawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
+ {"native_drawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
+ {"native_drawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
+ {"native_drawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
+ {"native_drawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
+ {"native_drawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
+ {"native_drawRegion", "(JJJ)V", (void*) CanvasJNI::drawRegion },
+ {"native_drawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
+ {"native_drawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
+ {"native_drawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
+ {"native_drawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
+ {"native_drawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
+ {"nativeDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
+ {"native_drawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
+ {"nativeDrawBitmapMatrix", "(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
+ {"nativeDrawBitmapMesh", "(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
+ {"native_drawText","(J[CIIFFIJJ)V", (void*) CanvasJNI::drawTextChars},
+ {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) CanvasJNI::drawTextString},
+ {"native_drawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
+ {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunString},
+ {"native_drawTextOnPath","(J[CIIJFFIJJ)V", (void*) CanvasJNI::drawTextOnPathChars},
+ {"native_drawTextOnPath","(JLjava/lang/String;JFFIJJ)V", (void*) CanvasJNI::drawTextOnPathString},
+ {"nativeSetDrawFilter", "(JJ)V", (void*) CanvasJNI::setDrawFilter},
};
int register_android_graphics_Canvas(JNIEnv* env) {
diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
index ade718b..99a5fc7 100644
--- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
@@ -188,17 +188,20 @@
{"nCreateAnimatorSet", "()J", (void*)createAnimatorSet},
{"nSetVectorDrawableTarget", "(JJ)V", (void*)setVectorDrawableTarget},
{"nAddAnimator", "(JJJJJII)V", (void*)addAnimator},
- {"nCreateGroupPropertyHolder", "!(JIFF)J", (void*)createGroupPropertyHolder},
- {"nCreatePathDataPropertyHolder", "!(JJJ)J", (void*)createPathDataPropertyHolder},
- {"nCreatePathColorPropertyHolder", "!(JIII)J", (void*)createPathColorPropertyHolder},
- {"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder},
- {"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder},
{"nSetPropertyHolderData", "(J[FI)V", (void*)setFloatPropertyHolderData},
{"nSetPropertyHolderData", "(J[II)V", (void*)setIntPropertyHolderData},
{"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)start},
{"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)reverse},
- {"nEnd", "!(J)V", (void*)end},
- {"nReset", "!(J)V", (void*)reset},
+
+ // ------------- @FastNative -------------------
+
+ {"nCreateGroupPropertyHolder", "(JIFF)J", (void*)createGroupPropertyHolder},
+ {"nCreatePathDataPropertyHolder", "(JJJ)J", (void*)createPathDataPropertyHolder},
+ {"nCreatePathColorPropertyHolder", "(JIII)J", (void*)createPathColorPropertyHolder},
+ {"nCreatePathPropertyHolder", "(JIFF)J", (void*)createPathPropertyHolder},
+ {"nCreateRootAlphaPropertyHolder", "(JFF)J", (void*)createRootAlphaPropertyHolder},
+ {"nEnd", "(J)V", (void*)end},
+ {"nReset", "(J)V", (void*)reset},
};
const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT";
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 045f127..e9ea702 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -350,64 +350,66 @@
}
static const JNINativeMethod gMethods[] = {
- {"nCreateTree", "!(J)J", (void*)createTree},
- {"nCreateTreeFromCopy", "!(JJ)J", (void*)createTreeFromCopy},
- {"nSetRendererViewportSize", "!(JFF)V", (void*)setTreeViewportSize},
- {"nSetRootAlpha", "!(JF)Z", (void*)setRootAlpha},
- {"nGetRootAlpha", "!(J)F", (void*)getRootAlpha},
- {"nSetAllowCaching", "!(JZ)V", (void*)setAllowCaching},
-
{"nDraw", "(JJJLandroid/graphics/Rect;ZZ)I", (void*)draw},
- {"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
- {"nCreateFullPath", "!(J)J", (void*)createFullPath},
- {"nUpdateFullPathProperties", "!(JFIFIFFFFFIII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
- {"nUpdateFullPathFillGradient", "!(JJ)V", (void*)updateFullPathFillGradient},
- {"nUpdateFullPathStrokeGradient", "!(JJ)V", (void*)updateFullPathStrokeGradient},
{"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
{"nGetGroupProperties", "(J[FI)Z", (void*)getGroupProperties},
-
- {"nCreateClipPath", "!()J", (void*)createEmptyClipPath},
- {"nCreateClipPath", "!(J)J", (void*)createClipPath},
- {"nCreateGroup", "!()J", (void*)createEmptyGroup},
- {"nCreateGroup", "!(J)J", (void*)createGroup},
- {"nSetName", "(JLjava/lang/String;)V", (void*)setNodeName},
- {"nUpdateGroupProperties", "!(JFFFFFFF)V", (void*)updateGroupProperties},
-
- {"nAddChild", "!(JJ)V", (void*)addChild},
{"nSetPathString", "(JLjava/lang/String;I)V", (void*)setPathString},
+ {"nSetName", "(JLjava/lang/String;)V", (void*)setNodeName},
- {"nGetRotation", "!(J)F", (void*)getRotation},
- {"nSetRotation", "!(JF)V", (void*)setRotation},
- {"nGetPivotX", "!(J)F", (void*)getPivotX},
- {"nSetPivotX", "!(JF)V", (void*)setPivotX},
- {"nGetPivotY", "!(J)F", (void*)getPivotY},
- {"nSetPivotY", "!(JF)V", (void*)setPivotY},
- {"nGetScaleX", "!(J)F", (void*)getScaleX},
- {"nSetScaleX", "!(JF)V", (void*)setScaleX},
- {"nGetScaleY", "!(J)F", (void*)getScaleY},
- {"nSetScaleY", "!(JF)V", (void*)setScaleY},
- {"nGetTranslateX", "!(J)F", (void*)getTranslateX},
- {"nSetTranslateX", "!(JF)V", (void*)setTranslateX},
- {"nGetTranslateY", "!(J)F", (void*)getTranslateY},
- {"nSetTranslateY", "!(JF)V", (void*)setTranslateY},
+ // ------------- @FastNative ----------------
- {"nSetPathData", "!(JJ)V", (void*)setPathData},
- {"nGetStrokeWidth", "!(J)F", (void*)getStrokeWidth},
- {"nSetStrokeWidth", "!(JF)V", (void*)setStrokeWidth},
- {"nGetStrokeColor", "!(J)I", (void*)getStrokeColor},
- {"nSetStrokeColor", "!(JI)V", (void*)setStrokeColor},
- {"nGetStrokeAlpha", "!(J)F", (void*)getStrokeAlpha},
- {"nSetStrokeAlpha", "!(JF)V", (void*)setStrokeAlpha},
- {"nGetFillColor", "!(J)I", (void*)getFillColor},
- {"nSetFillColor", "!(JI)V", (void*)setFillColor},
- {"nGetFillAlpha", "!(J)F", (void*)getFillAlpha},
- {"nSetFillAlpha", "!(JF)V", (void*)setFillAlpha},
- {"nGetTrimPathStart", "!(J)F", (void*)getTrimPathStart},
- {"nSetTrimPathStart", "!(JF)V", (void*)setTrimPathStart},
- {"nGetTrimPathEnd", "!(J)F", (void*)getTrimPathEnd},
- {"nSetTrimPathEnd", "!(JF)V", (void*)setTrimPathEnd},
- {"nGetTrimPathOffset", "!(J)F", (void*)getTrimPathOffset},
- {"nSetTrimPathOffset", "!(JF)V", (void*)setTrimPathOffset},
+ {"nCreateTree", "(J)J", (void*)createTree},
+ {"nCreateTreeFromCopy", "(JJ)J", (void*)createTreeFromCopy},
+ {"nSetRendererViewportSize", "(JFF)V", (void*)setTreeViewportSize},
+ {"nSetRootAlpha", "(JF)Z", (void*)setRootAlpha},
+ {"nGetRootAlpha", "(J)F", (void*)getRootAlpha},
+ {"nSetAllowCaching", "(JZ)V", (void*)setAllowCaching},
+
+ {"nCreateFullPath", "()J", (void*)createEmptyFullPath},
+ {"nCreateFullPath", "(J)J", (void*)createFullPath},
+ {"nUpdateFullPathProperties", "(JFIFIFFFFFIII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
+ {"nUpdateFullPathFillGradient", "(JJ)V", (void*)updateFullPathFillGradient},
+ {"nUpdateFullPathStrokeGradient", "(JJ)V", (void*)updateFullPathStrokeGradient},
+
+ {"nCreateClipPath", "()J", (void*)createEmptyClipPath},
+ {"nCreateClipPath", "(J)J", (void*)createClipPath},
+ {"nCreateGroup", "()J", (void*)createEmptyGroup},
+ {"nCreateGroup", "(J)J", (void*)createGroup},
+ {"nUpdateGroupProperties", "(JFFFFFFF)V", (void*)updateGroupProperties},
+
+ {"nAddChild", "(JJ)V", (void*)addChild},
+ {"nGetRotation", "(J)F", (void*)getRotation},
+ {"nSetRotation", "(JF)V", (void*)setRotation},
+ {"nGetPivotX", "(J)F", (void*)getPivotX},
+ {"nSetPivotX", "(JF)V", (void*)setPivotX},
+ {"nGetPivotY", "(J)F", (void*)getPivotY},
+ {"nSetPivotY", "(JF)V", (void*)setPivotY},
+ {"nGetScaleX", "(J)F", (void*)getScaleX},
+ {"nSetScaleX", "(JF)V", (void*)setScaleX},
+ {"nGetScaleY", "(J)F", (void*)getScaleY},
+ {"nSetScaleY", "(JF)V", (void*)setScaleY},
+ {"nGetTranslateX", "(J)F", (void*)getTranslateX},
+ {"nSetTranslateX", "(JF)V", (void*)setTranslateX},
+ {"nGetTranslateY", "(J)F", (void*)getTranslateY},
+ {"nSetTranslateY", "(JF)V", (void*)setTranslateY},
+
+ {"nSetPathData", "(JJ)V", (void*)setPathData},
+ {"nGetStrokeWidth", "(J)F", (void*)getStrokeWidth},
+ {"nSetStrokeWidth", "(JF)V", (void*)setStrokeWidth},
+ {"nGetStrokeColor", "(J)I", (void*)getStrokeColor},
+ {"nSetStrokeColor", "(JI)V", (void*)setStrokeColor},
+ {"nGetStrokeAlpha", "(J)F", (void*)getStrokeAlpha},
+ {"nSetStrokeAlpha", "(JF)V", (void*)setStrokeAlpha},
+ {"nGetFillColor", "(J)I", (void*)getFillColor},
+ {"nSetFillColor", "(JI)V", (void*)setFillColor},
+ {"nGetFillAlpha", "(J)F", (void*)getFillAlpha},
+ {"nSetFillAlpha", "(JF)V", (void*)setFillAlpha},
+ {"nGetTrimPathStart", "(J)F", (void*)getTrimPathStart},
+ {"nSetTrimPathStart", "(JF)V", (void*)setTrimPathStart},
+ {"nGetTrimPathEnd", "(J)F", (void*)getTrimPathEnd},
+ {"nSetTrimPathEnd", "(JF)V", (void*)setTrimPathEnd},
+ {"nGetTrimPathOffset", "(J)F", (void*)getTrimPathOffset},
+ {"nSetTrimPathOffset", "(JF)V", (void*)setTrimPathOffset},
};
int register_android_graphics_drawable_VectorDrawable(JNIEnv* env) {
diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp
index 8eb39e1..fbccfd5 100644
--- a/core/jni/android_hardware_location_ContextHubService.cpp
+++ b/core/jni/android_hardware_location_ContextHubService.cpp
@@ -33,6 +33,7 @@
#include <unordered_map>
#include <queue>
+#include <android-base/macros.h>
#include <cutils/log.h>
#include "JNIHelp.h"
@@ -704,10 +705,10 @@
}
jbyteArray jmsg = env->NewByteArray(msgLen);
- jintArray jheader = env->NewIntArray(sizeof(header));
+ jintArray jheader = env->NewIntArray(arraysize(header));
env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
- env->SetIntArrayRegion(jheader, 0, sizeof(header), (jint *)header);
+ env->SetIntArrayRegion(jheader, 0, arraysize(header), (jint *)header);
ALOGI("Passing msg type %" PRIu32 " from app %" PRIu32 " from hub %" PRIu32,
header[HEADER_FIELD_MSG_TYPE], header[HEADER_FIELD_APP_INSTANCE],
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index e0bfecb..06f22dd 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -15,15 +15,7 @@
*/
#define LOG_TAG "android.os.Debug"
-#include "JNIHelp.h"
-#include "jni.h"
-#include <utils/String8.h>
-#include "utils/misc.h"
-#include "cutils/debugger.h"
-#include <memtrack/memtrack.h>
-#include <memunreachable/memunreachable.h>
-#include <cutils/log.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
@@ -40,9 +32,26 @@
#include <iomanip>
#include <string>
+#include "jni.h"
+
+#include "android-base/stringprintf.h"
+#include "cutils/debugger.h"
+#include "cutils/log.h"
+#include "JNIHelp.h"
+#include "memtrack/memtrack.h"
+#include "memunreachable/memunreachable.h"
+#include "utils/misc.h"
+#include "utils/String8.h"
+
namespace android
{
+using UniqueFile = std::unique_ptr<FILE, decltype(&fclose)>;
+
+static inline UniqueFile MakeUniqueFile(const char* path, const char* mode) {
+ return UniqueFile(fopen(path, mode), fclose);
+}
+
enum {
HEAP_UNKNOWN,
HEAP_DALVIK,
@@ -116,8 +125,6 @@
jfieldID otherStats_field;
jfieldID hasSwappedOutPss_field;
-static bool memtrackLoaded;
-
struct stats_t {
int pss;
int swappablePss;
@@ -199,10 +206,6 @@
*/
static int read_memtrack_memory(int pid, struct graphics_memory_pss* graphics_mem)
{
- if (!memtrackLoaded) {
- return -1;
- }
-
struct memtrack_proc* p = memtrack_proc_new();
if (p == NULL) {
ALOGW("failed to create memtrack_proc");
@@ -427,15 +430,13 @@
static void load_maps(int pid, stats_t* stats, bool* foundSwapPss)
{
- char tmp[128];
- FILE *fp;
+ *foundSwapPss = false;
- sprintf(tmp, "/proc/%d/smaps", pid);
- fp = fopen(tmp, "r");
- if (fp == 0) return;
+ std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid);
+ UniqueFile fp = MakeUniqueFile(smaps_path.c_str(), "re");
+ if (fp == nullptr) return;
- read_mapinfo(fp, stats, foundSwapPss);
- fclose(fp);
+ read_mapinfo(fp.get(), stats, foundSwapPss);
}
static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz,
@@ -517,51 +518,48 @@
jlong uss = 0;
jlong memtrack = 0;
- char tmp[128];
- FILE *fp;
-
struct graphics_memory_pss graphics_mem;
if (read_memtrack_memory(pid, &graphics_mem) == 0) {
pss = uss = memtrack = graphics_mem.graphics + graphics_mem.gl + graphics_mem.other;
}
- sprintf(tmp, "/proc/%d/smaps", pid);
- fp = fopen(tmp, "r");
+ {
+ std::string smaps_path = base::StringPrintf("/proc/%d/smaps", pid);
+ UniqueFile fp = MakeUniqueFile(smaps_path.c_str(), "re");
- if (fp != 0) {
- while (true) {
- if (fgets(line, 1024, fp) == NULL) {
- break;
- }
+ if (fp != nullptr) {
+ while (true) {
+ if (fgets(line, 1024, fp.get()) == NULL) {
+ break;
+ }
- if (line[0] == 'P') {
- if (strncmp(line, "Pss:", 4) == 0) {
- char* c = line + 4;
+ if (line[0] == 'P') {
+ if (strncmp(line, "Pss:", 4) == 0) {
+ char* c = line + 4;
+ while (*c != 0 && (*c < '0' || *c > '9')) {
+ c++;
+ }
+ pss += atoi(c);
+ } else if (strncmp(line, "Private_Clean:", 14) == 0
+ || strncmp(line, "Private_Dirty:", 14) == 0) {
+ char* c = line + 14;
+ while (*c != 0 && (*c < '0' || *c > '9')) {
+ c++;
+ }
+ uss += atoi(c);
+ }
+ } else if (line[0] == 'S' && strncmp(line, "SwapPss:", 8) == 0) {
+ char* c = line + 8;
+ jlong lSwapPss;
while (*c != 0 && (*c < '0' || *c > '9')) {
c++;
}
- pss += atoi(c);
- } else if (strncmp(line, "Private_Clean:", 14) == 0
- || strncmp(line, "Private_Dirty:", 14) == 0) {
- char* c = line + 14;
- while (*c != 0 && (*c < '0' || *c > '9')) {
- c++;
- }
- uss += atoi(c);
+ lSwapPss = atoi(c);
+ swapPss += lSwapPss;
+ pss += lSwapPss; // Also in swap, those pages would be accounted as Pss without SWAP
}
- } else if (line[0] == 'S' && strncmp(line, "SwapPss:", 8) == 0) {
- char* c = line + 8;
- jlong lSwapPss;
- while (*c != 0 && (*c < '0' || *c > '9')) {
- c++;
- }
- lSwapPss = atoi(c);
- swapPss += lSwapPss;
- pss += lSwapPss; // Also in swap, those pages would be accounted as Pss without SWAP
}
}
-
- fclose(fp);
}
if (outUssSwapPss != NULL) {
@@ -605,12 +603,14 @@
NULL
};
long size, vmalloc_allocated_size = 0;
- FILE* fp = fopen("/proc/vmallocinfo", "r");
- if (fp == NULL) {
+
+ UniqueFile fp = MakeUniqueFile("/proc/vmallocinfo", "re");
+ if (fp == nullptr) {
return 0;
}
+
while (true) {
- if (fgets(line, 1024, fp) == NULL) {
+ if (fgets(line, 1024, fp.get()) == NULL) {
break;
}
bool valid_line = true;
@@ -626,7 +626,6 @@
vmalloc_allocated_size += size;
}
}
- fclose(fp);
return vmalloc_allocated_size;
}
@@ -650,27 +649,25 @@
static long long get_zram_mem_used()
{
#define ZRAM_SYSFS "/sys/block/zram0/"
- FILE *f = fopen(ZRAM_SYSFS "mm_stat", "r");
- if (f) {
+ UniqueFile mm_stat_file = MakeUniqueFile(ZRAM_SYSFS "mm_stat", "re");
+ if (mm_stat_file) {
long long mem_used_total = 0;
- int matched = fscanf(f, "%*d %*d %lld %*d %*d %*d %*d", &mem_used_total);
+ int matched = fscanf(mm_stat_file.get(), "%*d %*d %lld %*d %*d %*d %*d", &mem_used_total);
if (matched != 1)
ALOGW("failed to parse " ZRAM_SYSFS "mm_stat");
- fclose(f);
return mem_used_total;
}
- f = fopen(ZRAM_SYSFS "mem_used_total", "r");
- if (f) {
+ UniqueFile mem_used_total_file = MakeUniqueFile(ZRAM_SYSFS "mem_used_total", "re");
+ if (mem_used_total_file) {
long long mem_used_total = 0;
- int matched = fscanf(f, "%lld", &mem_used_total);
+ int matched = fscanf(mem_used_total_file.get(), "%lld", &mem_used_total);
if (matched != 1)
ALOGW("failed to parse " ZRAM_SYSFS "mem_used_total");
- fclose(f);
return mem_used_total;
}
@@ -783,8 +780,8 @@
static jint read_binder_stat(const char* stat)
{
- FILE* fp = fopen(BINDER_STATS, "r");
- if (fp == NULL) {
+ UniqueFile fp = MakeUniqueFile(BINDER_STATS, "re");
+ if (fp == nullptr) {
return -1;
}
@@ -795,8 +792,7 @@
// loop until we have the block that represents this process
do {
- if (fgets(line, 1024, fp) == 0) {
- fclose(fp);
+ if (fgets(line, 1024, fp.get()) == 0) {
return -1;
}
} while (strncmp(compare, line, len));
@@ -805,8 +801,7 @@
len = snprintf(compare, 128, " %s: ", stat);
do {
- if (fgets(line, 1024, fp) == 0) {
- fclose(fp);
+ if (fgets(line, 1024, fp.get()) == 0) {
return -1;
}
} while (strncmp(compare, line, len));
@@ -814,7 +809,6 @@
// we have the line, now increment the line ptr to the value
char* ptr = line + len;
jint result = atoi(ptr);
- fclose(fp);
return result;
}
@@ -839,7 +833,8 @@
size_t* infoSize, size_t* totalMemory, size_t* backtraceSize);
extern "C" void free_malloc_leak_info(uint8_t* info);
#define SIZE_FLAG_ZYGOTE_CHILD (1<<31)
-#define BACKTRACE_SIZE 32
+
+static size_t gNumBacktraceElements;
/*
* This is a qsort() callback.
@@ -859,11 +854,11 @@
return -1;
}
- intptr_t* bt1 = (intptr_t*)(rec1 + 2);
- intptr_t* bt2 = (intptr_t*)(rec2 + 2);
- for (size_t idx = 0; idx < BACKTRACE_SIZE; idx++) {
- intptr_t addr1 = bt1[idx];
- intptr_t addr2 = bt2[idx];
+ uintptr_t* bt1 = (uintptr_t*)(rec1 + 2);
+ uintptr_t* bt2 = (uintptr_t*)(rec2 + 2);
+ for (size_t idx = 0; idx < gNumBacktraceElements; idx++) {
+ uintptr_t addr1 = bt1[idx];
+ uintptr_t addr2 = bt2[idx];
if (addr1 == addr2) {
if (addr1 == 0)
break;
@@ -907,9 +902,10 @@
if (info == NULL) {
fprintf(fp, "Native heap dump not available. To enable, run these"
" commands (requires root):\n");
- fprintf(fp, "$ adb shell setprop libc.debug.malloc 1\n");
- fprintf(fp, "$ adb shell stop\n");
- fprintf(fp, "$ adb shell start\n");
+ fprintf(fp, "# adb shell stop\n");
+ fprintf(fp, "# adb shell setprop libc.debug.malloc.options "
+ "backtrace\n");
+ fprintf(fp, "# adb shell start\n");
return;
}
assert(infoSize != 0);
@@ -920,13 +916,11 @@
size_t recordCount = overallSize / infoSize;
fprintf(fp, "Total memory: %zu\n", totalMemory);
fprintf(fp, "Allocation records: %zd\n", recordCount);
- if (backtraceSize != BACKTRACE_SIZE) {
- fprintf(fp, "WARNING: mismatched backtrace sizes (%zu vs. %d)\n",
- backtraceSize, BACKTRACE_SIZE);
- }
+ fprintf(fp, "Backtrace size: %zd\n", backtraceSize);
fprintf(fp, "\n");
/* re-sort the entries */
+ gNumBacktraceElements = backtraceSize;
qsort(info, recordCount, infoSize, compareHeapRecords);
/* dump the entries to the file */
@@ -934,7 +928,7 @@
for (size_t idx = 0; idx < recordCount; idx++) {
size_t size = *(size_t*) ptr;
size_t allocations = *(size_t*) (ptr + sizeof(size_t));
- intptr_t* backtrace = (intptr_t*) (ptr + sizeof(size_t) * 2);
+ uintptr_t* backtrace = (uintptr_t*) (ptr + sizeof(size_t) * 2);
fprintf(fp, "z %d sz %8zu num %4zu bt",
(size & SIZE_FLAG_ZYGOTE_CHILD) != 0,
@@ -960,16 +954,15 @@
fprintf(fp, "MAPS\n");
const char* maps = "/proc/self/maps";
- FILE* in = fopen(maps, "r");
- if (in == NULL) {
+ UniqueFile in = MakeUniqueFile(maps, "re");
+ if (in == nullptr) {
fprintf(fp, "Could not open %s\n", maps);
return;
}
char buf[BUFSIZ];
- while (size_t n = fread(buf, sizeof(char), BUFSIZ, in)) {
+ while (size_t n = fread(buf, sizeof(char), BUFSIZ, in.get())) {
fwrite(buf, sizeof(char), n, fp);
}
- fclose(in);
fprintf(fp, "END\n");
}
@@ -999,8 +992,8 @@
return;
}
- FILE* fp = fdopen(fd, "w");
- if (fp == NULL) {
+ UniqueFile fp(fdopen(fd, "w"), fclose);
+ if (fp == nullptr) {
ALOGW("fdopen(%d) failed: %s\n", fd, strerror(errno));
close(fd);
jniThrowRuntimeException(env, "fdopen() failed");
@@ -1008,10 +1001,8 @@
}
ALOGD("Native heap dump starting...\n");
- dumpNativeHeap(fp);
+ dumpNativeHeap(fp.get());
ALOGD("Native heap dump complete.\n");
-
- fclose(fp);
}
@@ -1093,14 +1084,6 @@
int register_android_os_Debug(JNIEnv *env)
{
- int err = memtrack_init();
- if (err != 0) {
- memtrackLoaded = false;
- ALOGE("failed to load memtrack module: %d", err);
- } else {
- memtrackLoaded = true;
- }
-
jclass clazz = env->FindClass("android/os/Debug$MemoryInfo");
// Sanity check the number of other statistics expected in Java matches here.
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 7da0314..13e3f0d 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -266,6 +266,9 @@
return NULL;
}
+ LOG(INFO) << "Starting thread pool.";
+ ::android::hardware::ProcessState::self()->startThreadPool();
+
return JHwRemoteBinder::NewObject(env, service);
}
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index 0a8ae2b..8f7908a 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -722,33 +722,50 @@
// ----------------------------------------------------------------------------
static const JNINativeMethod gParcelMethods[] = {
- {"nativeDataSize", "!(J)I", (void*)android_os_Parcel_dataSize},
- {"nativeDataAvail", "!(J)I", (void*)android_os_Parcel_dataAvail},
- {"nativeDataPosition", "!(J)I", (void*)android_os_Parcel_dataPosition},
- {"nativeDataCapacity", "!(J)I", (void*)android_os_Parcel_dataCapacity},
- {"nativeSetDataSize", "!(JI)J", (void*)android_os_Parcel_setDataSize},
- {"nativeSetDataPosition", "!(JI)V", (void*)android_os_Parcel_setDataPosition},
- {"nativeSetDataCapacity", "!(JI)V", (void*)android_os_Parcel_setDataCapacity},
+ // @FastNative
+ {"nativeDataSize", "(J)I", (void*)android_os_Parcel_dataSize},
+ // @FastNative
+ {"nativeDataAvail", "(J)I", (void*)android_os_Parcel_dataAvail},
+ // @FastNative
+ {"nativeDataPosition", "(J)I", (void*)android_os_Parcel_dataPosition},
+ // @FastNative
+ {"nativeDataCapacity", "(J)I", (void*)android_os_Parcel_dataCapacity},
+ // @FastNative
+ {"nativeSetDataSize", "(JI)J", (void*)android_os_Parcel_setDataSize},
+ // @FastNative
+ {"nativeSetDataPosition", "(JI)V", (void*)android_os_Parcel_setDataPosition},
+ // @FastNative
+ {"nativeSetDataCapacity", "(JI)V", (void*)android_os_Parcel_setDataCapacity},
- {"nativePushAllowFds", "!(JZ)Z", (void*)android_os_Parcel_pushAllowFds},
- {"nativeRestoreAllowFds", "!(JZ)V", (void*)android_os_Parcel_restoreAllowFds},
+ // @FastNative
+ {"nativePushAllowFds", "(JZ)Z", (void*)android_os_Parcel_pushAllowFds},
+ // @FastNative
+ {"nativeRestoreAllowFds", "(JZ)V", (void*)android_os_Parcel_restoreAllowFds},
{"nativeWriteByteArray", "(J[BII)V", (void*)android_os_Parcel_writeNative},
{"nativeWriteBlob", "(J[BII)V", (void*)android_os_Parcel_writeBlob},
- {"nativeWriteInt", "!(JI)V", (void*)android_os_Parcel_writeInt},
- {"nativeWriteLong", "!(JJ)V", (void*)android_os_Parcel_writeLong},
- {"nativeWriteFloat", "!(JF)V", (void*)android_os_Parcel_writeFloat},
- {"nativeWriteDouble", "!(JD)V", (void*)android_os_Parcel_writeDouble},
+ // @FastNative
+ {"nativeWriteInt", "(JI)V", (void*)android_os_Parcel_writeInt},
+ // @FastNative
+ {"nativeWriteLong", "(JJ)V", (void*)android_os_Parcel_writeLong},
+ // @FastNative
+ {"nativeWriteFloat", "(JF)V", (void*)android_os_Parcel_writeFloat},
+ // @FastNative
+ {"nativeWriteDouble", "(JD)V", (void*)android_os_Parcel_writeDouble},
{"nativeWriteString", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString},
{"nativeWriteStrongBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
{"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)J", (void*)android_os_Parcel_writeFileDescriptor},
{"nativeCreateByteArray", "(J)[B", (void*)android_os_Parcel_createByteArray},
{"nativeReadBlob", "(J)[B", (void*)android_os_Parcel_readBlob},
- {"nativeReadInt", "!(J)I", (void*)android_os_Parcel_readInt},
- {"nativeReadLong", "!(J)J", (void*)android_os_Parcel_readLong},
- {"nativeReadFloat", "!(J)F", (void*)android_os_Parcel_readFloat},
- {"nativeReadDouble", "!(J)D", (void*)android_os_Parcel_readDouble},
+ // @FastNative
+ {"nativeReadInt", "(J)I", (void*)android_os_Parcel_readInt},
+ // @FastNative
+ {"nativeReadLong", "(J)J", (void*)android_os_Parcel_readLong},
+ // @FastNative
+ {"nativeReadFloat", "(J)F", (void*)android_os_Parcel_readFloat},
+ // @FastNative
+ {"nativeReadDouble", "(J)D", (void*)android_os_Parcel_readDouble},
{"nativeReadString", "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString},
{"nativeReadStrongBinder", "(J)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder},
{"nativeReadFileDescriptor", "(J)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
@@ -765,7 +782,8 @@
{"nativeMarshall", "(J)[B", (void*)android_os_Parcel_marshall},
{"nativeUnmarshall", "(J[BII)J", (void*)android_os_Parcel_unmarshall},
{"nativeAppendFrom", "(JJII)J", (void*)android_os_Parcel_appendFrom},
- {"nativeHasFileDescriptors", "!(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
+ // @FastNative
+ {"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
{"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
{"nativeEnforceInterface", "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp
index ccb833a..2fade69 100644
--- a/core/jni/android_os_SystemClock.cpp
+++ b/core/jni/android_os_SystemClock.cpp
@@ -36,29 +36,18 @@
namespace android {
-/*
- * native public static long uptimeMillis();
- */
-static jlong android_os_SystemClock_uptimeMillis(JNIEnv* env,
- jobject clazz)
-{
- return (jlong)uptimeMillis();
-}
-
-/*
- * native public static long elapsedRealtime();
- */
-static jlong android_os_SystemClock_elapsedRealtime(JNIEnv* env,
- jobject clazz)
-{
- return (jlong)elapsedRealtime();
-}
+static_assert(std::is_same<int64_t, jlong>::value, "jlong isn't an int64_t");
+static_assert(std::is_same<decltype(uptimeMillis()), int64_t>::value,
+ "uptimeMillis signature change, expected int64_t return value");
+static_assert(std::is_same<decltype(elapsedRealtime()), int64_t>::value,
+ "uptimeMillis signature change, expected int64_t return value");
+static_assert(std::is_same<decltype(elapsedRealtimeNano()), int64_t>::value,
+ "uptimeMillis signature change, expected int64_t return value");
/*
* native public static long currentThreadTimeMillis();
*/
-static jlong android_os_SystemClock_currentThreadTimeMillis(JNIEnv* env,
- jobject clazz)
+static jlong android_os_SystemClock_currentThreadTimeMillis()
{
struct timespec tm;
@@ -70,8 +59,7 @@
/*
* native public static long currentThreadTimeMicro();
*/
-static jlong android_os_SystemClock_currentThreadTimeMicro(JNIEnv* env,
- jobject clazz)
+static jlong android_os_SystemClock_currentThreadTimeMicro()
{
struct timespec tm;
@@ -83,8 +71,7 @@
/*
* native public static long currentTimeMicro();
*/
-static jlong android_os_SystemClock_currentTimeMicro(JNIEnv* env,
- jobject clazz)
+static jlong android_os_SystemClock_currentTimeMicro()
{
struct timeval tv;
@@ -93,31 +80,22 @@
}
/*
- * public static native long elapsedRealtimeNano();
- */
-static jlong android_os_SystemClock_elapsedRealtimeNano(JNIEnv* env,
- jobject clazz)
-{
- return (jlong)elapsedRealtimeNano();
-}
-
-/*
* JNI registration.
*/
static const JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "uptimeMillis", "!()J",
- (void*) android_os_SystemClock_uptimeMillis },
- { "elapsedRealtime", "!()J",
- (void*) android_os_SystemClock_elapsedRealtime },
- { "currentThreadTimeMillis", "!()J",
+ // All of these are @CriticalNative, so we can defer directly to SystemClock.h for
+ // some of these
+ { "uptimeMillis", "()J", (void*) uptimeMillis },
+ { "elapsedRealtime", "()J", (void*) elapsedRealtime },
+ { "elapsedRealtimeNanos", "()J", (void*) elapsedRealtimeNano },
+
+ // SystemClock doesn't have an implementation for these that we can directly call
+ { "currentThreadTimeMillis", "()J",
(void*) android_os_SystemClock_currentThreadTimeMillis },
- { "currentThreadTimeMicro", "!()J",
+ { "currentThreadTimeMicro", "()J",
(void*) android_os_SystemClock_currentThreadTimeMicro },
- { "currentTimeMicro", "!()J",
+ { "currentTimeMicro", "()J",
(void*) android_os_SystemClock_currentTimeMicro },
- { "elapsedRealtimeNanos", "!()J",
- (void*) android_os_SystemClock_elapsedRealtimeNano },
};
int register_android_os_SystemClock(JNIEnv* env)
{
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 30fc47b..ea893f0 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -110,27 +110,30 @@
{ "nativeGetEnabledTags",
"()J",
(void*)android_os_Trace_nativeGetEnabledTags },
- { "nativeTraceCounter",
- "!(JLjava/lang/String;I)V",
- (void*)android_os_Trace_nativeTraceCounter },
- { "nativeTraceBegin",
- "!(JLjava/lang/String;)V",
- (void*)android_os_Trace_nativeTraceBegin },
- { "nativeTraceEnd",
- "!(J)V",
- (void*)android_os_Trace_nativeTraceEnd },
- { "nativeAsyncTraceBegin",
- "!(JLjava/lang/String;I)V",
- (void*)android_os_Trace_nativeAsyncTraceBegin },
- { "nativeAsyncTraceEnd",
- "!(JLjava/lang/String;I)V",
- (void*)android_os_Trace_nativeAsyncTraceEnd },
{ "nativeSetAppTracingAllowed",
"(Z)V",
(void*)android_os_Trace_nativeSetAppTracingAllowed },
{ "nativeSetTracingEnabled",
"(Z)V",
(void*)android_os_Trace_nativeSetTracingEnabled },
+
+ // ----------- @FastNative ----------------
+
+ { "nativeTraceCounter",
+ "(JLjava/lang/String;I)V",
+ (void*)android_os_Trace_nativeTraceCounter },
+ { "nativeTraceBegin",
+ "(JLjava/lang/String;)V",
+ (void*)android_os_Trace_nativeTraceBegin },
+ { "nativeTraceEnd",
+ "(J)V",
+ (void*)android_os_Trace_nativeTraceEnd },
+ { "nativeAsyncTraceBegin",
+ "(JLjava/lang/String;I)V",
+ (void*)android_os_Trace_nativeAsyncTraceBegin },
+ { "nativeAsyncTraceEnd",
+ "(JLjava/lang/String;I)V",
+ (void*)android_os_Trace_nativeAsyncTraceEnd },
};
int register_android_os_Trace(JNIEnv* env) {
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index c4c1511..5a4348e 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -31,7 +31,7 @@
#include "androidfw/Asset.h"
#include "androidfw/AssetManager.h"
-#include "androidfw/AttributeFinder.h"
+#include "androidfw/AttributeResolution.h"
#include "androidfw/ResourceTypes.h"
#include "android_runtime/AndroidRuntime.h"
#include "android_util_Binder.h"
@@ -51,7 +51,6 @@
namespace android {
static const bool kThrowOnBadId = false;
-static const bool kDebugStyles = false;
// ----------------------------------------------------------------------------
@@ -186,18 +185,19 @@
argv[argc++] = AssetManager::TARGET_APK_PATH;
argv[argc++] = AssetManager::IDMAP_DIR;
- // Directories to scan for overlays: if OVERLAY_SUBDIR_PROPERTY is defined,
- // use OVERLAY_SUBDIR/<value of OVERLAY_SUBDIR_PROPERTY>/ if exists, otherwise
+ // Directories to scan for overlays: if OVERLAY_SKU_DIR_PROPERTY is defined,
+ // use OVERLAY_DIR/<value of OVERLAY_SKU_DIR_PROPERTY> if exists, otherwise
// use OVERLAY_DIR if exists.
char subdir[PROP_VALUE_MAX];
- int len = __system_property_get(AssetManager::OVERLAY_SUBDIR_PROPERTY, subdir);
+ int len = __system_property_get(AssetManager::OVERLAY_SKU_DIR_PROPERTY, subdir);
+ String8 overlayPath;
if (len > 0) {
- String8 subdirPath = String8(AssetManager::OVERLAY_SUBDIR) + "/" + subdir;
- if (stat(subdirPath.string(), &st) == 0) {
- argv[argc++] = subdirPath.string();
- }
- } else if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
- argv[argc++] = AssetManager::OVERLAY_DIR;
+ overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
+ } else {
+ overlayPath = String8(AssetManager::OVERLAY_DIR);
+ }
+ if (stat(overlayPath.string(), &st) == 0) {
+ argv[argc++] = overlayPath.string();
}
// Finally, invoke idmap (if any overlay directory exists)
@@ -1120,30 +1120,6 @@
theme->dumpToLog();
}
-class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, jsize> {
-public:
- explicit XmlAttributeFinder(const ResXMLParser* parser)
- : BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0)
- , mParser(parser) {}
-
- inline uint32_t getAttribute(jsize index) const {
- return mParser->getAttributeNameResID(index);
- }
-
-private:
- const ResXMLParser* mParser;
-};
-
-class BagAttributeFinder : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
-public:
- BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end)
- : BackTrackingAttributeFinder(start, end) {}
-
- inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
- return entry->map.name.ident;
- }
-};
-
static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
jlong themeToken,
jint defStyleAttr,
@@ -1166,16 +1142,6 @@
return JNI_FALSE;
}
- if (kDebugStyles) {
- ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x "
- "defStyleRes=0x%x", themeToken, defStyleAttr, defStyleRes);
- }
-
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
- const ResTable& res = theme->getResTable();
- ResTable_config config;
- Res_value value;
-
const jsize NI = env->GetArrayLength(attrs);
const jsize NV = env->GetArrayLength(outValues);
if (NV < (NI*STYLE_NUM_ENTRIES)) {
@@ -1192,159 +1158,32 @@
const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
- jint* dest = baseDest;
- if (dest == NULL) {
+ if (baseDest == NULL) {
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
return JNI_FALSE;
}
jint* indices = NULL;
- int indicesIdx = 0;
if (outIndices != NULL) {
if (env->GetArrayLength(outIndices) > NI) {
indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
}
}
- // Load default style from attribute, if specified...
- uint32_t defStyleBagTypeSetFlags = 0;
- if (defStyleAttr != 0) {
- Res_value value;
- if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- defStyleRes = value.data;
- }
- }
- }
-
- // Now lock down the resource object and start pulling stuff from it.
- res.lock();
-
- // Retrieve the default style bag, if requested.
- const ResTable::bag_entry* defStyleStart = NULL;
- uint32_t defStyleTypeSetFlags = 0;
- ssize_t bagOff = defStyleRes != 0
- ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
- defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
- const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
- BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
-
- // Now iterate through all of the attributes that the client has requested,
- // filling in each with whatever data we can find.
- ssize_t block = 0;
- uint32_t typeSetFlags;
- for (jsize ii=0; ii<NI; ii++) {
- const uint32_t curIdent = (uint32_t)src[ii];
-
- if (kDebugStyles) {
- ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
- }
-
- // Try to find a value for this attribute... we prioritize values
- // coming from, first XML attributes, then XML style, then default
- // style, and finally the theme.
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- typeSetFlags = 0;
- config.density = 0;
-
- // Retrieve the current input value if available.
- if (NSV > 0 && srcValues[ii] != 0) {
- block = -1;
- value.dataType = Res_value::TYPE_ATTRIBUTE;
- value.data = srcValues[ii];
- if (kDebugStyles) {
- ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
-
- if (value.dataType == Res_value::TYPE_NULL) {
- const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
- if (defStyleEntry != defStyleEnd) {
- block = defStyleEntry->stringBlock;
- typeSetFlags = defStyleTypeSetFlags;
- value = defStyleEntry->map.value;
- if (kDebugStyles) {
- ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
- }
-
- uint32_t resid = 0;
- if (value.dataType != Res_value::TYPE_NULL) {
- // Take care of resolving the found resource to its final value.
- ssize_t newBlock = theme->resolveAttributeReference(&value, block,
- &resid, &typeSetFlags, &config);
- if (newBlock >= 0) block = newBlock;
- if (kDebugStyles) {
- ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- } else {
- // If we still don't have a value for this attribute, try to find
- // it in the theme!
- ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
- if (newBlock >= 0) {
- if (kDebugStyles) {
- ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- newBlock = res.resolveReference(&value, block, &resid,
- &typeSetFlags, &config);
- if (kThrowOnBadId) {
- if (newBlock == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return JNI_FALSE;
- }
- }
- if (newBlock >= 0) block = newBlock;
- if (kDebugStyles) {
- ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
- }
-
- // Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- if (kDebugStyles) {
- ALOGI("-> Setting to @null!");
- }
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- block = -1;
- }
-
- if (kDebugStyles) {
- ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
- value.data);
- }
-
- // Write the final value back to Java.
- dest[STYLE_TYPE] = value.dataType;
- dest[STYLE_DATA] = value.data;
- dest[STYLE_ASSET_COOKIE] =
- block != -1 ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
- dest[STYLE_RESOURCE_ID] = resid;
- dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
- dest[STYLE_DENSITY] = config.density;
-
- if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
- indicesIdx++;
- indices[indicesIdx] = ii;
- }
-
- dest += STYLE_NUM_ENTRIES;
- }
-
- res.unlock();
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+ bool result = resolveAttrs(theme, defStyleAttr, defStyleRes,
+ (uint32_t*) srcValues, NSV,
+ (uint32_t*) src, NI,
+ (uint32_t*) baseDest,
+ (uint32_t*) indices);
if (indices != NULL) {
- indices[0] = indicesIdx;
env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
}
env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-
- return JNI_TRUE;
+ return result ? JNI_TRUE : JNI_FALSE;
}
static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
@@ -1369,18 +1208,6 @@
return JNI_FALSE;
}
- if (kDebugStyles) {
- ALOGI("APPLY STYLE: theme=0x%" PRIx64 " defStyleAttr=0x%x defStyleRes=0x%x "
- "xml=0x%" PRIx64, themeToken, defStyleAttr, defStyleRes,
- xmlParserToken);
- }
-
- ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
- const ResTable& res = theme->getResTable();
- ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
- ResTable_config config;
- Res_value value;
-
const jsize NI = env->GetArrayLength(attrs);
const jsize NV = env->GetArrayLength(outValues);
if (NV < (NI*STYLE_NUM_ENTRIES)) {
@@ -1394,211 +1221,32 @@
}
jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
- jint* dest = baseDest;
- if (dest == NULL) {
+ if (baseDest == NULL) {
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
return JNI_FALSE;
}
jint* indices = NULL;
- int indicesIdx = 0;
if (outIndices != NULL) {
if (env->GetArrayLength(outIndices) > NI) {
indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
}
}
- // Load default style from attribute, if specified...
- uint32_t defStyleBagTypeSetFlags = 0;
- if (defStyleAttr != 0) {
- Res_value value;
- if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- defStyleRes = value.data;
- }
- }
- }
-
- // Retrieve the style class associated with the current XML tag.
- int style = 0;
- uint32_t styleBagTypeSetFlags = 0;
- if (xmlParser != NULL) {
- ssize_t idx = xmlParser->indexOfStyle();
- if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
- if (value.dataType == value.TYPE_ATTRIBUTE) {
- if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
- value.dataType = Res_value::TYPE_NULL;
- }
- }
- if (value.dataType == value.TYPE_REFERENCE) {
- style = value.data;
- }
- }
- }
-
- // Now lock down the resource object and start pulling stuff from it.
- res.lock();
-
- // Retrieve the default style bag, if requested.
- const ResTable::bag_entry* defStyleAttrStart = NULL;
- uint32_t defStyleTypeSetFlags = 0;
- ssize_t bagOff = defStyleRes != 0
- ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
- defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
- const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
- BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
-
- // Retrieve the style class bag, if requested.
- const ResTable::bag_entry* styleAttrStart = NULL;
- uint32_t styleTypeSetFlags = 0;
- bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
- styleTypeSetFlags |= styleBagTypeSetFlags;
- const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
- BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
-
- // Retrieve the XML attributes, if requested.
- static const ssize_t kXmlBlock = 0x10000000;
- XmlAttributeFinder xmlAttrFinder(xmlParser);
- const jsize xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0;
-
- // Now iterate through all of the attributes that the client has requested,
- // filling in each with whatever data we can find.
- ssize_t block = 0;
- uint32_t typeSetFlags;
- for (jsize ii = 0; ii < NI; ii++) {
- const uint32_t curIdent = (uint32_t)src[ii];
-
- if (kDebugStyles) {
- ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
- }
-
- // Try to find a value for this attribute... we prioritize values
- // coming from, first XML attributes, then XML style, then default
- // style, and finally the theme.
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- typeSetFlags = 0;
- config.density = 0;
-
- // Walk through the xml attributes looking for the requested attribute.
- const jsize xmlAttrIdx = xmlAttrFinder.find(curIdent);
- if (xmlAttrIdx != xmlAttrEnd) {
- // We found the attribute we were looking for.
- block = kXmlBlock;
- xmlParser->getAttributeValue(xmlAttrIdx, &value);
- if (kDebugStyles) {
- ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
-
- if (value.dataType == Res_value::TYPE_NULL) {
- // Walk through the style class values looking for the requested attribute.
- const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
- if (styleAttrEntry != styleAttrEnd) {
- // We found the attribute we were looking for.
- block = styleAttrEntry->stringBlock;
- typeSetFlags = styleTypeSetFlags;
- value = styleAttrEntry->map.value;
- if (kDebugStyles) {
- ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
- }
-
- if (value.dataType == Res_value::TYPE_NULL) {
- // Walk through the default style values looking for the requested attribute.
- const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
- if (defStyleAttrEntry != defStyleAttrEnd) {
- // We found the attribute we were looking for.
- block = defStyleAttrEntry->stringBlock;
- typeSetFlags = styleTypeSetFlags;
- value = defStyleAttrEntry->map.value;
- if (kDebugStyles) {
- ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
- }
-
- uint32_t resid = 0;
- if (value.dataType != Res_value::TYPE_NULL) {
- // Take care of resolving the found resource to its final value.
- ssize_t newBlock = theme->resolveAttributeReference(&value, block,
- &resid, &typeSetFlags, &config);
- if (newBlock >= 0) {
- block = newBlock;
- }
-
- if (kDebugStyles) {
- ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- } else {
- // If we still don't have a value for this attribute, try to find
- // it in the theme!
- ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
- if (newBlock >= 0) {
- if (kDebugStyles) {
- ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- newBlock = res.resolveReference(&value, block, &resid,
- &typeSetFlags, &config);
- if (kThrowOnBadId) {
- if (newBlock == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return JNI_FALSE;
- }
- }
-
- if (newBlock >= 0) {
- block = newBlock;
- }
-
- if (kDebugStyles) {
- ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- }
- }
-
- // Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- if (kDebugStyles) {
- ALOGI("-> Setting to @null!");
- }
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- block = kXmlBlock;
- }
-
- if (kDebugStyles) {
- ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
- }
-
- // Write the final value back to Java.
- dest[STYLE_TYPE] = value.dataType;
- dest[STYLE_DATA] = value.data;
- dest[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
- static_cast<jint>(res.getTableCookie(block)) : -1;
- dest[STYLE_RESOURCE_ID] = resid;
- dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
- dest[STYLE_DENSITY] = config.density;
-
- if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
- indicesIdx++;
- indices[indicesIdx] = ii;
- }
-
- dest += STYLE_NUM_ENTRIES;
- }
-
- res.unlock();
+ ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+ ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
+ bool result = applyStyle(theme, xmlParser,
+ defStyleAttr, defStyleRes,
+ (uint32_t*) src, NI,
+ (uint32_t*) baseDest,
+ (uint32_t*) indices);
if (indices != NULL) {
- indices[0] = indicesIdx;
env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
}
env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-
- return JNI_TRUE;
+ return result ? JNI_TRUE : JNI_FALSE;
}
static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
@@ -1626,8 +1274,6 @@
}
const ResTable& res(am->getResources());
ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
- ResTable_config config;
- Res_value value;
const jsize NI = env->GetArrayLength(attrs);
const jsize NV = env->GetArrayLength(outValues);
@@ -1642,108 +1288,29 @@
}
jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
- jint* dest = baseDest;
- if (dest == NULL) {
+ if (baseDest == NULL) {
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
return JNI_FALSE;
}
jint* indices = NULL;
- int indicesIdx = 0;
if (outIndices != NULL) {
if (env->GetArrayLength(outIndices) > NI) {
indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
}
}
- // Now lock down the resource object and start pulling stuff from it.
- res.lock();
-
- // Retrieve the XML attributes, if requested.
- const jsize NX = xmlParser->getAttributeCount();
- jsize ix=0;
- uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
-
- static const ssize_t kXmlBlock = 0x10000000;
-
- // Now iterate through all of the attributes that the client has requested,
- // filling in each with whatever data we can find.
- ssize_t block = 0;
- uint32_t typeSetFlags;
- for (jsize ii=0; ii<NI; ii++) {
- const uint32_t curIdent = (uint32_t)src[ii];
-
- // Try to find a value for this attribute...
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- typeSetFlags = 0;
- config.density = 0;
-
- // Skip through XML attributes until the end or the next possible match.
- while (ix < NX && curIdent > curXmlAttr) {
- ix++;
- curXmlAttr = xmlParser->getAttributeNameResID(ix);
- }
- // Retrieve the current XML attribute if it matches, and step to next.
- if (ix < NX && curIdent == curXmlAttr) {
- block = kXmlBlock;
- xmlParser->getAttributeValue(ix, &value);
- ix++;
- curXmlAttr = xmlParser->getAttributeNameResID(ix);
- }
-
- //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
- uint32_t resid = 0;
- if (value.dataType != Res_value::TYPE_NULL) {
- // Take care of resolving the found resource to its final value.
- //printf("Resolving attribute reference\n");
- ssize_t newBlock = res.resolveReference(&value, block, &resid,
- &typeSetFlags, &config);
- if (kThrowOnBadId) {
- if (newBlock == BAD_INDEX) {
- jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
- return JNI_FALSE;
- }
- }
- if (newBlock >= 0) block = newBlock;
- }
-
- // Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- }
-
- //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
-
- // Write the final value back to Java.
- dest[STYLE_TYPE] = value.dataType;
- dest[STYLE_DATA] = value.data;
- dest[STYLE_ASSET_COOKIE] =
- block != kXmlBlock ? reinterpret_cast<jint>(res.getTableCookie(block)) : (jint)-1;
- dest[STYLE_RESOURCE_ID] = resid;
- dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
- dest[STYLE_DENSITY] = config.density;
-
- if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
- indicesIdx++;
- indices[indicesIdx] = ii;
- }
-
- dest += STYLE_NUM_ENTRIES;
- }
-
- res.unlock();
+ bool result = retrieveAttributes(&res, xmlParser,
+ (uint32_t*) src, NI,
+ (uint32_t*) baseDest,
+ (uint32_t*) indices);
if (indices != NULL) {
- indices[0] = indicesIdx;
env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
}
-
env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
-
- return JNI_TRUE;
+ return result ? JNI_TRUE : JNI_FALSE;
}
static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
@@ -2160,9 +1727,11 @@
(void*) android_content_AssetManager_readAsset },
{ "seekAsset", "(JJI)J",
(void*) android_content_AssetManager_seekAsset },
- { "getAssetLength", "!(J)J",
+ // @FastNative
+ { "getAssetLength", "(J)J",
(void*) android_content_AssetManager_getAssetLength },
- { "getAssetRemainingLength", "!(J)J",
+ // @FastNative
+ { "getAssetRemainingLength", "(J)J",
(void*) android_content_AssetManager_getAssetRemainingLength },
{ "addAssetPathNative", "(Ljava/lang/String;Z)I",
(void*) android_content_AssetManager_addAssetPath },
@@ -2178,25 +1747,35 @@
(void*) android_content_AssetManager_getNonSystemLocales },
{ "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
(void*) android_content_AssetManager_getSizeConfigurations },
- { "setConfiguration", "!(IILjava/lang/String;IIIIIIIIIIIIII)V",
+ // @FastNative
+ { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
(void*) android_content_AssetManager_setConfiguration },
- { "getResourceIdentifier","!(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+ // @FastNative
+ { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
(void*) android_content_AssetManager_getResourceIdentifier },
- { "getResourceName","!(I)Ljava/lang/String;",
+ // @FastNative
+ { "getResourceName","(I)Ljava/lang/String;",
(void*) android_content_AssetManager_getResourceName },
- { "getResourcePackageName","!(I)Ljava/lang/String;",
+ // @FastNative
+ { "getResourcePackageName","(I)Ljava/lang/String;",
(void*) android_content_AssetManager_getResourcePackageName },
- { "getResourceTypeName","!(I)Ljava/lang/String;",
+ // @FastNative
+ { "getResourceTypeName","(I)Ljava/lang/String;",
(void*) android_content_AssetManager_getResourceTypeName },
- { "getResourceEntryName","!(I)Ljava/lang/String;",
+ // @FastNative
+ { "getResourceEntryName","(I)Ljava/lang/String;",
(void*) android_content_AssetManager_getResourceEntryName },
- { "loadResourceValue","!(ISLandroid/util/TypedValue;Z)I",
+ // @FastNative
+ { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
(void*) android_content_AssetManager_loadResourceValue },
- { "loadResourceBagValue","!(IILandroid/util/TypedValue;Z)I",
+ // @FastNative
+ { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
(void*) android_content_AssetManager_loadResourceBagValue },
- { "getStringBlockCount","!()I",
+ // @FastNative
+ { "getStringBlockCount","()I",
(void*) android_content_AssetManager_getStringBlockCount },
- { "getNativeStringBlock","!(I)J",
+ // @FastNative
+ { "getNativeStringBlock","(I)J",
(void*) android_content_AssetManager_getNativeStringBlock },
{ "getCookieName","(I)Ljava/lang/String;",
(void*) android_content_AssetManager_getCookieName },
@@ -2214,21 +1793,28 @@
(void*) android_content_AssetManager_copyTheme },
{ "clearTheme", "(J)V",
(void*) android_content_AssetManager_clearTheme },
- { "loadThemeAttributeValue", "!(JILandroid/util/TypedValue;Z)I",
+ // @FastNative
+ { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
(void*) android_content_AssetManager_loadThemeAttributeValue },
- { "getThemeChangingConfigurations", "!(J)I",
+ // @FastNative
+ { "getThemeChangingConfigurations", "(J)I",
(void*) android_content_AssetManager_getThemeChangingConfigurations },
{ "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
(void*) android_content_AssetManager_dumpTheme },
- { "applyStyle","!(JIIJ[I[I[I)Z",
+ // @FastNative
+ { "applyStyle","(JIIJ[I[I[I)Z",
(void*) android_content_AssetManager_applyStyle },
- { "resolveAttrs","!(JII[I[I[I[I)Z",
+ // @FastNative
+ { "resolveAttrs","(JII[I[I[I[I)Z",
(void*) android_content_AssetManager_resolveAttrs },
- { "retrieveAttributes","!(J[I[I[I)Z",
+ // @FastNative
+ { "retrieveAttributes","(J[I[I[I)Z",
(void*) android_content_AssetManager_retrieveAttributes },
- { "getArraySize","!(I)I",
+ // @FastNative
+ { "getArraySize","(I)I",
(void*) android_content_AssetManager_getArraySize },
- { "retrieveArray","!(I[I)I",
+ // @FastNative
+ { "retrieveArray","(I[I)I",
(void*) android_content_AssetManager_retrieveArray },
// XML files.
@@ -2238,11 +1824,14 @@
// Arrays.
{ "getArrayStringResource","(I)[Ljava/lang/String;",
(void*) android_content_AssetManager_getArrayStringResource },
- { "getArrayStringInfo","!(I)[I",
+ // @FastNative
+ { "getArrayStringInfo","(I)[I",
(void*) android_content_AssetManager_getArrayStringInfo },
- { "getArrayIntResource","!(I)[I",
+ // @FastNative
+ { "getArrayIntResource","(I)[I",
(void*) android_content_AssetManager_getArrayIntResource },
- { "getStyleAttributes","!(I)[I",
+ // @FastNative
+ { "getStyleAttributes","(I)[I",
(void*) android_content_AssetManager_getStyleAttributes },
// Bookkeeping.
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 4f8a2cb..173afd8 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -19,7 +19,7 @@
#include "JNIHelp.h"
#include "core_jni_helpers.h"
#include "jni.h"
-#include "log/logger.h"
+#include <log/logger.h>
#define UNUSED __attribute__((__unused__))
diff --git a/core/jni/android_util_PathParser.cpp b/core/jni/android_util_PathParser.cpp
index 53669a8..10efb95 100644
--- a/core/jni/android_util_PathParser.cpp
+++ b/core/jni/android_util_PathParser.cpp
@@ -101,14 +101,17 @@
static const JNINativeMethod gMethods[] = {
{"nParseStringForPath", "(JLjava/lang/String;I)V", (void*)parseStringForPath},
- {"nCreateEmptyPathData", "!()J", (void*)createEmptyPathData},
- {"nCreatePathData", "!(J)J", (void*)createPathData},
{"nCreatePathDataFromString", "(Ljava/lang/String;I)J", (void*)createPathDataFromStringPath},
- {"nInterpolatePathData", "!(JJJF)Z", (void*)interpolatePathData},
- {"nFinalize", "!(J)V", (void*)deletePathData},
- {"nCanMorph", "!(JJ)Z", (void*)canMorphPathData},
- {"nSetPathData", "!(JJ)V", (void*)setPathData},
- {"nCreatePathFromPathData", "!(JJ)V", (void*)setSkPathFromPathData},
+
+ // ---------------- @FastNative -----------------
+
+ {"nCreateEmptyPathData", "()J", (void*)createEmptyPathData},
+ {"nCreatePathData", "(J)J", (void*)createPathData},
+ {"nInterpolatePathData", "(JJJF)Z", (void*)interpolatePathData},
+ {"nFinalize", "(J)V", (void*)deletePathData},
+ {"nCanMorph", "(JJ)Z", (void*)canMorphPathData},
+ {"nSetPathData", "(JJ)V", (void*)setPathData},
+ {"nCreatePathFromPathData", "(JJ)V", (void*)setSkPathFromPathData},
};
int register_android_util_PathParser(JNIEnv* env) {
diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp
index a15c23c..99882cc 100644
--- a/core/jni/android_util_XmlBlock.cpp
+++ b/core/jni/android_util_XmlBlock.cpp
@@ -372,42 +372,45 @@
(void*) android_content_XmlBlock_nativeGetStringBlock },
{ "nativeCreateParseState", "(J)J",
(void*) android_content_XmlBlock_nativeCreateParseState },
- { "nativeNext", "!(J)I",
- (void*) android_content_XmlBlock_nativeNext },
- { "nativeGetNamespace", "!(J)I",
- (void*) android_content_XmlBlock_nativeGetNamespace },
- { "nativeGetName", "!(J)I",
- (void*) android_content_XmlBlock_nativeGetName },
- { "nativeGetText", "!(J)I",
- (void*) android_content_XmlBlock_nativeGetText },
- { "nativeGetLineNumber", "!(J)I",
- (void*) android_content_XmlBlock_nativeGetLineNumber },
- { "nativeGetAttributeCount", "!(J)I",
- (void*) android_content_XmlBlock_nativeGetAttributeCount },
- { "nativeGetAttributeNamespace","!(JI)I",
- (void*) android_content_XmlBlock_nativeGetAttributeNamespace },
- { "nativeGetAttributeName", "!(JI)I",
- (void*) android_content_XmlBlock_nativeGetAttributeName },
- { "nativeGetAttributeResource", "!(JI)I",
- (void*) android_content_XmlBlock_nativeGetAttributeResource },
- { "nativeGetAttributeDataType", "!(JI)I",
- (void*) android_content_XmlBlock_nativeGetAttributeDataType },
- { "nativeGetAttributeData", "!(JI)I",
- (void*) android_content_XmlBlock_nativeGetAttributeData },
- { "nativeGetAttributeStringValue", "!(JI)I",
- (void*) android_content_XmlBlock_nativeGetAttributeStringValue },
- { "nativeGetAttributeIndex", "!(JLjava/lang/String;Ljava/lang/String;)I",
- (void*) android_content_XmlBlock_nativeGetAttributeIndex },
- { "nativeGetIdAttribute", "!(J)I",
- (void*) android_content_XmlBlock_nativeGetIdAttribute },
- { "nativeGetClassAttribute", "!(J)I",
- (void*) android_content_XmlBlock_nativeGetClassAttribute },
- { "nativeGetStyleAttribute", "!(J)I",
- (void*) android_content_XmlBlock_nativeGetStyleAttribute },
{ "nativeDestroyParseState", "(J)V",
(void*) android_content_XmlBlock_nativeDestroyParseState },
{ "nativeDestroy", "(J)V",
(void*) android_content_XmlBlock_nativeDestroy },
+
+ // ------------------- @FastNative ----------------------
+
+ { "nativeNext", "(J)I",
+ (void*) android_content_XmlBlock_nativeNext },
+ { "nativeGetNamespace", "(J)I",
+ (void*) android_content_XmlBlock_nativeGetNamespace },
+ { "nativeGetName", "(J)I",
+ (void*) android_content_XmlBlock_nativeGetName },
+ { "nativeGetText", "(J)I",
+ (void*) android_content_XmlBlock_nativeGetText },
+ { "nativeGetLineNumber", "(J)I",
+ (void*) android_content_XmlBlock_nativeGetLineNumber },
+ { "nativeGetAttributeCount", "(J)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeCount },
+ { "nativeGetAttributeNamespace","(JI)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeNamespace },
+ { "nativeGetAttributeName", "(JI)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeName },
+ { "nativeGetAttributeResource", "(JI)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeResource },
+ { "nativeGetAttributeDataType", "(JI)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeDataType },
+ { "nativeGetAttributeData", "(JI)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeData },
+ { "nativeGetAttributeStringValue", "(JI)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeStringValue },
+ { "nativeGetAttributeIndex", "(JLjava/lang/String;Ljava/lang/String;)I",
+ (void*) android_content_XmlBlock_nativeGetAttributeIndex },
+ { "nativeGetIdAttribute", "(J)I",
+ (void*) android_content_XmlBlock_nativeGetIdAttribute },
+ { "nativeGetClassAttribute", "(J)I",
+ (void*) android_content_XmlBlock_nativeGetClassAttribute },
+ { "nativeGetStyleAttribute", "(J)I",
+ (void*) android_content_XmlBlock_nativeGetStyleAttribute },
};
int register_android_content_XmlBlock(JNIEnv* env)
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index ea5a760..2eada3e 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -161,7 +161,8 @@
{ "nativeDispose",
"(J)V",
(void*)nativeDispose },
- { "nativeScheduleVsync", "!(J)V",
+ // @FastNative
+ { "nativeScheduleVsync", "(J)V",
(void*)nativeScheduleVsync }
};
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index edc0da3..8d2a058 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -215,24 +215,27 @@
const char* const kClassPathName = "android/view/DisplayListCanvas";
static JNINativeMethod gMethods[] = {
- { "nInsertReorderBarrier","!(JZ)V", (void*) android_view_DisplayListCanvas_insertReorderBarrier },
- { "nCallDrawGLFunction", "!(JJLjava/lang/Runnable;)V",
+ // ------------ @FastNative ------------------
+
+ { "nInsertReorderBarrier","(JZ)V", (void*) android_view_DisplayListCanvas_insertReorderBarrier },
+
+ { "nCallDrawGLFunction", "(JJLjava/lang/Runnable;)V",
(void*) android_view_DisplayListCanvas_callDrawGLFunction },
- { "nDrawRoundRect", "!(JJJJJJJJ)V", (void*) android_view_DisplayListCanvas_drawRoundRectProps },
- { "nDrawCircle", "!(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps },
+ { "nDrawRoundRect", "(JJJJJJJJ)V", (void*) android_view_DisplayListCanvas_drawRoundRectProps },
+ { "nDrawCircle", "(JJJJJ)V", (void*) android_view_DisplayListCanvas_drawCircleProps },
- { "nFinishRecording", "!(J)J", (void*) android_view_DisplayListCanvas_finishRecording },
- { "nDrawRenderNode", "!(JJ)V", (void*) android_view_DisplayListCanvas_drawRenderNode },
+ { "nFinishRecording", "(J)J", (void*) android_view_DisplayListCanvas_finishRecording },
+ { "nDrawRenderNode", "(JJ)V", (void*) android_view_DisplayListCanvas_drawRenderNode },
- { "nCreateDisplayListCanvas", "!(II)J", (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
- { "nResetDisplayListCanvas", "!(JII)V", (void*) android_view_DisplayListCanvas_resetDisplayListCanvas },
+ { "nCreateDisplayListCanvas", "(II)J", (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
+ { "nResetDisplayListCanvas", "(JII)V", (void*) android_view_DisplayListCanvas_resetDisplayListCanvas },
- { "nDrawLayer", "!(JJ)V", (void*) android_view_DisplayListCanvas_drawLayer },
+ { "nDrawLayer", "(JJ)V", (void*) android_view_DisplayListCanvas_drawLayer },
- { "nGetMaximumTextureWidth", "!()I", (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
- { "nGetMaximumTextureHeight", "!()I", (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
+ { "nGetMaximumTextureWidth", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
+ { "nGetMaximumTextureHeight", "()I", (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
};
static JNINativeMethod gActivityThreadMethods[] = {
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 59c337b..1743731 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -182,7 +182,8 @@
SkBitmap bitmap;
bitmap.setInfo(SkImageInfo::Make(buffer->getWidth(), buffer->getHeight(),
convertPixelFormat(buffer->getPixelFormat()),
- kPremul_SkAlphaType),
+ kPremul_SkAlphaType,
+ GraphicsJNI::defaultColorSpace()),
bytesCount);
if (buffer->getWidth() > 0 && buffer->getHeight() > 0) {
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 0245d38..2132f3d 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -383,17 +383,6 @@
return 0;
}
-static jlong android_view_MotionEvent_nativeCopy(JNIEnv* env, jclass clazz,
- jlong destNativePtr, jlong sourceNativePtr, jboolean keepHistory) {
- MotionEvent* destEvent = reinterpret_cast<MotionEvent*>(destNativePtr);
- if (!destEvent) {
- destEvent = new MotionEvent();
- }
- MotionEvent* sourceEvent = reinterpret_cast<MotionEvent*>(sourceNativePtr);
- destEvent->copyFrom(sourceEvent, keepHistory);
- return reinterpret_cast<jlong>(destEvent);
-}
-
static void android_view_MotionEvent_nativeDispose(JNIEnv* env, jclass clazz,
jlong nativePtr) {
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
@@ -426,228 +415,6 @@
event->setMetaState(event->getMetaState() | metaState);
}
-static jint android_view_MotionEvent_nativeGetDeviceId(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getDeviceId();
-}
-
-static jint android_view_MotionEvent_nativeGetSource(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getSource();
-}
-
-static void android_view_MotionEvent_nativeSetSource(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint source) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- event->setSource(source);
-}
-
-static jint android_view_MotionEvent_nativeGetAction(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getAction();
-}
-
-static void android_view_MotionEvent_nativeSetAction(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint action) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- event->setAction(action);
-}
-
-static int android_view_MotionEvent_nativeGetActionButton(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getActionButton();
-}
-
-static void android_view_MotionEvent_nativeSetActionButton(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint button) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- event->setActionButton(button);
-}
-
-static jboolean android_view_MotionEvent_nativeIsTouchEvent(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->isTouchEvent();
-}
-
-static jint android_view_MotionEvent_nativeGetFlags(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getFlags();
-}
-
-static void android_view_MotionEvent_nativeSetFlags(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint flags) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- event->setFlags(flags);
-}
-
-static jint android_view_MotionEvent_nativeGetEdgeFlags(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getEdgeFlags();
-}
-
-static void android_view_MotionEvent_nativeSetEdgeFlags(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint edgeFlags) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- event->setEdgeFlags(edgeFlags);
-}
-
-static jint android_view_MotionEvent_nativeGetMetaState(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getMetaState();
-}
-
-static jint android_view_MotionEvent_nativeGetButtonState(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getButtonState();
-}
-
-static void android_view_MotionEvent_nativeSetButtonState(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint buttonState) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- event->setButtonState(buttonState);
-}
-
-static void android_view_MotionEvent_nativeOffsetLocation(JNIEnv* env, jclass clazz,
- jlong nativePtr, jfloat deltaX, jfloat deltaY) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->offsetLocation(deltaX, deltaY);
-}
-
-static jfloat android_view_MotionEvent_nativeGetXOffset(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getXOffset();
-}
-
-static jfloat android_view_MotionEvent_nativeGetYOffset(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getYOffset();
-}
-
-static jfloat android_view_MotionEvent_nativeGetXPrecision(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getXPrecision();
-}
-
-static jfloat android_view_MotionEvent_nativeGetYPrecision(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getYPrecision();
-}
-
-static jlong android_view_MotionEvent_nativeGetDownTimeNanos(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return event->getDownTime();
-}
-
-static void android_view_MotionEvent_nativeSetDownTimeNanos(JNIEnv* env, jclass clazz,
- jlong nativePtr, jlong downTimeNanos) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- event->setDownTime(downTimeNanos);
-}
-
-static jint android_view_MotionEvent_nativeGetPointerCount(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return jint(event->getPointerCount());
-}
-
-static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint pointerIndex) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- size_t pointerCount = event->getPointerCount();
- if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
- return -1;
- }
- return event->getPointerId(pointerIndex);
-}
-
-static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint pointerIndex) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- size_t pointerCount = event->getPointerCount();
- if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
- return -1;
- }
- return event->getToolType(pointerIndex);
-}
-
-static jint android_view_MotionEvent_nativeFindPointerIndex(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint pointerId) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return jint(event->findPointerIndex(pointerId));
-}
-
-static jint android_view_MotionEvent_nativeGetHistorySize(JNIEnv* env, jclass clazz,
- jlong nativePtr) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- return jint(event->getHistorySize());
-}
-
-static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint historyPos) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- if (historyPos == HISTORY_CURRENT) {
- return event->getEventTime();
- } else {
- size_t historySize = event->getHistorySize();
- if (!validateHistoryPos(env, historyPos, historySize)) {
- return 0;
- }
- return event->getHistoricalEventTime(historyPos);
- }
-}
-
-static jfloat android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- size_t pointerCount = event->getPointerCount();
- if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
- return 0;
- }
-
- if (historyPos == HISTORY_CURRENT) {
- return event->getRawAxisValue(axis, pointerIndex);
- } else {
- size_t historySize = event->getHistorySize();
- if (!validateHistoryPos(env, historyPos, historySize)) {
- return 0;
- }
- return event->getHistoricalRawAxisValue(axis, pointerIndex, historyPos);
- }
-}
-
-static jfloat android_view_MotionEvent_nativeGetAxisValue(JNIEnv* env, jclass clazz,
- jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- size_t pointerCount = event->getPointerCount();
- if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
- return 0;
- }
-
- if (historyPos == HISTORY_CURRENT) {
- return event->getAxisValue(axis, pointerIndex);
- } else {
- size_t historySize = event->getHistorySize();
- if (!validateHistoryPos(env, historyPos, historySize)) {
- return 0;
- }
- return event->getHistoricalAxisValue(axis, pointerIndex, historyPos);
- }
-}
-
static void android_view_MotionEvent_nativeGetPointerCoords(JNIEnv* env, jclass clazz,
jlong nativePtr, jint pointerIndex, jint historyPos, jobject outPointerCoordsObj) {
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
@@ -684,30 +451,6 @@
pointerPropertiesFromNative(env, pointerProperties, outPointerPropertiesObj);
}
-static void android_view_MotionEvent_nativeScale(JNIEnv* env, jclass clazz,
- jlong nativePtr, jfloat scale) {
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
- event->scale(scale);
-}
-
-static void android_view_MotionEvent_nativeTransform(JNIEnv* env, jclass clazz,
- jlong nativePtr, jobject matrixObj) {
- SkMatrix* matrix = android_graphics_Matrix_getSkMatrix(env, matrixObj);
- MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-
- float m[9];
- m[0] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleX));
- m[1] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewX));
- m[2] = SkScalarToFloat(matrix->get(SkMatrix::kMTransX));
- m[3] = SkScalarToFloat(matrix->get(SkMatrix::kMSkewY));
- m[4] = SkScalarToFloat(matrix->get(SkMatrix::kMScaleY));
- m[5] = SkScalarToFloat(matrix->get(SkMatrix::kMTransY));
- m[6] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp0));
- m[7] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp1));
- m[8] = SkScalarToFloat(matrix->get(SkMatrix::kMPersp2));
- event->transform(m);
-}
-
static jlong android_view_MotionEvent_nativeReadFromParcel(JNIEnv* env, jclass clazz,
jlong nativePtr, jobject parcelObj) {
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
@@ -750,6 +493,243 @@
return static_cast<jint>(MotionEvent::getAxisFromLabel(axisLabel.c_str()));
}
+// ---------------- @FastNative ----------------------------------
+
+static jint android_view_MotionEvent_nativeGetPointerId(JNIEnv* env, jclass clazz,
+ jlong nativePtr, jint pointerIndex) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ size_t pointerCount = event->getPointerCount();
+ if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
+ return -1;
+ }
+ return event->getPointerId(pointerIndex);
+}
+
+static jint android_view_MotionEvent_nativeGetToolType(JNIEnv* env, jclass clazz,
+ jlong nativePtr, jint pointerIndex) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ size_t pointerCount = event->getPointerCount();
+ if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
+ return -1;
+ }
+ return event->getToolType(pointerIndex);
+}
+
+static jlong android_view_MotionEvent_nativeGetEventTimeNanos(JNIEnv* env, jclass clazz,
+ jlong nativePtr, jint historyPos) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ if (historyPos == HISTORY_CURRENT) {
+ return event->getEventTime();
+ } else {
+ size_t historySize = event->getHistorySize();
+ if (!validateHistoryPos(env, historyPos, historySize)) {
+ return 0;
+ }
+ return event->getHistoricalEventTime(historyPos);
+ }
+}
+
+static jfloat android_view_MotionEvent_nativeGetRawAxisValue(JNIEnv* env, jclass clazz,
+ jlong nativePtr, jint axis,
+ jint pointerIndex, jint historyPos) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ size_t pointerCount = event->getPointerCount();
+ if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
+ return 0;
+ }
+
+ if (historyPos == HISTORY_CURRENT) {
+ return event->getRawAxisValue(axis, pointerIndex);
+ } else {
+ size_t historySize = event->getHistorySize();
+ if (!validateHistoryPos(env, historyPos, historySize)) {
+ return 0;
+ }
+ return event->getHistoricalRawAxisValue(axis, pointerIndex, historyPos);
+ }
+}
+
+static jfloat android_view_MotionEvent_nativeGetAxisValue(JNIEnv* env, jclass clazz,
+ jlong nativePtr, jint axis, jint pointerIndex, jint historyPos) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ size_t pointerCount = event->getPointerCount();
+ if (!validatePointerIndex(env, pointerIndex, pointerCount)) {
+ return 0;
+ }
+
+ if (historyPos == HISTORY_CURRENT) {
+ return event->getAxisValue(axis, pointerIndex);
+ } else {
+ size_t historySize = event->getHistorySize();
+ if (!validateHistoryPos(env, historyPos, historySize)) {
+ return 0;
+ }
+ return event->getHistoricalAxisValue(axis, pointerIndex, historyPos);
+ }
+}
+
+// ----------------- @CriticalNative ------------------------------
+
+static jlong android_view_MotionEvent_nativeCopy(jlong destNativePtr, jlong sourceNativePtr,
+ jboolean keepHistory) {
+ MotionEvent* destEvent = reinterpret_cast<MotionEvent*>(destNativePtr);
+ if (!destEvent) {
+ destEvent = new MotionEvent();
+ }
+ MotionEvent* sourceEvent = reinterpret_cast<MotionEvent*>(sourceNativePtr);
+ destEvent->copyFrom(sourceEvent, keepHistory);
+ return reinterpret_cast<jlong>(destEvent);
+}
+
+static jint android_view_MotionEvent_nativeGetDeviceId(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getDeviceId();
+}
+
+static jint android_view_MotionEvent_nativeGetSource(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getSource();
+}
+
+static void android_view_MotionEvent_nativeSetSource(jlong nativePtr, jint source) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ event->setSource(source);
+}
+
+static jint android_view_MotionEvent_nativeGetAction(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getAction();
+}
+
+static void android_view_MotionEvent_nativeSetAction(jlong nativePtr, jint action) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ event->setAction(action);
+}
+
+static int android_view_MotionEvent_nativeGetActionButton(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getActionButton();
+}
+
+static void android_view_MotionEvent_nativeSetActionButton(jlong nativePtr, jint button) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ event->setActionButton(button);
+}
+
+static jboolean android_view_MotionEvent_nativeIsTouchEvent(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->isTouchEvent();
+}
+
+static jint android_view_MotionEvent_nativeGetFlags(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getFlags();
+}
+
+static void android_view_MotionEvent_nativeSetFlags(jlong nativePtr, jint flags) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ event->setFlags(flags);
+}
+
+static jint android_view_MotionEvent_nativeGetEdgeFlags(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getEdgeFlags();
+}
+
+static void android_view_MotionEvent_nativeSetEdgeFlags(jlong nativePtr, jint edgeFlags) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ event->setEdgeFlags(edgeFlags);
+}
+
+static jint android_view_MotionEvent_nativeGetMetaState(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getMetaState();
+}
+
+static jint android_view_MotionEvent_nativeGetButtonState(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getButtonState();
+}
+
+static void android_view_MotionEvent_nativeSetButtonState(jlong nativePtr, jint buttonState) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ event->setButtonState(buttonState);
+}
+
+static void android_view_MotionEvent_nativeOffsetLocation(jlong nativePtr, jfloat deltaX,
+ jfloat deltaY) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->offsetLocation(deltaX, deltaY);
+}
+
+static jfloat android_view_MotionEvent_nativeGetXOffset(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getXOffset();
+}
+
+static jfloat android_view_MotionEvent_nativeGetYOffset(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getYOffset();
+}
+
+static jfloat android_view_MotionEvent_nativeGetXPrecision(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getXPrecision();
+}
+
+static jfloat android_view_MotionEvent_nativeGetYPrecision(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getYPrecision();
+}
+
+static jlong android_view_MotionEvent_nativeGetDownTimeNanos(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return event->getDownTime();
+}
+
+static void android_view_MotionEvent_nativeSetDownTimeNanos(jlong nativePtr, jlong downTimeNanos) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ event->setDownTime(downTimeNanos);
+}
+
+static jint android_view_MotionEvent_nativeGetPointerCount(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return jint(event->getPointerCount());
+}
+
+static jint android_view_MotionEvent_nativeFindPointerIndex(jlong nativePtr, jint pointerId) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return jint(event->findPointerIndex(pointerId));
+}
+
+static jint android_view_MotionEvent_nativeGetHistorySize(jlong nativePtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ return jint(event->getHistorySize());
+}
+
+static void android_view_MotionEvent_nativeScale(jlong nativePtr, jfloat scale) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ event->scale(scale);
+}
+
+static void android_view_MotionEvent_nativeTransform(jlong nativePtr, jlong matrixPtr) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
+
+ static_assert(SkMatrix::kMScaleX == 0, "SkMatrix unexpected index");
+ static_assert(SkMatrix::kMSkewX == 1, "SkMatrix unexpected index");
+ static_assert(SkMatrix::kMTransX == 2, "SkMatrix unexpected index");
+ static_assert(SkMatrix::kMSkewY == 3, "SkMatrix unexpected index");
+ static_assert(SkMatrix::kMScaleY == 4, "SkMatrix unexpected index");
+ static_assert(SkMatrix::kMTransY == 5, "SkMatrix unexpected index");
+ static_assert(SkMatrix::kMPersp0 == 6, "SkMatrix unexpected index");
+ static_assert(SkMatrix::kMPersp1 == 7, "SkMatrix unexpected index");
+ static_assert(SkMatrix::kMPersp2 == 8, "SkMatrix unexpected index");
+ float m[9];
+ matrix->get9(m);
+ event->transform(m);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMotionEventMethods[] = {
@@ -758,117 +738,12 @@
"(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
"[Landroid/view/MotionEvent$PointerCoords;)J",
(void*)android_view_MotionEvent_nativeInitialize },
- { "nativeCopy",
- "(JJZ)J",
- (void*)android_view_MotionEvent_nativeCopy },
{ "nativeDispose",
"(J)V",
(void*)android_view_MotionEvent_nativeDispose },
{ "nativeAddBatch",
"(JJ[Landroid/view/MotionEvent$PointerCoords;I)V",
(void*)android_view_MotionEvent_nativeAddBatch },
- { "nativeGetDeviceId",
- "!(J)I",
- (void*)android_view_MotionEvent_nativeGetDeviceId },
- { "nativeGetSource",
- "!(J)I",
- (void*)android_view_MotionEvent_nativeGetSource },
- { "nativeSetSource",
- "!(JI)I",
- (void*)android_view_MotionEvent_nativeSetSource },
- { "nativeGetAction",
- "!(J)I",
- (void*)android_view_MotionEvent_nativeGetAction },
- { "nativeSetAction",
- "!(JI)V",
- (void*)android_view_MotionEvent_nativeSetAction },
- { "nativeGetActionButton",
- "!(J)I",
- (void*)android_view_MotionEvent_nativeGetActionButton},
- { "nativeSetActionButton",
- "!(JI)V",
- (void*)android_view_MotionEvent_nativeSetActionButton},
- { "nativeIsTouchEvent",
- "!(J)Z",
- (void*)android_view_MotionEvent_nativeIsTouchEvent },
- { "nativeGetFlags",
- "!(J)I",
- (void*)android_view_MotionEvent_nativeGetFlags },
- { "nativeSetFlags",
- "!(JI)V",
- (void*)android_view_MotionEvent_nativeSetFlags },
- { "nativeGetEdgeFlags",
- "!(J)I",
- (void*)android_view_MotionEvent_nativeGetEdgeFlags },
- { "nativeSetEdgeFlags",
- "!(JI)V",
- (void*)android_view_MotionEvent_nativeSetEdgeFlags },
- { "nativeGetMetaState",
- "!(J)I",
- (void*)android_view_MotionEvent_nativeGetMetaState },
- { "nativeGetButtonState",
- "!(J)I",
- (void*)android_view_MotionEvent_nativeGetButtonState },
- { "nativeSetButtonState",
- "!(JI)V",
- (void*)android_view_MotionEvent_nativeSetButtonState },
- { "nativeOffsetLocation",
- "!(JFF)V",
- (void*)android_view_MotionEvent_nativeOffsetLocation },
- { "nativeGetXOffset",
- "!(J)F",
- (void*)android_view_MotionEvent_nativeGetXOffset },
- { "nativeGetYOffset",
- "!(J)F",
- (void*)android_view_MotionEvent_nativeGetYOffset },
- { "nativeGetXPrecision",
- "!(J)F",
- (void*)android_view_MotionEvent_nativeGetXPrecision },
- { "nativeGetYPrecision",
- "!(J)F",
- (void*)android_view_MotionEvent_nativeGetYPrecision },
- { "nativeGetDownTimeNanos",
- "!(J)J",
- (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
- { "nativeSetDownTimeNanos",
- "!(JJ)V",
- (void*)android_view_MotionEvent_nativeSetDownTimeNanos },
- { "nativeGetPointerCount",
- "!(J)I",
- (void*)android_view_MotionEvent_nativeGetPointerCount },
- { "nativeGetPointerId",
- "!(JI)I",
- (void*)android_view_MotionEvent_nativeGetPointerId },
- { "nativeGetToolType",
- "!(JI)I",
- (void*)android_view_MotionEvent_nativeGetToolType },
- { "nativeFindPointerIndex",
- "!(JI)I",
- (void*)android_view_MotionEvent_nativeFindPointerIndex },
- { "nativeGetHistorySize",
- "!(J)I",
- (void*)android_view_MotionEvent_nativeGetHistorySize },
- { "nativeGetEventTimeNanos",
- "!(JI)J",
- (void*)android_view_MotionEvent_nativeGetEventTimeNanos },
- { "nativeGetRawAxisValue",
- "!(JIII)F",
- (void*)android_view_MotionEvent_nativeGetRawAxisValue },
- { "nativeGetAxisValue",
- "!(JIII)F",
- (void*)android_view_MotionEvent_nativeGetAxisValue },
- { "nativeGetPointerCoords",
- "(JIILandroid/view/MotionEvent$PointerCoords;)V",
- (void*)android_view_MotionEvent_nativeGetPointerCoords },
- { "nativeGetPointerProperties",
- "(JILandroid/view/MotionEvent$PointerProperties;)V",
- (void*)android_view_MotionEvent_nativeGetPointerProperties },
- { "nativeScale",
- "!(JF)V",
- (void*)android_view_MotionEvent_nativeScale },
- { "nativeTransform",
- "(JLandroid/graphics/Matrix;)V",
- (void*)android_view_MotionEvent_nativeTransform },
{ "nativeReadFromParcel",
"(JLandroid/os/Parcel;)J",
(void*)android_view_MotionEvent_nativeReadFromParcel },
@@ -879,6 +754,116 @@
(void*)android_view_MotionEvent_nativeAxisToString },
{ "nativeAxisFromString", "(Ljava/lang/String;)I",
(void*)android_view_MotionEvent_nativeAxisFromString },
+ { "nativeGetPointerProperties",
+ "(JILandroid/view/MotionEvent$PointerProperties;)V",
+ (void*)android_view_MotionEvent_nativeGetPointerProperties },
+ { "nativeGetPointerCoords",
+ "(JIILandroid/view/MotionEvent$PointerCoords;)V",
+ (void*)android_view_MotionEvent_nativeGetPointerCoords },
+
+ // --------------- @FastNative ----------------------
+ { "nativeGetPointerId",
+ "(JI)I",
+ (void*)android_view_MotionEvent_nativeGetPointerId },
+ { "nativeGetToolType",
+ "(JI)I",
+ (void*)android_view_MotionEvent_nativeGetToolType },
+ { "nativeGetEventTimeNanos",
+ "(JI)J",
+ (void*)android_view_MotionEvent_nativeGetEventTimeNanos },
+ { "nativeGetRawAxisValue",
+ "(JIII)F",
+ (void*)android_view_MotionEvent_nativeGetRawAxisValue },
+ { "nativeGetAxisValue",
+ "(JIII)F",
+ (void*)android_view_MotionEvent_nativeGetAxisValue },
+
+ // --------------- @CriticalNative ------------------
+
+ { "nativeCopy",
+ "(JJZ)J",
+ (void*)android_view_MotionEvent_nativeCopy },
+ { "nativeGetDeviceId",
+ "(J)I",
+ (void*)android_view_MotionEvent_nativeGetDeviceId },
+ { "nativeGetSource",
+ "(J)I",
+ (void*)android_view_MotionEvent_nativeGetSource },
+ { "nativeSetSource",
+ "(JI)I",
+ (void*)android_view_MotionEvent_nativeSetSource },
+ { "nativeGetAction",
+ "(J)I",
+ (void*)android_view_MotionEvent_nativeGetAction },
+ { "nativeSetAction",
+ "(JI)V",
+ (void*)android_view_MotionEvent_nativeSetAction },
+ { "nativeGetActionButton",
+ "(J)I",
+ (void*)android_view_MotionEvent_nativeGetActionButton},
+ { "nativeSetActionButton",
+ "(JI)V",
+ (void*)android_view_MotionEvent_nativeSetActionButton},
+ { "nativeIsTouchEvent",
+ "(J)Z",
+ (void*)android_view_MotionEvent_nativeIsTouchEvent },
+ { "nativeGetFlags",
+ "(J)I",
+ (void*)android_view_MotionEvent_nativeGetFlags },
+ { "nativeSetFlags",
+ "(JI)V",
+ (void*)android_view_MotionEvent_nativeSetFlags },
+ { "nativeGetEdgeFlags",
+ "(J)I",
+ (void*)android_view_MotionEvent_nativeGetEdgeFlags },
+ { "nativeSetEdgeFlags",
+ "(JI)V",
+ (void*)android_view_MotionEvent_nativeSetEdgeFlags },
+ { "nativeGetMetaState",
+ "(J)I",
+ (void*)android_view_MotionEvent_nativeGetMetaState },
+ { "nativeGetButtonState",
+ "(J)I",
+ (void*)android_view_MotionEvent_nativeGetButtonState },
+ { "nativeSetButtonState",
+ "(JI)V",
+ (void*)android_view_MotionEvent_nativeSetButtonState },
+ { "nativeOffsetLocation",
+ "(JFF)V",
+ (void*)android_view_MotionEvent_nativeOffsetLocation },
+ { "nativeGetXOffset",
+ "(J)F",
+ (void*)android_view_MotionEvent_nativeGetXOffset },
+ { "nativeGetYOffset",
+ "(J)F",
+ (void*)android_view_MotionEvent_nativeGetYOffset },
+ { "nativeGetXPrecision",
+ "(J)F",
+ (void*)android_view_MotionEvent_nativeGetXPrecision },
+ { "nativeGetYPrecision",
+ "(J)F",
+ (void*)android_view_MotionEvent_nativeGetYPrecision },
+ { "nativeGetDownTimeNanos",
+ "(J)J",
+ (void*)android_view_MotionEvent_nativeGetDownTimeNanos },
+ { "nativeSetDownTimeNanos",
+ "(JJ)V",
+ (void*)android_view_MotionEvent_nativeSetDownTimeNanos },
+ { "nativeGetPointerCount",
+ "(J)I",
+ (void*)android_view_MotionEvent_nativeGetPointerCount },
+ { "nativeFindPointerIndex",
+ "(JI)I",
+ (void*)android_view_MotionEvent_nativeFindPointerIndex },
+ { "nativeGetHistorySize",
+ "(J)I",
+ (void*)android_view_MotionEvent_nativeGetHistorySize },
+ { "nativeScale",
+ "(JF)V",
+ (void*)android_view_MotionEvent_nativeScale },
+ { "nativeTransform",
+ "(JJ)V",
+ (void*)android_view_MotionEvent_nativeTransform },
};
int register_android_view_MotionEvent(JNIEnv* env) {
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 3f2b924..b6c81cf8 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -318,11 +318,11 @@
return 0;
}
-
SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height,
convertPixelFormat(outBuffer.format),
- outBuffer.format == PIXEL_FORMAT_RGBX_8888 ?
- kOpaque_SkAlphaType : kPremul_SkAlphaType);
+ outBuffer.format == PIXEL_FORMAT_RGBX_8888
+ ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
+ GraphicsJNI::defaultColorSpace());
SkBitmap bitmap;
ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 73b3f52..65f12ac 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -175,7 +175,9 @@
}
SkImageInfo screenshotInfo = SkImageInfo::Make(screenshot->getWidth(),
screenshot->getHeight(),
- colorType, alphaType);
+ colorType,
+ alphaType,
+ GraphicsJNI::defaultColorSpace());
const size_t rowBytes =
screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat());
@@ -184,14 +186,14 @@
return NULL;
}
- Bitmap* bitmap = new Bitmap(
+ auto pixelRef = new PixelRef(
(void*) screenshot->getPixels(), (void*) screenshot.get(), DeleteScreenshot,
screenshotInfo, rowBytes, nullptr);
screenshot.release();
- bitmap->peekAtPixelRef()->setImmutable();
+ pixelRef->setImmutable();
- return GraphicsJNI::createBitmap(env, bitmap,
- GraphicsJNI::kBitmapCreateFlag_Premultiplied, NULL);
+ return bitmap::createBitmap(env, pixelRef,
+ bitmap::kBitmapCreateFlag_Premultiplied, NULL);
}
static void nativeScreenshot(JNIEnv* env, jclass clazz, jobject displayTokenObj,
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index e185281..268aec5 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -90,7 +90,8 @@
default:
break;
}
- return SkImageInfo::Make(buffer.width, buffer.height, colorType, alphaType);
+ return SkImageInfo::Make(buffer.width, buffer.height, colorType, alphaType,
+ GraphicsJNI::defaultColorSpace());
}
/**
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 649cc1e..14dcb3f 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -613,21 +613,6 @@
return atoi(prop) > 0 ? JNI_TRUE : JNI_FALSE;
}
-static void android_view_ThreadedRenderer_setAtlas(JNIEnv* env, jobject clazz,
- jlong proxyPtr, jobject graphicBuffer, jlongArray atlasMapArray) {
- sp<GraphicBuffer> buffer = graphicBufferForJavaObject(env, graphicBuffer);
- jsize len = env->GetArrayLength(atlasMapArray);
- if (len <= 0) {
- ALOGW("Failed to initialize atlas, invalid map length: %d", len);
- return;
- }
- int64_t* map = new int64_t[len];
- env->GetLongArrayRegion(atlasMapArray, 0, len, map);
-
- RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
- proxy->setTextureAtlas(buffer, map, len);
-}
-
static void android_view_ThreadedRenderer_setProcessStatsBuffer(JNIEnv* env, jobject clazz,
jlong proxyPtr, jint fd) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -954,8 +939,7 @@
const char* const kClassPathName = "android/view/ThreadedRenderer";
static const JNINativeMethod gMethods[] = {
- { "nSupportsOpenGL", "!()Z", (void*) android_view_ThreadedRenderer_supportsOpenGL },
- { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V", (void*) android_view_ThreadedRenderer_setAtlas },
+ { "nSupportsOpenGL", "()Z", (void*) android_view_ThreadedRenderer_supportsOpenGL },
{ "nSetProcessStatsBuffer", "(JI)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
{ "nGetRenderThreadTid", "(J)I", (void*) android_view_ThreadedRenderer_getRenderThreadTid },
{ "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
diff --git a/core/jni/fd_utils-inl.h b/core/jni/fd_utils-inl.h
index 5c17b23..af27069 100644
--- a/core/jni/fd_utils-inl.h
+++ b/core/jni/fd_utils-inl.h
@@ -260,16 +260,13 @@
// Whitelist files needed for Runtime Resource Overlay, like these:
// /system/vendor/overlay/framework-res.apk
- // /system/vendor/overlay-subdir/pg/framework-res.apk
+ // /system/vendor/overlay/PG/android-framework-runtime-resource-overlay.apk
// /data/resource-cache/system@vendor@overlay@framework-res.apk@idmap
- // /data/resource-cache/system@vendor@overlay-subdir@pg@framework-res.apk@idmap
- // See AssetManager.cpp for more details on overlay-subdir.
+ // /data/resource-cache/system@vendor@overlay@PG@framework-res.apk@idmap
static const char* kOverlayDir = "/system/vendor/overlay/";
- static const char* kOverlaySubdir = "/system/vendor/overlay-subdir/";
static const char* kApkSuffix = ".apk";
- if ((android::base::StartsWith(path, kOverlayDir)
- || android::base::StartsWith(path, kOverlaySubdir))
+ if (android::base::StartsWith(path, kOverlayDir)
&& android::base::EndsWith(path, kApkSuffix)
&& path.find("/../") == std::string::npos) {
return true;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 357d6f9..c346849 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -149,6 +149,8 @@
<protected-broadcast
android:name="android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT" />
<protected-broadcast
+ android:name="android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED" />
+ <protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast
android:name="android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED" />
@@ -290,6 +292,7 @@
<protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_SCAN_AVAILABLE" />
+ <protected-broadcast android:name="android.net.wifi.nan.action.WIFI_NAN_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
<protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
<protected-broadcast android:name="android.net.wifi.STATE_CHANGE" />
@@ -433,6 +436,7 @@
<protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" />
<protected-broadcast android:name="EventConditionProvider.EVALUATE" />
+ <protected-broadcast android:name="SnoozeHelper.EVALUATE" />
<protected-broadcast android:name="wifi_scan_available" />
<protected-broadcast android:name="action.cne.started" />
@@ -495,6 +499,8 @@
<protected-broadcast android:name="com.android.server.retaildemo.ACTION_RESET_DEMO" />
+ <protected-broadcast android:name="android.intent.action.DEVICE_LOCKED_CHANGED" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -3039,7 +3045,7 @@
<!-- @SystemApi Allows access to MAC addresses of WiFi and Bluetooth peer devices.
@hide -->
<permission android:name="android.permission.PEERS_MAC_ADDRESS"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|setup" />
<!-- Allows the Nfc stack to dispatch Nfc messages to applications. Applications
can use this permission to ensure incoming Nfc messages are from the Nfc stack
diff --git a/core/res/res/color/background_cache_hint_selector_device_default.xml b/core/res/res/color/background_cache_hint_selector_device_default.xml
new file mode 100644
index 0000000..4470754
--- /dev/null
+++ b/core/res/res/color/background_cache_hint_selector_device_default.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_accelerated="false" android:color="?attr/colorBackground" />
+ <item android:color="@android:color/transparent" />
+</selector>
+
diff --git a/core/res/res/layout-round-watch/alert_dialog_title_material.xml b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
index 0279911..7e71e41 100644
--- a/core/res/res/layout-round-watch/alert_dialog_title_material.xml
+++ b/core/res/res/layout-round-watch/alert_dialog_title_material.xml
@@ -24,6 +24,7 @@
android:maxHeight="24dp"
android:maxWidth="24dp"
android:layout_marginTop="12dp"
+ android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@null" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 34244ab..5ca9f43 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Foonopsies"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Skermslot"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Sit af"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Noodgeval"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Foutverslag"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Neem foutverslag"</string>
<string name="bugreport_message" msgid="398447048750350456">"Dit sal inligting oor die huidige toestand van jou toestel insamel om as \'n e-posboodskap te stuur. Dit sal \'n tydjie neem vandat die foutverslag begin is totdat dit reg is om gestuur te word; wees asseblief geduldig."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g>-USB-datastokkie"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-berging"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Redigeer"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Datagebruik-opletberig"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Tik om gebruik en instellings te bekyk."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G-datalimiet bereik"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-datalimiet bereik"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index b3cd896..18fc6dd 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"የስልክ አማራጮች"</string>
<string name="global_action_lock" msgid="2844945191792119712">"ማያ ቆልፍ"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"ኃይል አጥፋ"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"ድንገተኛ አደጋ"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"የሳንካ ሪፖርት"</string>
<string name="bugreport_title" msgid="2667494803742548533">"የሳንካ ሪፖርት ውሰድ"</string>
<string name="bugreport_message" msgid="398447048750350456">"ይሄ እንደ የኢሜይል መልዕክት አድርጎ የሚልከውን ስለመሣሪያዎ የአሁኑ ሁኔታ መረጃ ይሰበስባል። የሳንካ ሪፖርቱን ከመጀመር ጀምሮ እስኪላክ ድረስ ትንሽ ጊዜ ይወስዳል፤ እባክዎ ይታገሱ።"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"የ<xliff:g id="MANUFACTURER">%s</xliff:g> ዩኤስቢ አንጻፊ"</string>
<string name="storage_usb" msgid="3017954059538517278">"የUSB ማከማቻ"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"አርትዕ"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"የውሂብ አጠቃቀም ማንቂያ"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"አጠቃቀምን እና ቅንብሮችን ለማየት መታ ያድርጉ።"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"የ2ጂ-3ጂ ውሂብ ገደብ ላይ ተደርሷል"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"የ4ጂ ውሂብ ገደብ ላይ ተደርሷል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 717e9da..3451bcc 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -222,8 +222,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"خيارات الهاتف"</string>
<string name="global_action_lock" msgid="2844945191792119712">"تأمين الشاشة"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"إيقاف التشغيل"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"الطوارئ"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"تقرير الأخطاء"</string>
<string name="bugreport_title" msgid="2667494803742548533">"إعداد تقرير بالأخطاء"</string>
<string name="bugreport_message" msgid="398447048750350456">"سيجمع هذا معلومات حول حالة جهازك الحالي لإرسالها كرسالة إلكترونية، ولكنه سيستغرق وقتًا قليلاً من بدء عرض تقرير بالأخطاء. وحتى يكون جاهزًا للإرسال، الرجاء الانتظار."</string>
@@ -1434,8 +1433,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"محرك أقراص USB من <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"وحدة تخزين USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"تعديل"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"تنبيه استخدام البيانات"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"انقر لعرض الاستخدام والإعدادات."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"تم بلوغ حد بيانات اتصال 2G-3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"تم بلوغ حد بيانات اتصال 4G"</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 5ff1373..1f0d164 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefon seçimləri"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Ekran kilidi"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Söndür"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Təcili"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Baq hesabatı"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Baqı xəbər verin"</string>
<string name="bugreport_message" msgid="398447048750350456">"Bu, sizin hazırkı cihaz durumu haqqında məlumat toplayacaq ki, elektron məktub şəklində göndərsin. Baq raportuna başlamaq üçün bir az vaxt lazım ola bilər, bir az səbr edin."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drayv"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB yaddaş"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Düzəliş edin"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Data istifadə siqnalı"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"İstifadə və ayarları görmək üçün tıklayın."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limitinə çatdı"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limitinə çatdı"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index a351d5c..2509eae 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -152,7 +152,7 @@
<string name="httpErrorAuth" msgid="1435065629438044534">"Nije moguće potvrditi autentičnost."</string>
<string name="httpErrorProxyAuth" msgid="1788207010559081331">"Potvrda identiteta preko proksi servera nije uspela."</string>
<string name="httpErrorConnect" msgid="8714273236364640549">"Nije moguće povezati se sa serverom."</string>
- <string name="httpErrorIO" msgid="2340558197489302188">"Nije moguće komunicirati sa serverom. Pokušajte ponovo kasnije."</string>
+ <string name="httpErrorIO" msgid="2340558197489302188">"Nije moguće komunicirati sa serverom. Probajte ponovo kasnije."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"Veza sa serverom je istekla."</string>
<string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Stranica sadrži previše veza za preusmeravanje sa servera."</string>
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protokol nije podržan."</string>
@@ -160,7 +160,7 @@
<string name="httpErrorBadUrl" msgid="3636929722728881972">"Stranicu nije moguće otvoriti zato što je URL adresa nevažeća."</string>
<string name="httpErrorFile" msgid="2170788515052558676">"Nije moguće pristupiti datoteci."</string>
<string name="httpErrorFileNotFound" msgid="6203856612042655084">"Nije moguće pronaći traženu datoteku."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Previše zahteva se obrađuje. Pokušajte ponovo kasnije."</string>
+ <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Previše zahteva se obrađuje. Probajte ponovo kasnije."</string>
<string name="notification_title" msgid="8967710025036163822">"Greška pri prijavljivanju za <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
<string name="contentServiceSync" msgid="8353523060269335667">"Sinhronizacija"</string>
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sinhronizacija"</string>
@@ -216,8 +216,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Zaključaj ekran"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Isključi"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Hitni poziv"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Izveštaj o grešci"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Napravi izveštaj o grešci"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupiti informacije o trenutnom stanju uređaja kako bi bile poslate u poruci e-pošte. Od započinjanja izveštaja o grešci do trenutka za njegovo slanje proći će neko vreme; budite strpljivi."</string>
@@ -441,19 +440,19 @@
<string name="permdesc_manageFingerprint" msgid="178208705828055464">"Dozvoljava aplikaciji da aktivira metode za dodavanje i brisanje šablona otisaka prstiju koji će se koristiti."</string>
<string name="permlab_useFingerprint" msgid="3150478619915124905">"koristi hardver za otiske prstiju"</string>
<string name="permdesc_useFingerprint" msgid="9165097460730684114">"Dozvoljava aplikaciji da koristi hardver za otiske prstiju radi potvrde autentičnosti"</string>
- <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je delimični otisak prsta. Pokušajte ponovo."</string>
- <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspela obrada otiska prsta. Pokušajte ponovo."</string>
+ <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Otkriven je delimični otisak prsta. Probajte ponovo."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nije uspela obrada otiska prsta. Probajte ponovo."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Senzor za otiske prstiju je prljav. Očistite ga i pokušajte ponovo."</string>
- <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Prebrzo ste pomerili prst. Pokušajte ponovo."</string>
- <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Previše sporo ste pomerili prst. Pokušajte ponovo."</string>
+ <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Prebrzo ste pomerili prst. Probajte ponovo."</string>
+ <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Previše sporo ste pomerili prst. Probajte ponovo."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Hardver za otiske prstiju nije dostupan."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Nije moguće sačuvati otisak prsta. Uklonite neki od postojećih otisaka prstiju."</string>
- <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Pokušajte ponovo."</string>
+ <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vremensko ograničenje za otisak prsta je isteklo. Probajte ponovo."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Radnja sa otiskom prsta je otkazana."</string>
- <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Previše pokušaja. Pokušajte ponovo kasnije."</string>
- <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Pokušajte ponovo."</string>
+ <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Previše pokušaja. Probajte ponovo kasnije."</string>
+ <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Probajte ponovo."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -681,8 +680,8 @@
<string name="lockscreen_emergency_call" msgid="5298642613417801888">"Hitne službe"</string>
<string name="lockscreen_return_to_call" msgid="5244259785500040021">"Nazad na poziv"</string>
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Tačno!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Pokušajte ponovo"</string>
- <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Pokušajte ponovo"</string>
+ <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Probajte ponovo"</string>
+ <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Probajte ponovo"</string>
<string name="lockscreen_storage_locked" msgid="9167551160010625200">"Otključaj za sve funkcije i podatke"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Premašen je najveći dozvoljeni broj pokušaja Otključavanja licem"</string>
<string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Nema SIM kartice"</string>
@@ -706,19 +705,19 @@
<string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Pogledajte Korisnički vodič ili kontaktirajte Korisničku podršku."</string>
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM kartica je zaključana."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Otključavanje SIM kartice…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste nepravilno nacrtali šablon za otključavanje. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
- <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli lozinku. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
- <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli PIN. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja od vas će biti zatraženo da otključate TV pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću podataka za prijavljivanje na Google.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste nepravilno nacrtali šablon za otključavanje. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli lozinku. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste pogrešno uneli PIN. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću podataka za prijavljivanje na Google.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja od vas će biti zatraženo da otključate TV pomoću podataka za prijavljivanje na Google.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> puta ste netačno uneli šablon za otključavanje. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> nesupešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću podataka za prijavljivanje na Google.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Nepravilno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još neuspešnih pokušaja (<xliff:g id="NUMBER_1">%2$d</xliff:g>) tablet će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja TV će biti resetovan na podrazumevana fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Neispravno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još neuspešnih pokušaja (<xliff:g id="NUMBER_1">%2$d</xliff:g>) telefon će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Neispravno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> puta. Tablet će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER">%d</xliff:g> puta. TV će sada biti resetovan na podrazumevana fabrička podešavanja."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Neispravno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> puta. Telefon će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Pokušajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sekunde(i)."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Probajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sekunde(i)."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zaboravili ste šablon?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Otključavanje naloga"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Previše pokušaja unosa šablona"</string>
@@ -1356,8 +1355,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB memorija"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Izmeni"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Obaveštenje o potrošnji podataka"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za potrošnju i podešavanja."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Nema više 2G-3G podataka"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Nema više 4G podataka"</string>
@@ -1423,7 +1421,7 @@
<string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan šablon"</string>
<string name="kg_wrong_password" msgid="2333281762128113157">"Pogrešna lozinka"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"Pogrešan PIN"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Pokušajte ponovo za <xliff:g id="NUMBER">%1$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probajte ponovo za <xliff:g id="NUMBER">%1$d</xliff:g> sekunde(i)."</string>
<string name="kg_pattern_instructions" msgid="398978611683075868">"Nacrtajte šablon"</string>
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Unesite PIN SIM kartice"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Unesite PIN"</string>
@@ -1445,18 +1443,18 @@
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Nevažeće korisničko ime ili lozinka."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Zaboravili ste korisničko ime ili lozinku?\nPosetite adresu "<b>"google.com/accounts/recovery"</b>"."</string>
<string name="kg_login_checking_password" msgid="1052685197710252395">"Provera naloga…"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Pokušali ste da otključate tablet netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja tablet će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja TV će biti resetovan na podrazumevana fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Pokušali ste da otključate telefon netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja telefon će biti resetovan na fabrička podešavanja i svi korisnički podaci će biti izgubljeni."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Pokušali ste da otključate tablet netačno <xliff:g id="NUMBER">%d</xliff:g> puta. Tablet će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Pokušali ste da otključate TV netačno <xliff:g id="NUMBER">%d</xliff:g> puta. TV će sada biti resetovan na podrazumevana fabrička podešavanja."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Pokušali ste da otključate telefon netačno <xliff:g id="NUMBER">%d</xliff:g> puta. Telefon će sada biti vraćen na podrazumevana fabrička podešavanja."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate TV pomoću naloga e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nProbajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Neispravno ste nacrtali šablon za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate TV pomoću naloga e-pošte.\n\n Probajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nProbajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Ukloni"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Želite da pojačate zvuk iznad preporučenog nivoa?\n\nSlušanje glasne muzike duže vreme može da vam ošteti sluh."</string>
@@ -1567,14 +1565,14 @@
<string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Novi PIN"</string>
<string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Potvrdite novi PIN"</string>
<string name="restr_pin_create_pin" msgid="8017600000263450337">"Napravite PIN za izmenu ograničenja"</string>
- <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Pokušajte ponovo."</string>
+ <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ovi se ne podudaraju. Probajte ponovo."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN je prekratak. Mora da sadrži najmanje 4 cifre."</string>
<plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
- <item quantity="one">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundu</item>
- <item quantity="few">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekunde</item>
- <item quantity="other">Pokušajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundi</item>
+ <item quantity="one">Probajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundu</item>
+ <item quantity="few">Probajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekunde</item>
+ <item quantity="other">Probajte ponovo za <xliff:g id="COUNT">%d</xliff:g> sekundi</item>
</plurals>
- <string name="restr_pin_try_later" msgid="973144472490532377">"Pokušajte ponovo kasnije"</string>
+ <string name="restr_pin_try_later" msgid="973144472490532377">"Probajte ponovo kasnije"</string>
<string name="immersive_cling_title" msgid="8394201622932303336">"Prikazuje se ceo ekran"</string>
<string name="immersive_cling_description" msgid="3482371193207536040">"Da biste izašli, prevucite nadole odozgo."</string>
<string name="immersive_cling_positive" msgid="5016839404568297683">"Važi"</string>
diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
index 13a9cdcef..f5f1e62 100644
--- a/core/res/res/values-be-rBY/strings.xml
+++ b/core/res/res/values-be-rBY/strings.xml
@@ -218,8 +218,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Параметры тэлефона"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Блакіроўка экрана"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Выключыць"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"SOS-выклік"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Справаздача пра памылкі"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Справаздача пра памылку"</string>
<string name="bugreport_message" msgid="398447048750350456">"Будзе збiрацца iнфармацыя пра бягучы стан прылады, якая будзе адпраўляцца на электронную пошту. Стварэнне справаздачы пра памылкi зойме некаторы час."</string>
@@ -1382,8 +1381,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-дыск <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Рэдагаваць"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Абвестка аб выкарыстанні трафіка"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Прагляд выкарыстання і налад."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Дасягнуты ліміт трафіку 2G-3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Дасягнуты ліміт трафіку 4G"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 95e89af..f6eb810 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Опции на телефона"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Заключване на екрана"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Изключване"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Спешно обаждане"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Сигнал за програмна грешка"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Сигнал за програмна грешка"</string>
<string name="bugreport_message" msgid="398447048750350456">"По този начин ще се събере информация за текущото състояние на устройството ви, която да се изпрати като имейл съобщение. След стартирането на процеса ще мине известно време, докато сигналът за програмна грешка бъде готов за подаване. Моля, имайте търпение."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"USB устройство от <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB хранилище"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Редактиране"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Сигнал за преноса на данни"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Пренос и настройки: Докоснете за преглед."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Достигнат лимит за 2G/3G данните"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Достигнат лимит за 4G данните"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 25f3367..f873b1c 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ফোন বিকল্পগুলি"</string>
<string name="global_action_lock" msgid="2844945191792119712">"স্ক্রীণ লক"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"পাওয়ার বন্ধ করুন"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"জরুরী"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"ত্রুটির প্রতিবেদন"</string>
<string name="bugreport_title" msgid="2667494803742548533">"ত্রুটির অভিযোগ করুন"</string>
<string name="bugreport_message" msgid="398447048750350456">"এটি একটি ই-মেল বার্তা পাঠানোর জন্য আপনার ডিভাইসের বর্তমান অবস্থা সম্পর্কে তথ্য সংগ্রহ করবে৷ ত্রুটির প্রতিবেদন শুরুর সময় থেকে এটি পাঠানোর জন্য প্রস্তুত হতে কিছুটা সময় নেবে; দয়া করে ধৈর্য রাখুন৷"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ড্রাইভ"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB সঞ্চয়স্থান"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"সম্পাদনা করুন"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"ডেটা ব্যবহারের সতর্কতা"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"ব্যবহার এবং সেটিংস দেখতে আলতো চাপুন৷"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ডেটা সীমা ছাড়িয়েছে"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ডেটা সীমা ছাড়িয়েছে"</string>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index e786ff9..7cb46fe 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -216,8 +216,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Zaključavanje ekrana"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Isključi telefon"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Hitni slučaj"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Izvještaj o greškama"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Kreirajte izvještaj o greškama"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupljati informacije o trenutnom stanju uređaja, koji će biti poslani kao poruka e-pošte. Može malo potrajati dok se izvještaj o greškama ne kreira i bude spreman za slanje. Budite strpljivi."</string>
@@ -1358,8 +1357,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozorenje o prijenosu podataka"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za prikaz upotrebe i postavki."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dostignut limit za 2G-3G podatke"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dostignut limit za 4G podatke"</string>
@@ -1600,7 +1598,7 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao administrator"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao administrator"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Da bi se trajanje baterije produžilo, opcija za štednju baterije minimizira rad uređaja i ograničava vibriranje, usluge lokacije i većinu prijenosa podataka u pozadini. E-pošta, poruke i druge aplikacije koje se oslanjaju na sinhronizaciju ne mogu biti ažurirane dok ih ne otvorite.\n\nŠtednja baterije se automatski isključi prilikom punjenja uređaja."</string>
- <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjilo korištenje podataka, usluga Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali se to može desiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
+ <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjio prijenos podataka, usluga Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali se to može desiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index ac0b6d3..d1fbebb 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opcions del telèfon"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Bloqueig de pantalla"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Apaga"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergències"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Informe d\'error"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Crea informe d\'errors"</string>
<string name="bugreport_message" msgid="398447048750350456">"Es recopilarà informació sobre l\'estat actual del dispositiu i se t\'enviarà per correu electrònic. Passaran uns quants minuts des de l\'inici de l\'informe d\'errors fins al seu enviament, per la qual cosa et recomanem que tinguis paciència."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Unitat USB de: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Emmagatzematge USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Edita"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta d\'ús de dades"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Toca per veure l\'ús i la configuració."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límit de dades 2G-3G assolit"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límit de dades 4G assolit"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 4370d9f..0e6ba82 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -218,8 +218,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefonu"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Zámek obrazovky"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Vypnout"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Stav nouze"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Hlášení chyb"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Vytvořit chybové hlášení"</string>
<string name="bugreport_message" msgid="398447048750350456">"Shromažďuje informace o aktuálním stavu zařízení. Tyto informace je následně možné poslat v e-mailové zprávě, chvíli však potrvá, než bude hlášení o chybě připraveno k odeslání. Buďte prosím trpěliví."</string>
@@ -1382,8 +1381,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Jednotka USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Úložiště USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Upravit"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozornění na používání dat"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Klepnutím zobrazíte nastavení."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dosáhli jste limitu dat 2G–3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dosáhli jste limitu dat 4G"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 1688cbe..628f9bb 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Indstillinger for telefon"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Skærmlås"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Sluk"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Nødopkald"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Fejlrapport"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Lav fejlrapport"</string>
<string name="bugreport_message" msgid="398447048750350456">"Der indsamles oplysninger om din enheds aktuelle status, der efterfølgende sendes i en e-mail. Der går lidt tid, fra fejlrapporten påbegyndes, til den er klar til at blive sendt. Tak for tålmodigheden."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-drev fra <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-lager"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediger"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Underretning om dataforbrug"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Tryk for at se forbrug og indstillinger."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Grænsen for 2G-3G-data er nået"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Grænsen for 4G-data er nået"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index d13777b..05155ca 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoptionen"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Displaysperre"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Ausschalten"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Notfall"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Fehlerbericht"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Fehlerbericht abrufen"</string>
<string name="bugreport_message" msgid="398447048750350456">"Bei diesem Fehlerbericht werden Daten zum aktuellen Status deines Geräts erfasst und als E-Mail versandt. Vom Start des Berichts bis zu seinem Versand kann es eine Weile dauern. Bitte habe etwas Geduld."</string>
@@ -418,7 +417,7 @@
<string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Ermöglicht der App, Pakete zu empfangen, die mithilfe von Multicast-Adressen an sämtliche Geräte in einem WLAN versendet wurden, nicht nur an dein Telefon. Dies nimmt mehr Leistung in Anspruch als der Nicht-Multicast-Modus."</string>
<string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"Auf Bluetooth-Einstellungen zugreifen"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"Ermöglicht der App, das lokale Bluetooth-Tablet zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen"</string>
- <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Ermöglicht der App, den lokalen Bluetooth-Fernseher zu konfigurieren, Remote-Geräte zu erkennen und ein Pairing mit diesen durchzuführen"</string>
+ <string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"Ermöglicht der App, den lokalen Bluetooth-Fernseher zu konfigurieren, Remote-Geräte zu erkennen und eine Kopplung mit ihnen durchzuführen"</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"Ermöglicht der App, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen"</string>
<string name="permlab_accessWimaxState" msgid="4195907010610205703">"WiMAX-Verbindungen herstellen und trennen"</string>
<string name="permdesc_accessWimaxState" msgid="6360102877261978887">"Ermöglicht der App festzustellen, ob WiMAX aktiviert ist. Zudem kann sie Informationen zu verbundenen WiMAX-Netzwerken abrufen."</string>
@@ -426,9 +425,9 @@
<string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"Ermöglicht der App, eine Verbindung zwischen dem Tablet und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
<string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"Ermöglicht der App, eine Verbindung zwischen dem Fernseher und WiMAX-Netzwerken herzustellen und diese zu trennen"</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"Ermöglicht der App, eine Verbindung zwischen dem Telefon und WiMAX-Netzwerken herzustellen und solche zu trennen."</string>
- <string name="permlab_bluetooth" msgid="6127769336339276828">"Pairing mit Bluetooth-Geräten durchführen"</string>
+ <string name="permlab_bluetooth" msgid="6127769336339276828">"Kopplung mit Bluetooth-Geräten durchführen"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"Ermöglicht der App, die Bluetooth-Konfiguration eines Tablets einzusehen und Verbindungen zu gekoppelten Geräten herzustellen und zu akzeptieren."</string>
- <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Ermöglicht der App, die Bluetooth-Konfiguration des Fernsehers einzusehen und Verbindungen zu Pairing-Geräten herzustellen und zu akzeptieren"</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"Ermöglicht der App, die Bluetooth-Konfiguration des Fernsehers abzurufen und Verbindungen zu gekoppelten Geräten herzustellen und zu akzeptieren"</string>
<string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"Ermöglicht der App, die Bluetooth-Konfiguration des Telefons einzusehen und Verbindungen mit gekoppelten Geräten herzustellen und zu akzeptieren."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"Nahfeldkommunikation steuern"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"Ermöglicht der App die Kommunikation mit Tags für die Nahfeldkommunikation, Karten und Readern"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-Speichergerät von <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-Speicher"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Bearbeiten"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Warnung zur Datennutzung"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Für Nutzung und Einstellungen tippen."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-/3G-Datenlimit erreicht"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-Datenlimit erreicht"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 8f63a73..5f148e3 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Επιλογές τηλεφώνου"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Κλείδωμα οθόνης"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Απενεργοποίηση"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Κλήση έκτακτης ανάγκης"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Αναφορά σφαλμάτων"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Λήψη αναφοράς σφάλματος"</string>
<string name="bugreport_message" msgid="398447048750350456">"Θα συλλέξει πληροφορίες σχετικά με την τρέχουσα κατάσταση της συσκευής σας και θα τις στείλει μέσω μηνύματος ηλεκτρονικού ταχυδρομείου. Απαιτείται λίγος χρόνος για τη σύνταξη της αναφοράς σφάλματος και την αποστολή της. Κάντε λίγη υπομονή."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Μονάδα USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Αποθηκευτικός χώρος USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Επεξεργασία"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Ειδοποίηση χρήσης δεδομένων"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Πατήστε για προβολή χρήσης/ρυθμ."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Συμπλ. το όριο δεδομένων 2G-3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Συμπλ. το όριο δεδομένων 4G"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 348a7de56..38f2b88 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
<string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 348a7de56..38f2b88 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
<string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 348a7de56..38f2b88 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Phone options"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Screen lock"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Power off"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Bug report"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Take bug report"</string>
<string name="bugreport_message" msgid="398447048750350456">"This will collect information about your current device state, to send as an email message. It will take a little time from starting the bug report until it is ready to be sent. Please be patient."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Data usage alert"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Tap to view usage and settings."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G data limit reached"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G data limit reached"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 39746e0..1277acc 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opciones de dispositivo"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergencias"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Informe de errores"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Iniciar informe de errores"</string>
<string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo, que se enviará por correo. Pasarán unos minutos desde que se inicie el informe de errores hasta que se envíe, por lo que te recomendamos que tengas paciencia."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidad USB de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta por el uso de datos"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Presiona para uso y opciones."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos 2G-3G alcanzado"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos 4G alcanzado"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 117205f..77b43b1 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opciones del teléfono"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Bloqueo de pantalla"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergencia"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Informe de error"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Crear informe de errores"</string>
<string name="bugreport_message" msgid="398447048750350456">"Se recopilará información sobre el estado actual de tu dispositivo y se enviará por correo electrónico. Pasarán unos minutos desde que empiece a generarse el informe de errores hasta que se envíe."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidad USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Almacenamiento USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta sobre el uso de datos"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Toca para ver uso y ajustes."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos 2G-3G alcanzado"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos 4G alcanzado"</string>
@@ -1571,7 +1569,7 @@
<string name="package_updated_device_owner" msgid="8856631322440187071">"Actualizado por tu administrador"</string>
<string name="package_deleted_device_owner" msgid="7650577387493101353">"Eliminado por tu administrador"</string>
<string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de la transmisión de datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de energía se desactiva automáticamente cuando el dispositivo se está cargando."</string>
- <string name="data_saver_description" msgid="6015391409098303235">"El Economizador de Datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se muestren hasta que no las toques."</string>
+ <string name="data_saver_description" msgid="6015391409098303235">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se muestren hasta que no las toques."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"¿Activar ahorro de datos?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"Activar"</string>
<plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 2fadecb..d7ee50c 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefonivalikud"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Ekraanilukk"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Lülita välja"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Hädaabi"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Veaaruanne"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Veaaruande võtmine"</string>
<string name="bugreport_message" msgid="398447048750350456">"Nii kogutakse teavet teie seadme praeguse oleku kohta, et saata see meilisõnumina. Enne kui saate veaaruande ära saata, võtab selle loomine natuke aega; varuge kannatust."</string>
@@ -253,7 +252,7 @@
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"saata ja vaadata SMS-sõnumeid"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Mäluruum"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"juurde pääseda seadmesse salvestatud fotodele, meediale ja failidele"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"juurde pääseda seadmesse salvestatud fotodele, meediasisule ja failidele"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"heli salvestamine"</string>
<string name="permgrouplab_camera" msgid="4820372495894586615">"Kaamera"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Tootja <xliff:g id="MANUFACTURER">%s</xliff:g> USB-ketas"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-mäluseade"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Muuda"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Andmekasutuse hoiatus"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Puudutage kasutuse/seadete vaat."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-, 3G-andmeside limiit on täis"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-andmeside limiit on täis"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 6179987..e7f3f02 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefonoaren aukerak"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Pantailaren blokeoa"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Itzali"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Larrialdiak"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Akatsen txostena"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Sortu akatsen txostena"</string>
<string name="bugreport_message" msgid="398447048750350456">"Gailuaren uneko egoerari buruzko informazioa bilduko da, mezu elektroniko gisa bidaltzeko. Minutu batzuk igaroko dira akatsen txostena sortzen hasten denetik bidaltzeko prest egon arte. Itxaron, mesedez."</string>
@@ -744,7 +743,7 @@
<string name="keyguard_accessibility_user_selector" msgid="1226798370913698896">"Erabiltzaile-hautatzailea"</string>
<string name="keyguard_accessibility_status" msgid="8008264603935930611">"Egoera"</string>
<string name="keyguard_accessibility_camera" msgid="8904231194181114603">"Kamera"</string>
- <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Multimedia-kontrolak"</string>
+ <string name="keygaurd_accessibility_media_controls" msgid="262209654292161806">"Multimedia kontrolatzeko aukerak"</string>
<string name="keyguard_accessibility_widget_reorder_start" msgid="8736853615588828197">"Widgetak berrantolatzen hasi da."</string>
<string name="keyguard_accessibility_widget_reorder_end" msgid="7170190950870468320">"Widgetak berrantolatu dira."</string>
<string name="keyguard_accessibility_widget_deleted" msgid="4426204263929224434">"<xliff:g id="WIDGET_INDEX">%1$s</xliff:g> widgeta ezabatu da."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB unitatea"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB memoria"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Editatu"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Datu-erabilerari buruzko abisua"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Sakatu erabilera eta ezarpenak ikusteko."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2-3 GB-ko mugara iritsi zara"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4 GB-ko mugara iritsi zara"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index fd2bf81..374183f 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"گزینههای تلفن"</string>
<string name="global_action_lock" msgid="2844945191792119712">"قفل صفحه"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"خاموش کردن"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"اضطراری"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"گزارش اشکال"</string>
<string name="bugreport_title" msgid="2667494803742548533">"گرفتن گزارش اشکال"</string>
<string name="bugreport_message" msgid="398447048750350456">"این گزارش اطلاعات مربوط به وضعیت دستگاه کنونی شما را جمعآوری میکند تا به صورت یک پیام رایانامه ارسال شود. از زمان شروع گزارش اشکال تا آماده شدن برای ارسال اندکی زمان میبرد؛ لطفاً شکیبا باشید."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"درایو USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"حافظهٔ USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"ویرایش"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"هشدار مصرف داده"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"برای مشاهده مصرف و تنظیمات ضربه بزنید."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"به حد مجاز مصرف داده 2G-3G رسید"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"به حد مجاز مصرف داده 4G رسید"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 3ea7e66..9b6d57c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Puhelimen asetukset"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Näytön lukitus"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Katkaise virta"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Hätäpuhelu"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Virheraportti"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Luo virheraportti"</string>
<string name="bugreport_message" msgid="398447048750350456">"Toiminto kerää tietoja laitteen tilasta ja lähettää ne sähköpostitse. Virheraportti on valmis lähetettäväksi hetken kuluttua - kiitos kärsivällisyydestäsi."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-asema: <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-tallennustila"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Muokkaa"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Datankäyttövaroitus"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Käyttö & asetukset napauttamalla"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G-tietojen raja saavutettu"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-tietojen raja saavutettu"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 8b74244..034b291 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Options du téléphone"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Verrouillage de l\'écran"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Urgence"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bogue"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bogue"</string>
<string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme de courriel. Merci de patienter pendant la préparation du rapport de bogue. Cette opération peut prendre quelques instants."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Clé USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifier"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerte d\'utilisation des données"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Touch. pour aff. util. et param."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de données 2G-3G atteinte"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de données 4G atteinte"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 8c8c683..09b55d9 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Options du téléphone"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Verrouillage de l\'écran"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Éteindre"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Urgences"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Rapport de bug"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Créer un rapport de bug"</string>
<string name="bugreport_message" msgid="398447048750350456">"Cela permet de recueillir des informations concernant l\'état actuel de votre appareil. Ces informations sont ensuite envoyées sous forme d\'e-mail. Merci de patienter pendant la préparation du rapport de bug. Cette opération peut prendre quelques instants."</string>
@@ -995,7 +994,7 @@
<string name="noApplications" msgid="2991814273936504689">"Aucune application ne peut effectuer cette action."</string>
<string name="aerr_application" msgid="250320989337856518">"<xliff:g id="APPLICATION">%1$s</xliff:g> a cessé de fonctionner."</string>
<string name="aerr_process" msgid="6201597323218674729">"Le processus <xliff:g id="PROCESS">%1$s</xliff:g> a cessé de fonctionner."</string>
- <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> ne cesse de s\'arrêter."</string>
+ <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> s\'arrête systématiquement"</string>
<string name="aerr_process_repeated" msgid="6235302956890402259">"Le processus \"<xliff:g id="PROCESS">%1$s</xliff:g>\" ne cesse de s\'arrêter."</string>
<string name="aerr_restart" msgid="7581308074153624475">"Rouvrir l\'application"</string>
<string name="aerr_report" msgid="5371800241488400617">"Envoyer des commentaires"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Clé USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Mémoire de stockage USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifier"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerte de consommation des données"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Appuyez pour conso/paramètres."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de données 2G-3G atteinte"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de données 4G atteinte"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index f842df2..704667a 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opcións de teléfono"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Bloqueo da pantalla"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Apagar"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emerxencias"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Informe de erros"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Crear informe de erros"</string>
<string name="bugreport_message" msgid="398447048750350456">"Este informe recompilará información acerca do estado actual do teu dispositivo para enviala en forma de mensaxe de correo electrónico. O informe de erros tardará un pouco en completarse desde o seu inicio ata que estea preparado para enviarse, polo que che recomendamos que teñas paciencia."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidade USB de <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"almacenamento USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de datos"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Toca para uso e configuración."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Límite de datos de 2G-3G acadado"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Límite de datos de 4G acadado"</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 45038b0..cd3e7be 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ફોન વિકલ્પો"</string>
<string name="global_action_lock" msgid="2844945191792119712">"સ્ક્રીન લૉક"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"પાવર બંધ"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"કટોકટી"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"બગ રિપોર્ટ"</string>
<string name="bugreport_title" msgid="2667494803742548533">"બગ રિપોર્ટ લો"</string>
<string name="bugreport_message" msgid="398447048750350456">"આ, એક ઇ-મેઇલ સંદેશ તરીકે મોકલવા માટે, તમારા વર્તમાન ઉપકરણ સ્થિતિ વિશેની માહિતી એકત્રિત કરશે. એક બગ રિપોર્ટ પ્રારંભ કરીને તે મોકલવા માટે તૈયાર ન થઈ જાય ત્યાં સુધી તેમાં થોડો સમય લાગશે; કૃપા કરીને ધીરજ રાખો."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ડ્રાઇવ"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB સંગ્રહ"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"સંપાદિત કરો"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"ડેટા વપરાશ ચેતવણી"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"વપરાશ અને સેટિંગ્સ જોવા ટૅપ કરો."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ડેટા મર્યાદા પર પહોંચ્યાં"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ડેટા મર્યાદા સુધી પહોંચ્યાં"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 8a651bd..c8b3256 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"फ़ोन विकल्प"</string>
<string name="global_action_lock" msgid="2844945191792119712">"स्क्रीन लॉक"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"पावर बंद"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"आपातकाल"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"बग रिपोर्ट"</string>
<string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट प्राप्त करें"</string>
<string name="bugreport_message" msgid="398447048750350456">"ईमेल संदेश के रूप में भेजने के लिए, इसके द्वारा आपके डिवाइस की वर्तमान स्थिति के बारे में जानकारी एकत्र की जाएगी. बग रिपोर्ट प्रारंभ करने से लेकर भेजने के लिए तैयार होने तक कुछ समय लगेगा; कृपया धैर्य रखें."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB डिस्क"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB मेमोरी"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"संपादित करें"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा उपयोग की सूचना"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"उपयोग व सेटिंग देखने हेतु टैप करें."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा सीमा पूर्ण हो गई"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा सीमा पूर्ण हो गई"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 16a304f..3fc3346 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -216,8 +216,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opcije telefona"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Zaključavanje zaslona"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Isključi"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Hitno"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Izvješće o bugovima"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Izvješće o programskoj pogrešci"</string>
<string name="bugreport_message" msgid="398447048750350456">"Time će se prikupiti podaci o trenutačnom stanju vašeg uređaja koje ćete nam poslati u e-poruci. Za pripremu izvješća o programskoj pogrešci potrebno je nešto vremena pa vas molimo za strpljenje."</string>
@@ -1356,8 +1355,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB pogon"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozorenje o upotrebi podataka"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za upotrebu i postavke"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dost. ogr. 2G–3G prijenosa pod."</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dost. ogr. 4G prijenosa podataka"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index cbb72a7..825672b 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefonbeállítások"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Képernyő lezárása"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Kikapcsolás"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Vészhívás"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Programhiba bejelentése"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Hibajelentés készítése"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ezzel információt fog gyűjteni az eszköz jelenlegi állapotáról, amelyet a rendszer e-mailben fog elküldeni. Kérjük, legyen türelemmel, amíg a hibajelentés elkészül, és küldhető állapotba kerül."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-meghajtó"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-tár"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Szerkesztés"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Adathasználati értesítés"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Koppintson az adatokért."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-/3G-adatkorlát elérve"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G-adatkorlát elérve"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index ae83552a..7cdc9bb 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Հեռախոսի ընտրանքներ"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Էկրանի փական"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Անջատել"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Արտակարգ իրավիճակ"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Վրիպակի զեկույց"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Գրել սխալի զեկույց"</string>
<string name="bugreport_message" msgid="398447048750350456">"Սա տեղեկություններ կհավաքագրի ձեր սարքի առկա կարգավիճակի մասին և կուղարկի այն էլեկտրոնային նամակով: Որոշակի ժամանակ կպահանջվի վրիպակի մասին զեկուցելու պահից սկսած մինչ ուղարկելը: Խնդրում ենք փոքր-ինչ համբերատար լինել:"</string>
@@ -1059,8 +1058,8 @@
<string name="volume_icon_description_incall" msgid="8890073218154543397">"Զանգի ձայնի բարձրություն"</string>
<string name="volume_icon_description_media" msgid="4217311719665194215">"Մեդիա ձայնի բարձրություն"</string>
<string name="volume_icon_description_notification" msgid="7044986546477282274">"Ծանուցումների ձայնի ուժգնությունը"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"Լռելյայն զանգերանգ"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Լռելյայն զանգերանգ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_default" msgid="3789758980357696936">"Կանխադրված զանգերանգ"</string>
+ <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Կանխադրված զանգերանգ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"Ոչ մեկը"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Զանգերանգներ"</string>
<string name="ringtone_unknown" msgid="5477919988701784788">"Անհայտ զանգերանգ"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"USB սարքավար <xliff:g id="MANUFACTURER">%s</xliff:g>-ից"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB կրիչ"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Խմբագրել"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Տվյալների օգտագործման զգուշացում"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Հպեք և տեսեք օգտագործումը և կարգավորումները:"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G տվյալների սահմանաչափը սպառվել է"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G տվյալների սահմանաչափը սպառվել է"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index b6f6c4d..d655477 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opsi telepon"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Kunci layar"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Matikan daya"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Darurat"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Laporan bug"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan bug"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpulkan informasi status perangkat Anda saat ini, untuk dikirimkan sebagai pesan email. Harap bersabar, mungkin perlu waktu untuk memulai laporan bug hingga siap dikirim."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Penyimpanan USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Lansiran penggunaan data"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Ketuk untuk lihat penggunaan & setelan."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Batas data 2G-3G terlampaui"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Batas data 4G terlampaui"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 5cce18b..cd41f51 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Valkostir síma"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Skjálás"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Slökkva"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Neyðarsímtal"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Villutilkynning"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Útbúa villutilkynningu"</string>
<string name="bugreport_message" msgid="398447048750350456">"Þetta safnar upplýsingum um núverandi stöðu tækisins til að senda með tölvupósti. Það tekur smástund frá því villutilkynningin er ræst og þar til hún er tilbúin til sendingar – sýndu biðlund."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-drif frá <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-geymsla"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Breyta"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Viðvörun um gagnanotkun"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Ýttu fyrir uppl. og stillingar"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gagnahámarki 2G og 3G náð"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gagnahámarki 4G náð"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 13c17ce..ec7f8f9 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opzioni telefono"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Blocco schermo"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Spegni"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergenza"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Segnalazione di bug"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Apri segnalazione bug"</string>
<string name="bugreport_message" msgid="398447048750350456">"Verranno raccolte informazioni sullo stato corrente del dispositivo che saranno inviate sotto forma di messaggio email. Passerà un po\' di tempo prima che la segnalazione di bug aperta sia pronta per essere inviata; ti preghiamo di avere pazienza."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Unità USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Archivio USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Modifica"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Avviso sull\'utilizzo dei dati"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Tocca per uso e impostazioni."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite di dati 2G-3G raggiunto"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite di dati 4G raggiunto"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 87ec61a..290a31f 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -218,8 +218,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"אפשרויות טלפון"</string>
<string name="global_action_lock" msgid="2844945191792119712">"נעילת מסך"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"כיבוי"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"חירום"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"דיווח על באג"</string>
<string name="bugreport_title" msgid="2667494803742548533">"שלח דיווח על באג"</string>
<string name="bugreport_message" msgid="398447048750350456">"פעולה זו תאסוף מידע על מצב המכשיר הנוכחי שלך על מנת לשלוח אותו כהודעת אימייל. היא תימשך זמן קצר מרגע פתיחת דיווח הבאג ועד לשליחת ההודעה בפועל. אנא המתן בסבלנות."</string>
@@ -1382,8 +1381,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"כונן USB של <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"אחסון USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"ערוך"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"התראה לשימוש בנתונים"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"הקש כדי להציג נתוני שימוש והגדרות."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"הגעת למגבלת הנתונים של 2G-3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"הגעת למגבלת הנתונים של 4G"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 213c064..5305b1f 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"携帯電話オプション"</string>
<string name="global_action_lock" msgid="2844945191792119712">"画面ロック"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"電源を切る"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"緊急通報"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"バグレポート"</string>
<string name="bugreport_title" msgid="2667494803742548533">"バグレポートを取得"</string>
<string name="bugreport_message" msgid="398447048750350456">"現在の端末の状態に関する情報が収集され、その内容がメールで送信されます。バグレポートが開始してから送信可能な状態となるまでには多少の時間がかかりますのでご了承ください。"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g>製USBドライブ"</string>
<string name="storage_usb" msgid="3017954059538517278">"USBストレージ"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"編集"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"データ使用量に関する通知"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"タップして使用状況と設定を表示します。"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G~3Gデータの上限に達しました"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4Gデータの上限に達しました"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 315ff64..1e34347 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ტელეფონის პარამეტრები"</string>
<string name="global_action_lock" msgid="2844945191792119712">"ეკრანის დაბლოკვა"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"კვების გამორთვა"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"საგანგებო სამსახურები"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"ხარვეზის შესახებ ანგარიში"</string>
<string name="bugreport_title" msgid="2667494803742548533">"შექმენით შეცდომის ანგარიში"</string>
<string name="bugreport_message" msgid="398447048750350456">"იგი შეაგროვებს ინფორმაციას თქვენი მოწყობილობის ამჟამინდელი მდგომარეობის შესახებ, რათა ის ელფოსტის შეტყობინების სახით გააგზავნოს. ხარვეზის ანგარიშის მომზადებასა და შეტყობინების გაგზავნას გარკვეული დრო სჭირდება. გთხოვთ, მოითმინოთ."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB დისკი"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB მეხსიერება"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"რედაქტირება"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"მონაცემთა მოხმარების გაფრთხილება"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"შეეხეთ მოხმარებისა და პარამეტრების სანახავად."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G მონაცემთა ლიმიტი ამოიწურა"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G მონაცემთა ლიმიტი ამოიწურა"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 525fbee..9a227c4 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Телефон опциялары"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Экранды құлыптау"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Өшіру"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Төтенше жағдай"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Вирус туралы хабарлау"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Қате туралы есеп құру"</string>
<string name="bugreport_message" msgid="398447048750350456">"Құрылғының қазіргі күйі туралы ақпаратты жинап, электрондық хабармен жібереді. Есеп әзір болғанша біраз уақыт кетеді, шыдай тұрыңыз."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB дискі"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB жады"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгерту"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Деректер трафигі туралы ескерту"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Трафик пен параметрлерді көру үшін түртіңіз."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G деректер шегіне жеттіңіз"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G деректер шегіне жеттіңіз"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 014d844..2491f82 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ជម្រើសទូរស័ព្ទ"</string>
<string name="global_action_lock" msgid="2844945191792119712">"ចាក់សោអេក្រង់"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"បិទ"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"អាសន្ន"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"របាយការណ៍កំហុស"</string>
<string name="bugreport_title" msgid="2667494803742548533">"យករបាយការណ៍កំហុស"</string>
<string name="bugreport_message" msgid="398447048750350456">"វានឹងប្រមូលព័ត៌មានអំពីស្ថានភាពឧបករណ៍របស់អ្នក ដើម្បីផ្ញើជាសារអ៊ីមែល។ វានឹងចំណាយពេលតិចពីពេលចាប់ផ្ដើមរបាយការណ៍រហូតដល់ពេលវារួចរាល់ដើម្បីផ្ញើ សូមអត់ធ្មត់។"</string>
@@ -1332,8 +1331,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"ឧបករណ៍ផ្ទុក USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"ឧបករណ៍ផ្ទុកយូអេសប៊ី"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"កែសម្រួល"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"ការព្រមានអំពីការប្រើទិន្នន័យ"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"ប៉ះដើម្បីមើលការប្រើប្រាស់ និងការកំណត់"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"បានដល់ដែនកំណត់ទិន្នន័យ 2G-3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"បានដល់ដែនកំណត់ទិន្នន័យ 4G"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index ab60289..b8c90d7 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ಫೋನ್ ಆಯ್ಕೆಗಳು"</string>
<string name="global_action_lock" msgid="2844945191792119712">"ಸ್ಕ್ರೀನ್ ಲಾಕ್"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"ಪವರ್ ಆಫ್ ಮಾಡು"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"ತುರ್ತು"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"ದೋಷದ ವರದಿ"</string>
<string name="bugreport_title" msgid="2667494803742548533">"ದೋಷ ವರದಿ ರಚಿಸಿ"</string>
<string name="bugreport_message" msgid="398447048750350456">"ನಿಮ್ಮ ಸಾಧನದ ಪ್ರಸ್ತುತ ಸ್ಥಿತಿಯ ಕುರಿತು ಮಾಹಿತಿಯನ್ನು ಸಂಗ್ರಹಿಸಿಕೊಳ್ಳುವುದರ ಜೊತೆ ಇ-ಮೇಲ್ ರೂಪದಲ್ಲಿ ನಿಮಗೆ ರವಾನಿಸುತ್ತದೆ. ಇದು ದೋಷ ವರದಿಯನ್ನು ಪ್ರಾರಂಭಿಸಿದ ಸಮಯದಿಂದ ಅದನ್ನು ಕಳುಹಿಸುವವರೆಗೆ ಸ್ವಲ್ಪ ಸಮಯವನ್ನು ತೆಗೆದುಕೊಳ್ಳುತ್ತದೆ; ದಯವಿಟ್ಟು ತಾಳ್ಮೆಯಿಂದಿರಿ."</string>
@@ -816,9 +815,9 @@
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"space"</string>
<string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
<string name="menu_delete_shortcut_label" msgid="3658178007202748164">"ಅಳಿಸು"</string>
- <string name="search_go" msgid="8298016669822141719">"ಹುಡುಕು"</string>
+ <string name="search_go" msgid="8298016669822141719">"ಹುಡುಕಿ"</string>
<string name="search_hint" msgid="1733947260773056054">"ಹುಡುಕಿ…"</string>
- <string name="searchview_description_search" msgid="6749826639098512120">"ಹುಡುಕು"</string>
+ <string name="searchview_description_search" msgid="6749826639098512120">"ಹುಡುಕಿ"</string>
<string name="searchview_description_query" msgid="5911778593125355124">"ಪ್ರಶ್ನೆಯನ್ನು ಹುಡುಕಿ"</string>
<string name="searchview_description_clear" msgid="1330281990951833033">"ಪ್ರಶ್ನೆಯನ್ನು ತೆರವುಗೊಳಿಸು"</string>
<string name="searchview_description_submit" msgid="2688450133297983542">"ಪ್ರಶ್ನೆಯನ್ನು ಸಲ್ಲಿಸು"</string>
@@ -1212,7 +1211,7 @@
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"ಝೂಮ್ ನಿಯಂತ್ರಿಸಲು ಎರಡು ಬಾರಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="gadget_host_error_inflating" msgid="4882004314906466162">"ವಿಜೆಟ್ ಸೇರಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ."</string>
<string name="ime_action_go" msgid="8320845651737369027">"ಹೋಗು"</string>
- <string name="ime_action_search" msgid="658110271822807811">"ಹುಡುಕು"</string>
+ <string name="ime_action_search" msgid="658110271822807811">"ಹುಡುಕಿ"</string>
<string name="ime_action_send" msgid="2316166556349314424">"ಕಳುಹಿಸು"</string>
<string name="ime_action_next" msgid="3138843904009813834">"ಮುಂದೆ"</string>
<string name="ime_action_done" msgid="8971516117910934605">"ಮುಗಿದಿದೆ"</string>
@@ -1270,8 +1269,8 @@
<string name="share" msgid="1778686618230011964">"ಹಂಚು"</string>
<string name="find" msgid="4808270900322985960">"ಹುಡುಕಿ"</string>
<string name="websearch" msgid="4337157977400211589">"ವೆಬ್ ಹುಡುಕಾಟ"</string>
- <string name="find_next" msgid="5742124618942193978">"ಮುಂದಿನದನ್ನು ಹುಡುಕು"</string>
- <string name="find_previous" msgid="2196723669388360506">"ಹಿಂದಿನದನ್ನು ಹುಡುಕು"</string>
+ <string name="find_next" msgid="5742124618942193978">"ಮುಂದಿನದನ್ನು ಹುಡುಕಿ"</string>
+ <string name="find_previous" msgid="2196723669388360506">"ಹಿಂದಿನದನ್ನು ಹುಡುಕಿ"</string>
<string name="gpsNotifTicker" msgid="5622683912616496172">"<xliff:g id="NAME">%s</xliff:g> ಅವರಿಂದ ಸ್ಥಾನ ವಿನಂತಿ"</string>
<string name="gpsNotifTitle" msgid="5446858717157416839">"ಸ್ಥಾನ ವಿನಂತಿ"</string>
<string name="gpsNotifMessage" msgid="1374718023224000702">"<xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>) ಅವರಿಂದ ವಿನಂತಿಸಲಾಗಿದೆ"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ಡ್ರೈವ್"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB ಸಂಗ್ರಹಣೆ"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"ಎಡಿಟ್"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"ಡೇಟಾ ಬಳಕೆ ಎಚ್ಚರಿಕೆ"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"ಬಳಕೆ ಮತ್ತು ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ"</string>
@@ -1652,7 +1650,7 @@
<string name="language_picker_section_suggested" msgid="8414489646861640885">"ಸೂಚಿತ ಭಾಷೆ"</string>
<string name="language_picker_section_all" msgid="3097279199511617537">"ಎಲ್ಲಾ ಭಾಷೆಗಳು"</string>
<string name="region_picker_section_all" msgid="8966316787153001779">"ಎಲ್ಲಾ ಪ್ರದೇಶಗಳು"</string>
- <string name="locale_search_menu" msgid="2560710726687249178">"ಹುಡುಕು"</string>
+ <string name="locale_search_menu" msgid="2560710726687249178">"ಹುಡುಕಿ"</string>
<string name="work_mode_off_title" msgid="8954725060677558855">"ಕೆಲಸದ ಮೋಡ್ ಆಫ್ ಆಗಿದೆ"</string>
<string name="work_mode_off_message" msgid="3286169091278094476">"ಅಪ್ಲಿಕೇಶನ್ಗಳು, ಹಿನ್ನೆಲೆ ಸಿಂಕ್ ಮತ್ತು ಇತರ ಸಂಬಂಧಿತ ವೈಶಿಷ್ಟ್ಯಗಳು ಸೇರಿದಂತೆ ನಿಮ್ಮ ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಕಾರ್ಯನಿರ್ವಹಿಸಲು ಅನುಮತಿಸಿ."</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"ಆನ್ ಮಾಡು"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 5d226a6..4191865 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"휴대전화 옵션"</string>
<string name="global_action_lock" msgid="2844945191792119712">"화면 잠금"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"종료"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"긴급 전화"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"버그 신고"</string>
<string name="bugreport_title" msgid="2667494803742548533">"버그 신고"</string>
<string name="bugreport_message" msgid="398447048750350456">"현재 기기 상태에 대한 정보를 수집하여 이메일 메시지로 전송합니다. 버그 신고를 시작하여 전송할 준비가 되려면 약간 시간이 걸립니다."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 드라이브"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB 저장소"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"수정"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"데이터 사용 알림"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"사용량 및 설정을 보려면 탭하세요."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G 데이터 한도에 도달함"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G 데이터 한도에 도달함"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 99bba3a7..7a48ae5 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Телефон мүмкүнчүлүктөрү"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Экран кулпусу"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Кубатын өчүрүү"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Тез жардам"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Ката тууралуу билдирүү"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Ката тууралуу билдирүү түзүү"</string>
<string name="bugreport_message" msgid="398447048750350456">"Бул сиздин түзмөгүңүздүн учурдагы абалын эмейл билдирүүсү катары жөнөтүш максатында маалымат чогултат. Ката тууралуу билдирүү түзүлүп башталып, жөнөтүлгөнгө чейин бир аз убакыт керек болот; сураныч, бир аз күтө туруңуз."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB түзмөгү"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB эстутуму"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Өзгөртүү"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Дайындарды колдонууну чектөө"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Колдонулушун жана жөндөөлөрүн көрүү үчүн таптаңыз."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G дайындар чегине жетти"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G дайындар чегине жетти"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 9762f26..26c9053 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ໂຕເລືອກໂທລະສັບ"</string>
<string name="global_action_lock" msgid="2844945191792119712">"ລັອກໜ້າຈໍ"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"ປິດ"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"ສຸກເສີນ"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"ລາຍງານຂໍ້ຜິດພາດ"</string>
<string name="bugreport_title" msgid="2667494803742548533">"ໃຊ້ລາຍງານຂໍ້ບົກພ່ອງ"</string>
<string name="bugreport_message" msgid="398447048750350456">"ນີ້ຈະເປັນການເກັບກຳຂໍ້ມູນກ່ຽວກັບ ສະຖານະປັດຈຸບັນຂອງອຸປະກອນທ່ານ ເພື່ອສົ່ງເປັນຂໍ້ຄວາມທາງອີເມວ. ມັນຈະໃຊ້ເວລາໜ້ອຍນຶ່ງ ໃນການເລີ່ມຕົ້ນການລາຍງານຂໍ້ຜິດພາດ ຈົນກວ່າຈະພ້ອມທີ່ຈະສົ່ງໄດ້, ກະລຸນາລໍຖ້າ."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ດຣ້າຍ"</string>
<string name="storage_usb" msgid="3017954059538517278">"ບ່ອນຈັດເກັບຂໍ້ມູນ USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"ແກ້ໄຂ"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"ແຈ້ງເຕືອນການໃຊ້ອິນເຕີເນັດ"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"ແຕະເພື່ອເບິ່ງການນຳໃຊ້ ແລະ ການຕັ້ງຄ່າ."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"ໃຊ້ຂໍ້ມູນ 2G-3G ຮອດຈຳນວນທີ່ຈຳກັດແລ້ວ"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"ໃຊ້ຂໍ້ມູນ 4G ຮອດຈຳນວນທີ່ຈຳກັດແລ້ວ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 6446066..a2f5eb8 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -218,8 +218,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefono parinktys"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Ekrano užraktas"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Išjungiamas maitinimas"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Skambutis pagalbos numeriu"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Pranešimas apie riktą"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Pranešti apie riktą"</string>
<string name="bugreport_message" msgid="398447048750350456">"Bus surinkta informacija apie dabartinę įrenginio būseną ir išsiųsta el. pašto pranešimu. Šiek tiek užtruks, kol pranešimas apie riktą bus paruoštas siųsti; būkite kantrūs."</string>
@@ -1382,8 +1381,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"„<xliff:g id="MANUFACTURER">%s</xliff:g>“ atmintukas"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB atmintis"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Redaguoti"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Duomenų naudojimo įspėjimas"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Pal. ir perž. naud. i. bei nust."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Pasiektas 2G–3G duomenų apribojimas"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Pasiektas 4G duomenų apribojimas"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index b0e7af5..6ea7d6b 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -216,8 +216,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Tālruņa opcijas"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Ekrāna bloķētājs"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Strāvas padeve ir izslēgta."</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Ārkārtas"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Kļūdu ziņojums"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Kļūdu ziņojuma sagatavošana"</string>
<string name="bugreport_message" msgid="398447048750350456">"Veicot šo darbību, tiks apkopota informācija par jūsu ierīces pašreizējo stāvokli un nosūtīta e-pasta ziņojuma veidā. Kļūdu ziņojuma pabeigšanai un nosūtīšanai var būt nepieciešams laiks. Lūdzu, esiet pacietīgs."</string>
@@ -1356,8 +1355,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disks"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB atmiņa"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediģēt"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Brīdinājums par datu lietojumu"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Piesk., lai sk. lietoj. un iest."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Sasniegts 2G-3G datu ierobež."</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Sasniegts 4G datu ierobežojums"</string>
diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
index d638b89..422f7c9 100644
--- a/core/res/res/values-mcc302-mnc220/config.xml
+++ b/core/res/res/values-mcc302-mnc220/config.xml
@@ -21,14 +21,6 @@
for different hardware and product builds. -->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string-array translatable="false" name="config_operatorConsideredNonRoaming">
- <item>302370</item>
- <item>302610</item>
- <item>302660</item>
- <item>302720</item>
- <item>302780</item>
- </string-array>
-
<integer name="config_mobile_mtu">1410</integer>
<!-- String containing the apn value for tethering. May be overriden by secure settings
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index 714b312..439f1d6 100755
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -48,9 +48,6 @@
provisioning, availability etc -->
<bool name="config_carrier_vt_available">true</bool>
- <!-- Flag specifying whether VoLTE availability is based on provisioning -->
- <bool name="config_carrier_volte_provisioned">true</bool>
-
<bool name="config_auto_attach_data_on_creation">false</bool>
<!-- Flag indicating whether strict threshold is used, or lenient threshold is used,
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index a47a483..3f228203 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Опции на телефон"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Заклучи екран"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Исклучи"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Итен случај"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Извештај за грешка"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Земи извештај за грешки"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ова ќе собира информации за моменталната состојба на вашиот уред, за да ги испрати како порака по е-пошта. Тоа ќе одземе малку време почнувајќи од извештајот за грешки додека не се подготви за праќање; бидете трпеливи."</string>
@@ -1332,8 +1331,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> УСБ-меморија"</string>
<string name="storage_usb" msgid="3017954059538517278">"УСБ меморија"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Уреди"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Известување за потрошен сообраќај"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Допрете за употреба и поставки."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Постигна лимит за 2G-3G податоци"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Постигнат лимит за 4G податоци"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index eaa8deb..beb6a67 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ഫോൺ ഓപ്ഷനുകൾ"</string>
<string name="global_action_lock" msgid="2844945191792119712">"സ്ക്രീൻ ലോക്ക്"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"പവർ ഓഫാക്കുക"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"അടിയന്തിരാവശ്യം"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"ബഗ് റിപ്പോർട്ട്"</string>
<string name="bugreport_title" msgid="2667494803742548533">"ബഗ് റിപ്പോർട്ട് എടുക്കുക"</string>
<string name="bugreport_message" msgid="398447048750350456">"ഒരു ഇമെയിൽ സന്ദേശമായി അയയ്ക്കുന്നതിന്, ഇത് നിങ്ങളുടെ നിലവിലെ ഉപകരണ നിലയെക്കുറിച്ചുള്ള വിവരങ്ങൾ ശേഖരിക്കും. ബഗ് റിപ്പോർട്ട് ആരംഭിക്കുന്നതിൽ നിന്ന് ഇത് അയയ്ക്കാനായി തയ്യാറാകുന്നതുവരെ അൽപ്പസമയമെടുക്കും; ക്ഷമയോടെ കാത്തിരിക്കുക."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ഡ്രൈവ്"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB സ്റ്റോറേജ്"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"എഡിറ്റുചെയ്യുക"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"ഡാറ്റാ ഉപയോഗ മുന്നറിയിപ്പ്"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"ഉപയോഗവും ക്രമീകരണവും കാണാൻ ടാപ്പുചെയ്യുക."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ഡാറ്റ പരിധിയിലെത്തി"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ഡാറ്റ പരിധിയിലെത്തി"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 79dbc68..bd80f84 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Утасны сонголтууд"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Дэлгэцний түгжээ"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Унтраах"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Яаралтай тусламж"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Алдаа мэдээллэх"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Согог репорт авах"</string>
<string name="bugreport_message" msgid="398447048750350456">"Энэ таны төхөөрөмжийн одоогийн статусын талаарх мэдээллийг цуглуулах ба имэйл мессеж болгон илгээнэ. Алдааны мэдэгдлээс эхэлж илгээхэд бэлэн болоход хэсэг хугацаа зарцуулагдана тэвчээртэй байна уу."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB диск"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB сан"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Засах"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Дата ашиглалтын сануулга"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Хэрэглээ, тохиргоог харах бол товш."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G дата хязгаарт хүрсэн"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G дата хязгаарт хүрсэн"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index fce64c4..758b21b 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"फोन पर्याय"</string>
<string name="global_action_lock" msgid="2844945191792119712">"स्क्रीन लॉक"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"बंद"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"आणीबाणी"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"दोष अहवाल"</string>
<string name="bugreport_title" msgid="2667494803742548533">"दोष अहवाल घ्या"</string>
<string name="bugreport_message" msgid="398447048750350456">"ई-मेल संदेश म्हणून पाठविण्यासाठी, हे आपल्या वर्तमान डिव्हाइस स्थितीविषयी माहिती संकलित करेल. दोष अहवाल प्रारंभ करण्यापासून तो पाठविण्यापर्यंत थोडा वेळ लागेल; कृपया धीर धरा."</string>
@@ -1076,7 +1075,7 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्कवर साइन इन करा"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"वाय-फाय मध्ये इंटरनेट प्रवेश नाही"</string>
+ <string name="wifi_no_internet" msgid="8451173622563841546">"वाय-फायवरून इंटरनेटवर प्रवेश नाही"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"पर्यायांसाठी टॅप करा"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
<string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेट प्रवेश नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरतो. शुल्क लागू शकतील."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ड्राइव्ह"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB संचयन"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"संपादित करा"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा वापर सूचना"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"वापर आणि सेटिंग्ज पाहण्यासाठी टॅप करा."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा मर्यादा गाठली"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा मर्यादा गाठली"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 53181ce..60330e5 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Pilihan telefon"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Kunci skrin"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Matikan kuasa"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Kecemasan"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Laporan pepijat"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan pepijat"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpul maklumat tentang keadaan peranti semasa anda untuk dihantarkan sebagai mesej e-mel. Harap bersabar, mungkin perlu sedikit masa untuk memulakan laporan sehingga siap untuk dihantar."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Pemacu USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Storan USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Edit"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Makluman penggunaan data"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Ketik utk lihat p\'gunaan & ttpn."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Mencapai had data 2G-3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Mencapai had data 4G"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 987d764..c18ff7f 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ဖုန်းဆိုင်ရာရွေးချယ်မှုများ"</string>
<string name="global_action_lock" msgid="2844945191792119712">"ဖုန်းမျက်နှာပြင်အား သော့ချရန်"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"ပါဝါပိတ်ရန်"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"အရေးပေါ်"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်း"</string>
<string name="bugreport_title" msgid="2667494803742548533">"အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်းအား ယူရန်"</string>
<string name="bugreport_message" msgid="398447048750350456">"သင့်ရဲ့ လက်ရှိ စက်အခြေအနေ အချက်အလက်များကို အီးမေးလ် အနေဖြင့် ပေးပို့ရန် စုဆောင်းပါမည်။ အမှားရှာဖွေပြင်ဆင်မှုမှတ်တမ်းမှ ပေးပို့ရန် အသင့်ဖြစ်သည်အထိ အချိန် အနည်းငယ်ကြာမြင့်မှာ ဖြစ်သဖြင့် သည်းခံပြီး စောင့်ပါရန်"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ဒရိုက်ဗ်"</string>
<string name="storage_usb" msgid="3017954059538517278">"USBဖြင့် သိမ်းဆည်း"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"ပြင်ဆင်ရန်"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"ဒေတာအသုံးပြုမှုသတိပေးချက်"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"အသုံးပြုမှုနှင့် ဆက်တင်များကိုကြည့်ရန် တို့ပါ။"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ဒေတာ ကန့်သတ်ချက် ပြည့်မီသွားပြီ"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ဒေတာ ကန့်သတ်ချက် ပြည့်မီသွားပြီ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index c807c14..9ff7803 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefoninnstillinger"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Lås skjermen"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Slå av"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Nødssituasjon"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Feilrapport"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Utfør feilrapport"</string>
<string name="bugreport_message" msgid="398447048750350456">"Informasjon om tilstanden til enheten din samles inn og sendes som en e-post. Det tar litt tid fra du starter feilrapporten til e-posten er klar, så vær tålmodig."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-stasjon"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Rediger"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Varsel om databruk"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Trykk for å se bruken og innstillingene."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Datagrensen for 2G-3G er nådd"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Datagrensen for 4G er nådd"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 65d3b69..e039927 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"फोन विकल्पहरू"</string>
<string name="global_action_lock" msgid="2844945191792119712">"स्क्रिन बन्द"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"बन्द गर्नुहोस्"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"आपतकालीन"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"बग रिपोर्ट"</string>
<string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट लिनुहोस्"</string>
<string name="bugreport_message" msgid="398447048750350456">"एउटा इमेल सन्देशको रूपमा पठाउनलाई यसले तपाईँको हालैको उपकरणको अवस्थाको बारेमा सूचना जम्मा गर्ने छ। बग रिपोर्ट सुरु गरेदेखि पठाउन तयार नभएसम्म यसले केही समय लिन्छ; कृपया धैर्य गर्नुहोस्।"</string>
@@ -1336,8 +1335,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ड्राइभ"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB भण्डारण"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"सम्पादन गर्नुहोस्"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"डेटा प्रयोग बारे सतर्कता"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"प्रयोग र सेटिङहरू हेर्न ट्याप गर्नुहोस्।"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G डेटा सीमा पुग्यो"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G डेटा सीमा पुग्यो"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 69a4074..13218b7 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefoonopties"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Schermvergrendeling"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Uitschakelen"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Noodgeval"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Foutenrapport"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Foutenrapport genereren"</string>
<string name="bugreport_message" msgid="398447048750350456">"Hiermee worden gegevens over de huidige status van je apparaat verzameld en als e-mail verzonden. Wanneer u een foutenrapport start, duurt het even voordat het kan worden verzonden. Even geduld alstublieft."</string>
@@ -238,7 +237,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"Spraakassistent"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"Nu vergrendelen"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999 +"</string>
- <string name="notification_hidden_text" msgid="1135169301897151909">"Inhoud verborgen"</string>
+ <string name="notification_hidden_text" msgid="1135169301897151909">"Content verborgen"</string>
<string name="notification_hidden_by_policy_text" msgid="9004631276932584600">"Content verborgen op basis van beleid"</string>
<string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
@@ -262,12 +261,12 @@
<string name="permgroupdesc_phone" msgid="6234224354060641055">"bellen en telefoontjes beheren"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"Lichaamssensoren"</string>
<string name="permgroupdesc_sensors" msgid="7147968539346634043">"toegang krijgen tot sensorgegevens over je vitale functies"</string>
- <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Inhoud van vensters ophalen"</string>
- <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"De inhoud inspecteren van een venster waarmee je interactie hebt."</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Content van vensters ophalen"</string>
+ <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"De content inspecteren van een venster waarmee je interactie hebt."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"\'Verkennen via aanraking\' inschakelen"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Aangetikte items worden hardop benoemd en het scherm kan worden verkend door middel van gebaren."</string>
<string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Verbeterde internettoegankelijkheid inschakelen"</string>
- <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Er kunnen scripts worden geïnstalleerd om app-inhoud toegankelijker te maken."</string>
+ <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Er kunnen scripts worden geïnstalleerd om app-content toegankelijker te maken."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Tekst observeren die u typt"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Omvat persoonlijke gegevens zoals creditcardnummers en wachtwoorden."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Schermvergroting bedienen"</string>
@@ -297,9 +296,9 @@
<string name="permlab_sendSms" msgid="7544599214260982981">"sms\'jes verzenden en bekijken"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Hiermee kan de app sms-berichten verzenden. Dit kan tot onverwachte kosten leiden. Schadelijke apps kunnen u geld kosten doordat ze zonder je bevestiging berichten kunnen verzenden."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"je tekstberichten (SMS of MMS) lezen"</string>
- <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tablet of simkaart. De app kan alle sms-berichten lezen, ongeacht inhoud of vertrouwelijkheid."</string>
- <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tv of simkaart. De app kan alle sms-berichten lezen, ongeacht inhoud of vertrouwelijkheid."</string>
- <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je telefoon of simkaart. De app kan alle sms-berichten lezen, ongeacht inhoud of vertrouwelijkheid."</string>
+ <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tablet of simkaart. De app kan alle sms-berichten lezen, ongeacht content of vertrouwelijkheid."</string>
+ <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je tv of simkaart. De app kan alle sms-berichten lezen, ongeacht content of vertrouwelijkheid."</string>
+ <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Hiermee kan de app sms-berichten lezen die zijn opgeslagen op je telefoon of simkaart. De app kan alle sms-berichten lezen, ongeacht content of vertrouwelijkheid."</string>
<string name="permlab_receiveWapPush" msgid="5991398711936590410">"tekstberichten (WAP) ontvangen"</string>
<string name="permdesc_receiveWapPush" msgid="748232190220583385">"Hiermee kan de app WAP-berichten ontvangen en verwerken. Dit betekent dat de app berichten die naar je apparaat zijn verzonden, kan bijhouden of verwijderen zonder deze aan u weer te geven."</string>
<string name="permlab_getTasks" msgid="6466095396623933906">"actieve apps ophalen"</string>
@@ -461,12 +460,12 @@
<string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Hiermee kan een app de synchronisatie-instellingen aanpassen voor een account. Deze toestemming kan bijvoorbeeld worden gebruikt om synchronisatie van de app Personen in te schakelen voor een account."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"synchronisatiestatistieken lezen"</string>
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"Hiermee kan een app de synchronisatiestatistieken voor een account lezen, inclusief de geschiedenis van synchronisatie-activiteiten en hoeveel gegevens zijn gesynchroniseerd."</string>
- <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"de inhoud van je USB-opslag lezen"</string>
- <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"de inhoud van je SD-kaart lezen"</string>
- <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"De app toestaan de inhoud van je USB-opslag te lezen."</string>
- <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"De app toestaan de inhoud van je SD-kaart te lezen."</string>
- <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"de inhoud van je USB-opslag aanpassen of verwijderen"</string>
- <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"de inhoud van je SD-kaart aanpassen of verwijderen"</string>
+ <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"de content van je USB-opslag lezen"</string>
+ <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"de content van je SD-kaart lezen"</string>
+ <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"De app toestaan de content van je USB-opslag te lezen."</string>
+ <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"De app toestaan de content van je SD-kaart te lezen."</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"de content van je USB-opslag aanpassen of verwijderen"</string>
+ <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"de content van je SD-kaart aanpassen of verwijderen"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Hiermee kan de app schrijven naar de USB-opslag."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Hiermee kan de app schrijven naar de SD-kaart."</string>
<string name="permlab_use_sip" msgid="2052499390128979920">"SIP-oproepen plaatsen/ontvangen"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB-drive"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-opslag"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Bewerken"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Melding voor datagebruik"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Tik voor gebruik en instellingen"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Gegevenslimiet van 2G-3G bereikt"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Gegevenslimiet van 4G bereikt"</string>
@@ -1529,7 +1527,7 @@
<string name="mediasize_unknown_portrait" msgid="3088043641616409762">"Onbekend portret"</string>
<string name="mediasize_unknown_landscape" msgid="4876995327029361552">"Onbekend landschap"</string>
<string name="write_fail_reason_cancelled" msgid="7091258378121627624">"Geannuleerd"</string>
- <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fout bij schrijven van inhoud"</string>
+ <string name="write_fail_reason_cannot_write" msgid="8132505417935337724">"Fout bij schrijven van content"</string>
<string name="reason_unknown" msgid="6048913880184628119">"onbekend"</string>
<string name="reason_service_unavailable" msgid="7824008732243903268">"Afdrukservice niet ingeschakeld"</string>
<string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g>-service geïnstalleerd"</string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index ac80d51..d3476aa 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ਫੋਨ ਚੋਣਾਂ"</string>
<string name="global_action_lock" msgid="2844945191792119712">"ਸਕ੍ਰੀਨ ਲੌਕ"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"ਪਾਵਰ ਬੰਦ"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"ਸੰਕਟਕਾਲ"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"ਬਗ ਰਿਪੋਰਟ"</string>
<string name="bugreport_title" msgid="2667494803742548533">"ਬਗ ਰਿਪੋਰਟ ਲਓ"</string>
<string name="bugreport_message" msgid="398447048750350456">"ਇਹ ਇੱਕ ਈ-ਮੇਲ ਸੁਨੇਹਾ ਭੇਜਣ ਲਈ, ਤੁਹਾਡੀ ਵਰਤਮਾਨ ਡੀਵਾਈਸ ਬਾਰੇ ਜਾਣਕਾਰੀ ਇਕੱਤਰ ਕਰੇਗਾ। ਬਗ ਰਿਪੋਰਟ ਸ਼ੁਰੂ ਕਰਨ ਵਿੱਚ ਥੋੜ੍ਹਾ ਸਮਾਂ ਲੱਗੇਗਾ ਜਦੋਂ ਤੱਕ ਇਹ ਭੇਜੇ ਜਾਣ ਲਈ ਤਿਆਰ ਨਾ ਹੋਵੇ, ਕਿਰਪਾ ਕਰਕੇ ਧੀਰਜ ਰੱਖੋ।"</string>
@@ -364,7 +363,7 @@
<string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"ਐਪ ਨੂੰ ਤੁਹਾਡਾ ਅਨੁਮਾਨਿਤ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਨੈੱਟਵਰਕ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸਰੋਤ ਵਰਤਦੇ ਹੋਏ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾਵਾਂ ਰਾਹੀਂ ਪ੍ਰਾਪਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ ਜਿਵੇਂ ਸੈਲ ਟਾਵਰ ਅਤੇ Wi-Fi. ਇਹ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾਵਾਂ ਚਾਲੂ ਅਤੇ ਐਪ ਨੂੰ ਉਹਨਾਂ ਨੂੰ ਵਰਤਣ ਲਈ ਤੁਹਾਡੀ ਡੀਵਾਈਸ ਤੇ ਹੋਣੀਆਂ ਚਾਹੀਦੀਆਂ ਹਨ। ਐਪਸ ਇਸਦੀ ਵਰਤੋਂ ਇਹ ਅਨੁਮਾਨ ਲਗਾਉਣ ਲਈ ਕਰ ਸਕਦੇ ਹਨ ਕਿ ਤੁਸੀਂ ਕਿੱਥੇ ਹੋ।"</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ਆਪਣੀਆਂ ਔਡੀਓ ਸੈਟਿੰਗਾਂ ਬਦਲੋ"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ਔਪ ਨੂੰ ਗਲੋਬਲ ਔਡੀਓ ਸੈਟਿੰਗਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ ਜਿਵੇਂ ਵੌਲਿਊਮ ਅਤੇ ਆਊਟਪੁਟ ਲਈ ਕਿਹੜਾ ਸਪੀਕਰ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ।"</string>
- <string name="permlab_recordAudio" msgid="3876049771427466323">"ਔਡੀਓ ਰਿਕਾਰਡ ਕਰੋ"</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ"</string>
<string name="permdesc_recordAudio" msgid="4906839301087980680">"ਐਪ ਨੂੰ ਮਾਈਕ੍ਰੋਫੋਨ ਨਾਲ ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_sim_communication" msgid="2935852302216852065">"SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜੋ"</string>
<string name="permdesc_sim_communication" msgid="5725159654279639498">"ਐਪ ਨੂੰ SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਬਹੁਤ ਘਾਤਕ ਹੈ।"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ਡ੍ਰਾਇਵ"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB ਸਟੋਰੇਜ"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"ਸੰਪਾਦਿਤ ਕਰੋ"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"ਡੈਟਾ ਵਰਤੋਂ ਚੇਤਾਵਨੀ"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"ਵਰਤੋਂ ਅਤੇ ਸੈਟਿੰਗਾਂ ਨੂੰ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋਈ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 8698846..a7571ef 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -218,8 +218,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opcje telefonu"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Blokada ekranu"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Wyłącz"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Alarmowy"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Zgłoszenie błędu"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Zgłoś błąd"</string>
<string name="bugreport_message" msgid="398447048750350456">"Informacje o bieżącym stanie urządzenia zostaną zebrane i wysłane e-mailem. Przygotowanie zgłoszenia błędu do wysłania chwilę potrwa, więc zachowaj cierpliwość."</string>
@@ -1382,8 +1381,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Dysk USB (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
<string name="storage_usb" msgid="3017954059538517278">"Nośnik USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Edytuj"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alert transmisji danych"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Kliknij, by wyświetlić użycie i ustawienia."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Osiągnięto limit danych 2G/3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Osiągnięto limit danych 4G"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 74b7519..24265ee 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Bloquear tela"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de bugs"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
<string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de dados"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver uso e config."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G-3G atingido"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 58e4097..6270210 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Bloqueio de ecrã"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de erros"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Criar relatório de erros"</string>
<string name="bugreport_message" msgid="398447048750350456">"Será recolhida informação sobre o estado atual do seu dispositivo a enviar através de uma mensagem de email. Demorará algum tempo até que o relatório de erro esteja pronto para ser enviado. Aguarde um pouco."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Unidade USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de utilização de dados"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver a utilização e definições"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G/3G atingido"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 74b7519..24265ee 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opções do telefone"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Bloquear tela"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Desligar"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergência"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Relatório de bugs"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Obter relatório de bugs"</string>
<string name="bugreport_message" msgid="398447048750350456">"Isto coletará informações sobre o estado atual do dispositivo para enviá-las em uma mensagem de e-mail. Após iniciar o relatório de bugs, será necessário aguardar algum tempo até que esteja pronto para ser enviado."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Drive USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Armazenamento USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Editar"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerta de uso de dados"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Toque para ver uso e config."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Limite de dados 2G-3G atingido"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Limite de dados 4G atingido"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 5011363..29c0a59 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -216,8 +216,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opțiuni telefon"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Blocați ecranul"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Opriți alimentarea"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Urgență"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Raport despre erori"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Executați un raport despre erori"</string>
<string name="bugreport_message" msgid="398447048750350456">"Acest raport va colecta informații despre starea actuală a dispozitivului, pentru a le trimite într-un e-mail. Aveți răbdare după pornirea raportului despre erori până când va fi gata de trimis."</string>
@@ -1356,8 +1355,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Unitate USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Dsipozitiv de stocare USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Editați"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alertă pentru utilizarea datelor"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Atingeți ca să vedeți utilizarea/setările."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Ați atins limita de date 2G-3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Ați atins limita de date 4G"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 7850cd8..ed6c798 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -218,8 +218,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Параметры телефона"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Блокировка экрана"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Отключить питание"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Экстренный вызов"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Отчет об ошибке"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Отчет об ошибке"</string>
<string name="bugreport_message" msgid="398447048750350456">"Информация о текущем состоянии вашего устройства будет собрана и отправлена по электронной почте. Подготовка отчета займет некоторое время."</string>
@@ -1382,8 +1381,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-накопитель <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-накопитель"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Изменить"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Лимит на передачу данных"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Нажмите, чтобы проверить трафик и настройки."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Достигнут лимит трафика 2G/3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Достигнут лимит трафика 4G"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 7cab897..91d5bbe 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"දුරකථන විකල්ප"</string>
<string name="global_action_lock" msgid="2844945191792119712">"තිර අගුල"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"බලය අක්රිය කරන්න"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"හදිසි"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"දෝෂ වර්තාව"</string>
<string name="bugreport_title" msgid="2667494803742548533">"දෝෂ වාර්තාවක් ගන්න"</string>
<string name="bugreport_message" msgid="398447048750350456">"ඊ-තැපැල් පණිවිඩයක් ලෙස යැවීමට මෙය ඔබගේ වත්මන් උපාංග තත්වය ගැන තොරතුරු එකතු කරනු ඇත. දෝෂ වාර්තාව ආරම්භ කර එය යැවීමට සූදානම් කරන තෙක් එයට කිසියම් කාලයක් ගතවනු ඇත; කරුණාකර ඉවසන්න."</string>
@@ -1332,8 +1331,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ධාවකය"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB ආචයනය"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"සංස්කරණය කරන්න"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"දත්ත භාවිතය ගැන ඇඟවීම"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"භාවිතය සහ සැකසීම් බැලීමට තට්ටු කරන්න."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G දත්ත සීමාවට ළඟාවී ඇත"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G දත්ත සීමාවට ළඟාවී ඇත"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 26e275f..5c129af 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -218,8 +218,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefónu"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Zámka obrazovky"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Vypnúť"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Tiesňové volanie"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Hlásenie o chybách"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Vytvoriť hlásenie chyby"</string>
<string name="bugreport_message" msgid="398447048750350456">"Týmto zhromaždíte informácie o aktuálnom stave zariadenia. Informácie je potom možné odoslať e-mailom, chvíľu však potrvá, kým bude hlásenie chyby pripravené na odoslanie. Prosíme vás preto o trpezlivosť."</string>
@@ -1382,8 +1381,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Disk USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Ukladací priestor USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Upraviť"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Upozornenie na spotrebu dát"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Klepnutím zobrazíte využitie a nastavenia."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Bol dosiahnutý limit 2G–3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Bol dosiahnutý limit 4G"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 7f49968..76f1e66 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -218,8 +218,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Možnosti telefona"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Zaklep zaslona"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Izklopi"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Klic v sili"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Poročilo o napakah"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Ustvari poročilo o napakah"</string>
<string name="bugreport_message" msgid="398447048750350456">"S tem bodo zbrani podatki o trenutnem stanju naprave, ki bodo poslani v e-poštnem sporočilu. Izvedba poročila o napakah in priprava trajata nekaj časa, zato bodite potrpežljivi."</string>
@@ -1382,8 +1381,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Pogon USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Pomnilnik USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Opozorilo o preneseni količini podatkov"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Dot. se za ogled upor. in nast."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dosežena pod. omejitev za 2G/3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dosežena pod. omejitev za 4G"</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index c906f74..0fb3ebe 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Opsionet e telefonit"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Kyçja e ekranit"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Fik"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Urgjenca"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Raporti i defekteve në kod"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Merr raportin e defekteve në kod"</string>
<string name="bugreport_message" msgid="398447048750350456">"Ky funksion mundëson mbledhjen e informacioneve mbi gjendjen aktuale të pajisjes për ta dërguar si mesazh mail-i. Do të duhet pak kohë nga nisja e raportit të defekteve në kod. Faleminderit për durimin."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-ja nga <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Hapësira ruajtëse e USB-së"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Redakto"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Sinjalizimi i të dhënave"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Trokit për të parë përdorimin dhe cilësimet."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Kufiri i të dhënave 2G-3G u arrit"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Kufiri i të dhënave 4G u arrit"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index f029dbb..fdf8a6d 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -152,7 +152,7 @@
<string name="httpErrorAuth" msgid="1435065629438044534">"Није могуће потврдити аутентичност."</string>
<string name="httpErrorProxyAuth" msgid="1788207010559081331">"Потврда идентитета преко прокси сервера није успела."</string>
<string name="httpErrorConnect" msgid="8714273236364640549">"Није могуће повезати се са сервером."</string>
- <string name="httpErrorIO" msgid="2340558197489302188">"Није могуће комуницирати са сервером. Покушајте поново касније."</string>
+ <string name="httpErrorIO" msgid="2340558197489302188">"Није могуће комуницирати са сервером. Пробајте поново касније."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"Веза са сервером је истекла."</string>
<string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Страница садржи превише веза за преусмеравање са сервера."</string>
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Протокол није подржан."</string>
@@ -160,7 +160,7 @@
<string name="httpErrorBadUrl" msgid="3636929722728881972">"Страницу није могуће отворити зато што је URL адреса неважећа."</string>
<string name="httpErrorFile" msgid="2170788515052558676">"Није могуће приступити датотеци."</string>
<string name="httpErrorFileNotFound" msgid="6203856612042655084">"Није могуће пронаћи тражену датотеку."</string>
- <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Превише захтева се обрађује. Покушајте поново касније."</string>
+ <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Превише захтева се обрађује. Пробајте поново касније."</string>
<string name="notification_title" msgid="8967710025036163822">"Грешка при пријављивању за <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
<string name="contentServiceSync" msgid="8353523060269335667">"Синхронизација"</string>
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Синхронизација"</string>
@@ -216,8 +216,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Опције телефона"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Закључај екран"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Искључи"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Хитни позив"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Извештај о грешци"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Направи извештај о грешци"</string>
<string name="bugreport_message" msgid="398447048750350456">"Овим ће се прикупити информације о тренутном стању уређаја како би биле послате у поруци е-поште. Од започињања извештаја о грешци до тренутка за његово слање проћи ће неко време; будите стрпљиви."</string>
@@ -441,19 +440,19 @@
<string name="permdesc_manageFingerprint" msgid="178208705828055464">"Дозвољава апликацији да активира методе за додавање и брисање шаблона отисака прстију који ће се користити."</string>
<string name="permlab_useFingerprint" msgid="3150478619915124905">"користи хардвер за отиске прстију"</string>
<string name="permdesc_useFingerprint" msgid="9165097460730684114">"Дозвољава апликацији да користи хардвер за отиске прстију ради потврде аутентичности"</string>
- <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Откривен је делимични отисак прста. Покушајте поново."</string>
- <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Није успела обрада отиска прста. Покушајте поново."</string>
+ <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Откривен је делимични отисак прста. Пробајте поново."</string>
+ <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Није успела обрада отиска прста. Пробајте поново."</string>
<string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Сензор за отиске прстију је прљав. Очистите га и покушајте поново."</string>
- <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Пребрзо сте померили прст. Покушајте поново."</string>
- <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Превише споро сте померили прст. Покушајте поново."</string>
+ <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Пребрзо сте померили прст. Пробајте поново."</string>
+ <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Превише споро сте померили прст. Пробајте поново."</string>
<string-array name="fingerprint_acquired_vendor">
</string-array>
<string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Хардвер за отиске прстију није доступан."</string>
<string name="fingerprint_error_no_space" msgid="1055819001126053318">"Није могуће сачувати отисак прста. Уклоните неки од постојећих отисака прстију."</string>
- <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Временско ограничење за отисак прста је истекло. Покушајте поново."</string>
+ <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Временско ограничење за отисак прста је истекло. Пробајте поново."</string>
<string name="fingerprint_error_canceled" msgid="4402024612660774395">"Радња са отиском прста је отказана."</string>
- <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Превише покушаја. Покушајте поново касније."</string>
- <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Покушајте поново."</string>
+ <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Превише покушаја. Пробајте поново касније."</string>
+ <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Пробајте поново."</string>
<string name="fingerprint_name_template" msgid="5870957565512716938">"Прст <xliff:g id="FINGERID">%d</xliff:g>"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
@@ -681,8 +680,8 @@
<string name="lockscreen_emergency_call" msgid="5298642613417801888">"Хитне службе"</string>
<string name="lockscreen_return_to_call" msgid="5244259785500040021">"Назад на позив"</string>
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Тачно!"</string>
- <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Покушајте поново"</string>
- <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Покушајте поново"</string>
+ <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Пробајте поново"</string>
+ <string name="lockscreen_password_wrong" msgid="5737815393253165301">"Пробајте поново"</string>
<string name="lockscreen_storage_locked" msgid="9167551160010625200">"Откључај за све функције и податке"</string>
<string name="faceunlock_multiple_failures" msgid="754137583022792429">"Премашен је највећи дозвољени број покушаја Откључавања лицем"</string>
<string name="lockscreen_missing_sim_message_short" msgid="5099439277819215399">"Нема SIM картице"</string>
@@ -706,19 +705,19 @@
<string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Погледајте Кориснички водич или контактирајте Корисничку подршку."</string>
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"SIM картица је закључана."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Откључавање SIM картице…"</string>
- <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте неправилно нацртали шаблон за откључавање. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
- <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели лозинку. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
- <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели PIN. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу података за пријављивање на Google.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја од вас ће бити затражено да откључате ТВ помоћу података за пријављивање на Google.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу података за пријављивање на Google.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
+ <string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте неправилно нацртали шаблон за откључавање. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели лозинку. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
+ <string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте погрешно унели PIN. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу података за пријављивање на Google.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја од вас ће бити затражено да откључате ТВ помоћу података за пријављивање на Google.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="2590227559763762751">"<xliff:g id="NUMBER_0">%1$d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> несупешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу података за пријављивање на Google.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="6128106399745755604">"Неправилно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Након још неуспешних покушаја (<xliff:g id="NUMBER_1">%2$d</xliff:g>) таблет ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="950408382418270260">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја ТВ ће бити ресетован на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
<string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="8603565142156826565">"Неисправно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Након још неуспешних покушаја (<xliff:g id="NUMBER_1">%2$d</xliff:g>) телефон ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="280873516493934365">"Неисправно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пута. Таблет ће сада бити враћен на подразумевана фабричка подешавања."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="3195755534096192191">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. ТВ ће сада бити ресетован на подразумевана фабричка подешавања."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="3025504721764922246">"Неисправно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пута. Телефон ће сада бити враћен на подразумевана фабричка подешавања."</string>
- <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Покушајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
+ <string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Пробајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Заборавили сте шаблон?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Откључавање налога"</string>
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"Превише покушаја уноса шаблона"</string>
@@ -1356,8 +1355,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB диск"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB меморија"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Измени"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Обавештење о потрошњи података"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Додирните за потрошњу и подешавања."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Нема више 2G-3G података"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Нема више 4G података"</string>
@@ -1423,7 +1421,7 @@
<string name="kg_wrong_pattern" msgid="1850806070801358830">"Погрешан шаблон"</string>
<string name="kg_wrong_password" msgid="2333281762128113157">"Погрешна лозинка"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"Погрешан PIN"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Покушајте поново за <xliff:g id="NUMBER">%1$d</xliff:g> секунде(и)."</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Пробајте поново за <xliff:g id="NUMBER">%1$d</xliff:g> секунде(и)."</string>
<string name="kg_pattern_instructions" msgid="398978611683075868">"Нацртајте шаблон"</string>
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Унесите PIN SIM картице"</string>
<string name="kg_pin_instructions" msgid="2377242233495111557">"Унесите PIN"</string>
@@ -1445,18 +1443,18 @@
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Неважеће корисничко име или лозинка."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Заборавили сте корисничко име или лозинку?\nПосетите адресу "<b>"google.com/accounts/recovery"</b>"."</string>
<string name="kg_login_checking_password" msgid="1052685197710252395">"Провера налога…"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте нетачни PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте нетачну лозинку <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте нетачни PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте нетачну лозинку <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"Покушали сте да откључате таблет нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. Након још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја таблет ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја ТВ ће бити ресетован на подразумевана фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="4051015943038199910">"Покушали сте да откључате телефон нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја телефон ће бити ресетован на фабричка подешавања и сви кориснички подаци ће бити изгубљени."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2072996269148483637">"Покушали сте да откључате таблет нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. Таблет ће сада бити враћен на подразумевана фабричка подешавања."</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="4987878286750741463">"Покушали сте да откључате ТВ нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. ТВ ће сада бити ресетован на подразумевана фабричка подешавања."</string>
<string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Покушали сте да откључате телефон нетачно <xliff:g id="NUMBER">%d</xliff:g> пута. Телефон ће сада бити враћен на подразумевана фабричка подешавања."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате ТВ помоћу налога е-поште.\n\n Покушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Неисправно сте нацртали шаблон за откључавање <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате ТВ помоћу налога е-поште.\n\n Пробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Уклони"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Желите да појачате звук изнад препорученог нивоа?\n\nСлушање гласне музике дуже време може да вам оштети слух."</string>
@@ -1567,14 +1565,14 @@
<string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"Нови PIN"</string>
<string name="restr_pin_confirm_pin" msgid="8501523829633146239">"Потврдите нови PIN"</string>
<string name="restr_pin_create_pin" msgid="8017600000263450337">"Направите PIN за измену ограничења"</string>
- <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ови се не подударају. Покушајте поново."</string>
+ <string name="restr_pin_error_doesnt_match" msgid="2224214190906994548">"PIN-ови се не подударају. Пробајте поново."</string>
<string name="restr_pin_error_too_short" msgid="8173982756265777792">"PIN је прекратак. Мора да садржи најмање 4 цифре."</string>
<plurals name="restr_pin_countdown" formatted="false" msgid="9061246974881224688">
- <item quantity="one">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунду</item>
- <item quantity="few">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунде</item>
- <item quantity="other">Покушајте поново за <xliff:g id="COUNT">%d</xliff:g> секунди</item>
+ <item quantity="one">Пробајте поново за <xliff:g id="COUNT">%d</xliff:g> секунду</item>
+ <item quantity="few">Пробајте поново за <xliff:g id="COUNT">%d</xliff:g> секунде</item>
+ <item quantity="other">Пробајте поново за <xliff:g id="COUNT">%d</xliff:g> секунди</item>
</plurals>
- <string name="restr_pin_try_later" msgid="973144472490532377">"Покушајте поново касније"</string>
+ <string name="restr_pin_try_later" msgid="973144472490532377">"Пробајте поново касније"</string>
<string name="immersive_cling_title" msgid="8394201622932303336">"Приказује се цео екран"</string>
<string name="immersive_cling_description" msgid="3482371193207536040">"Да бисте изашли, превуците надоле одозго."</string>
<string name="immersive_cling_positive" msgid="5016839404568297683">"Важи"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 3f4f836..66f085f 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefonalternativ"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Skärmlås"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Stäng av"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Nödsituation"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Felrapport"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Skapa felrapport"</string>
<string name="bugreport_message" msgid="398447048750350456">"Nu hämtas information om aktuell status för enheten, som sedan skickas i ett e-postmeddelade. Det tar en liten stund innan felrapporten är färdig och kan skickas, så vi ber dig ha tålamod."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"USB-enhet (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB-lagring"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Redigera"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Varning – dataanvändning"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Visa användning och inställning."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Datagränsen för 2G-3G har uppnåtts"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Datagränsen för 4G har uppnåtts"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 9cba390..4832546 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -212,8 +212,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Chaguo za simu"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Funga skrini"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Zima"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Dharura"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Ripoti ya hitilafu"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Chukua ripoti ya hitilafu"</string>
<string name="bugreport_message" msgid="398447048750350456">"Hii itakusanya maelezo kuhusu hali ya kifaa chako kwa sasa, na itume kama barua pepe. Itachukua muda mfupi tangu ripoti ya hitilafu ianze kuzalishwa hadi iwe tayari kutumwa; vumilia."</string>
@@ -1328,8 +1327,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Hifadhi ya USB iliyotengenezwa na <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Hifadhi ya USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Badilisha"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Tahadhari ya matumizi ya data"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Gonga ili uangalie matumizi na mipangilio."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Kikomo data ya 2G-3G kimefikiwa"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Kikomo cha data ya 4G kimefikiwa"</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index e784a76..f6bb25c 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"தொலைபேசி விருப்பங்கள்"</string>
<string name="global_action_lock" msgid="2844945191792119712">"திரைப் பூட்டு"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"முடக்கு"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"அவசர அழைப்பு"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"பிழை அறிக்கை"</string>
<string name="bugreport_title" msgid="2667494803742548533">"பிழை அறிக்கையை எடு"</string>
<string name="bugreport_message" msgid="398447048750350456">"உங்கள் நடப்புச் சாதன நிலையை மின்னஞ்சல் செய்தியாக அனுப்ப, அது குறித்த தகவலை இது சேகரிக்கும். பிழை அறிக்கையைத் தொடங்குவதில் இருந்து, அது அனுப்புவதற்குத் தயாராகும் வரை, இதற்குச் சிறிது நேரம் ஆகும்; பொறுமையாகக் காத்திருக்கவும்."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB டிரைவ்"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB சேமிப்பிடம்"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"திருத்து"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"தரவுப் பயன்பாடு குறித்த எச்சரிக்கை"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"தரவு உபயோகம், அமைப்புகளைப் பார்க்க, தட்டவும்."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G தரவு வரம்பைக் கடந்தது"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G தரவு வரம்பைக் கடந்தது"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 21ed7c6..24bfebd 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ఫోన్ ఎంపికలు"</string>
<string name="global_action_lock" msgid="2844945191792119712">"స్క్రీన్ లాక్"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"పవర్ ఆఫ్ చేయి"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"అత్యవసరం"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"బగ్ నివేదిక"</string>
<string name="bugreport_title" msgid="2667494803742548533">"బగ్ నివేదికను సిద్ధం చేయి"</string>
<string name="bugreport_message" msgid="398447048750350456">"ఇది ఇ-మెయిల్ సందేశం రూపంలో పంపడానికి మీ ప్రస్తుత పరికర స్థితి గురించి సమాచారాన్ని సేకరిస్తుంది. బగ్ నివేదికను ప్రారంభించడం మొదలుకొని పంపడానికి సిద్ధం చేసే వరకు ఇందుకు కొంత సమయం పడుతుంది; దయచేసి ఓపిక పట్టండి."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB డ్రైవ్"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB నిల్వ"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"సవరించు"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"డేటా వినియోగ హెచ్చరిక"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"వినియోగం,సెట్టింగ్ల కోసం నొక్కండి"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G డేటా పరిమితిని చేరుకుంది"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G డేటా పరిమితిని చేరుకుంది"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index df9b182..818bb9f 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ตัวเลือกโทรศัพท์"</string>
<string name="global_action_lock" msgid="2844945191792119712">"ล็อกหน้าจอ"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"ปิดเครื่อง"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"เหตุฉุกเฉิน"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"รายงานข้อบกพร่อง"</string>
<string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานข้อบกพร่อง"</string>
<string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานข้อบกพร่องจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"ไดรฟ์ USB ของ <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"ที่เก็บข้อมูล USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"แก้ไข"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"การแจ้งเตือนการใช้อินเทอร์เน็ต"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"แตะเพื่อดูการใช้งานและการตั้งค่า"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"ถึงขีดจำกัดข้อมูล 2G-3G แล้ว"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"ถึงขีดจำกัดข้อมูล 4G แล้ว"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index fac6eeb..81c5fd0 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Pagpipilian sa telepono"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Pag-lock sa screen"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"I-off"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Emergency"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Ulat sa bug"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Kunin ang ulat sa bug"</string>
<string name="bugreport_message" msgid="398447048750350456">"Mangongolekta ito ng impormasyon tungkol sa kasalukuyang katayuan ng iyong device, na ipapadala bilang mensaheng e-mail. Gugugol ito ng kaunting oras mula sa pagsisimula ng ulat sa bug hanggang sa handa na itong maipadala; mangyaring magpasensya."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB drive"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB storage"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"I-edit"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Alerto sa paggamit ng data"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"I-tap tingnan paggamit/setting."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Naabot na ang limitasyon sa 2G-3G data"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Naabot na ang limitasyon sa 4G data"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index afd9e68..9983142 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefon seçenekleri"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Ekran kilidi"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Kapat"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Acil durum"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Hata raporu"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Hata raporu al"</string>
<string name="bugreport_message" msgid="398447048750350456">"Bu rapor, e-posta iletisi olarak göndermek üzere cihazınızın şu anki durumuyla ilgili bilgi toplar. Hata raporu başlatıldıktan sonra hazır olması biraz zaman alabilir, lütfen sabırlı olun."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB sürücüsü"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB bellek"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Düzenle"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Veri kullanımı uyarısı"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Kul. ve ayar. gör. için dokunun."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G veri sınırına ulaşıldı"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G veri sınırına ulaşıldı"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 0ce3396..4c135ab 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -218,8 +218,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Параметри телеф."</string>
<string name="global_action_lock" msgid="2844945191792119712">"Заблок. екран"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Вимкнути"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Екстрений виклик"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Звіт про помилки"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Звіт про помилку"</string>
<string name="bugreport_message" msgid="398447048750350456">"Інформація про поточний стан вашого пристрою буде зібрана й надіслана електронною поштою. Підготовка звіту триватиме певний час."</string>
@@ -1382,8 +1381,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Носій USB (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
<string name="storage_usb" msgid="3017954059538517278">"Носій USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Редагувати"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Сповіщення про використ. трафіку"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Переглянути дані та параметри."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Досягнуто ліміту даних 2G–3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Досягнуто ліміту даних 4G"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index ebab740..d6eae64a 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"فون کے اختیارات"</string>
<string name="global_action_lock" msgid="2844945191792119712">"اسکرین لاک"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"پاور آف"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"ایمرجنسی"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"بگ کی اطلاع"</string>
<string name="bugreport_title" msgid="2667494803742548533">"بگ کی اطلاع لیں"</string>
<string name="bugreport_message" msgid="398447048750350456">"ایک ای میل پیغام کے بطور بھیجنے کیلئے، یہ آپ کے موجودہ آلہ کی حالت کے بارے میں معلومات جمع کرے گا۔ بگ کی اطلاع شروع کرنے سے لے کر بھیجنے کیلئے تیار ہونے تک اس میں تھوڑا وقت لگے گا؛ براہ کرم تحمل سے کام لیں۔"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB ڈرائیو"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB اسٹوریج"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"ترمیم کریں"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"ڈیٹا کے استعمال کا الرٹ"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"استعمال اور ترتیبات دیکھنے کیلئے تھپتھپائیں۔"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ڈیٹا کی حد کو پہنچ گیا"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ڈیٹا کی حد کو پہنچ گیا"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index f97a7b8..5b7cf74 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Telefon sozlamalari"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Ekran qulfi"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"O‘chirish"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Favqulodda chaqiruv"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Nosozlik haqida ma’lumot berish"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Xatoliklar hisoboti"</string>
<string name="bugreport_message" msgid="398447048750350456">"Qurilmangiz holati haqidagi ma’lumotlar to‘planib, e-pochta orqali yuboriladi. Hisobotni tayyorlash biroz vaqt olishi mumkin."</string>
@@ -1100,7 +1099,7 @@
<string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct yoniq"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Sozlamalarni ochish uchun bosing"</string>
<string name="accept" msgid="1645267259272829559">"Qabul qilish"</string>
- <string name="decline" msgid="2112225451706137894">"Rad qilish"</string>
+ <string name="decline" msgid="2112225451706137894">"Rad etish"</string>
<string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"taklif jo‘natildi"</string>
<string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ulanish taklifi"</string>
<string name="wifi_p2p_from_message" msgid="570389174731951769">"Kimdan:"</string>
@@ -1114,7 +1113,7 @@
<string name="sms_control_title" msgid="7296612781128917719">"SMS xabarlar yuborilmoqda"</string>
<string name="sms_control_message" msgid="3867899169651496433">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> katta miqdordagi SMS xabarlarini jo‘natmoqda. Ushbu ilovaga xabarlar jo‘natishni davom ettirishga ruxsat berasizmi?"</string>
<string name="sms_control_yes" msgid="3663725993855816807">"Ruxsat berish"</string>
- <string name="sms_control_no" msgid="625438561395534982">"Rad qilish"</string>
+ <string name="sms_control_no" msgid="625438561395534982">"Rad etish"</string>
<string name="sms_short_code_confirm_message" msgid="1645436466285310855">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>ga xabar jo‘natishni xohlaydi."</string>
<string name="sms_short_code_details" msgid="5873295990846059400">"Bunda, mobil hisobingizdan "<b>"to‘lov olinishi mumkin"</b>"."</string>
<string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Bunda, mobil hisobingizdan to‘lov olinishi mumkin."</b></string>
@@ -1224,7 +1223,7 @@
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Ushbu so‘rovga ruxsat berishni xohlaysizmi?"</string>
<string name="grant_permissions_header_text" msgid="6874497408201826708">"Ruxsat so‘rovi"</string>
<string name="allow" msgid="7225948811296386551">"Ruxsat berish"</string>
- <string name="deny" msgid="2081879885755434506">"Rad qilish"</string>
+ <string name="deny" msgid="2081879885755434506">"Rad etish"</string>
<string name="permission_request_notification_title" msgid="6486759795926237907">"Ruxsat so‘raldi"</string>
<string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"<xliff:g id="ACCOUNT">%s</xliff:g> hisobi uchun\nruxsat so‘raldi"</string>
<string name="forward_intent_to_owner" msgid="1207197447013960896">"Siz ushbu ilovadan ishchi profilingizdan tashqarida foydalanmoqdasiz"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB xotira qurilmasi"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB xotira"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Tahrirlash"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Trafik sarfi bo‘yicha ogohlantirish"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Trafik sarfi va sozlamalarni ko‘rish uchun bosing."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G trafik chekloviga yetdi"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G trafik chekloviga yetdi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 66b87e7..42e0b0a 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Tùy chọn điện thoại"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Khoá màn hình"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Tắt nguồn"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Khẩn cấp"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Báo cáo lỗi"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Nhận báo cáo lỗi"</string>
<string name="bugreport_message" msgid="398447048750350456">"Báo cáo này sẽ thu thập thông tin về tình trạng thiết bị hiện tại của bạn, để gửi dưới dạng thông báo qua email. Sẽ mất một chút thời gian kể từ khi bắt đầu báo cáo lỗi cho tới khi báo cáo sẵn sàng để gửi; xin vui lòng kiên nhẫn."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"Ổ USB <xliff:g id="MANUFACTURER">%s</xliff:g>"</string>
<string name="storage_usb" msgid="3017954059538517278">"Bộ lưu trữ USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Chỉnh sửa"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Thông báo về sử dụng dữ liệu"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Nhấn để xem sử dụng và cài đặt."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Đã đạt tới giới hạn dữ liệu 2G-3G"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Đã đạt tới giới hạn dữ liệu 4G"</string>
diff --git a/core/res/res/values-watch/colors_device_defaults.xml b/core/res/res/values-watch/colors_device_defaults.xml
new file mode 100644
index 0000000..9150cc4
--- /dev/null
+++ b/core/res/res/values-watch/colors_device_defaults.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Colors specific to DeviceDefault themes. These are mostly pass-throughs to enable
+ overlaying new theme colors. -->
+<resources>
+ <color name="button_normal_device_default_dark">@color/btn_default_material_dark</color>
+</resources>
diff --git a/core/res/res/values-watch/colors_material.xml b/core/res/res/values-watch/colors_material.xml
index 54eece4..18bfd4d 100644
--- a/core/res/res/values-watch/colors_material.xml
+++ b/core/res/res/values-watch/colors_material.xml
@@ -17,8 +17,10 @@
<color name="background_material_dark">#ff232e33</color>
<color name="background_floating_material_dark">#ff3e5059</color>
- <color name="accent_material_dark">#ff5e97f6</color>
+ <color name="accent_material_700">#ff2e4978</color>
<color name="accent_material_light">#ff4285f4</color>
+ <color name="accent_material_dark">#ff5e97f6</color>
+ <color name="accent_material_50">#ffd0def7</color>
<color name="primary_material_dark">#4D4D4D</color>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index 2313b26..aa1594d 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- 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.
@@ -18,26 +18,328 @@
===============================================================
PLEASE READ
===============================================================
-This file contains the themes that are the Device Defaults.
-If you want to edit themes to skin your device, do it here.
-We recommend that you do not edit themes.xml and instead edit
-this file.
-
-Editing this file instead of themes.xml will greatly simplify
+This file contains the themes that are the Device Defaults on
+Watch. If you want to edit themes to skin your device, do it
+here. Editing this file instead of themes.xml will greatly simplify
merges for future platform versions and CTS compliance will be
easier.
+
+You should also have a look at themes.xml, to
+understand why we define Dialogs and Settings with color
+palette Dark. It's because themes.xml modify Material in
+a similar way.
===============================================================
PLEASE READ
===============================================================
-->
<resources>
+ <style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
+ <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Material.NoActionBar">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
+ sets {@link android.R.attr#windowFullscreen} to true. -->
+ <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
+ extending in to overscan region. This theme
+ sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
+ to true. -->
+ <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
+ system decor. This theme sets {@link android.R.attr#windowTranslucentStatus} and
+ {@link android.R.attr#windowTranslucentNavigation} to true. -->
+ <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
<!-- Theme used for the intent picker activity. -->
- <style name="Theme.DeviceDefault.Resolver" parent="Theme.Material">
+ <style name="Theme.DeviceDefault.Resolver">
<item name="colorControlActivated">?attr/colorControlHighlight</item>
<item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
<item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
</style>
<!-- Use a dark theme for watches. -->
- <style name="Theme.DeviceDefault.System" parent="Theme.Material" />
+ <style name="Theme.DeviceDefault.System" />
+
+ <!-- DeviceDefault style for input methods, which is used by the
+ {@link android.inputmethodservice.InputMethodService} class.-->
+ <style name="Theme.DeviceDefault.InputMethod" parent="Theme.DeviceDefault.Panel">
+ <item name="windowAnimationStyle">@style/Animation.InputMethod</item>
+ <item name="imeFullscreenBackground">?colorBackground</item>
+ <item name="imeExtractEnterAnimation">@anim/input_method_extract_enter</item>
+ </style>
+
+ <!-- DeviceDefault theme for dialog windows and activities. In contrast to Material, the
+ watch theme is not floating. You can set this theme on an activity if you would like to make
+ an activity that looks like a Dialog.-->
+ <style name="Theme.DeviceDefault.Dialog" parent="Theme.Material.Dialog" >
+ <item name="windowIsFloating">false</item>
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+ <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+
+ <item name="buttonBarStyle">@style/DeviceDefault.ButtonBar.AlertDialog</item>
+ <item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Button.Borderless.Small</item>
+
+ <item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
+ <item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
+
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- DeviceDefault theme for a window that should look like the Settings app. -->
+ <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault"/>
+ <style name="Theme.DeviceDefault.Settings.NoActionBar" parent="Theme.DeviceDefault"/>
+ <style name="Theme.DeviceDefault.Settings.BaseDialog" parent="Theme.DeviceDefault.Dialog"/>
+ <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.DeviceDefault.Settings.BaseDialog"/>
+ <style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.DeviceDefault.DialogWhenLarge"/>
+ <style name="Theme.DeviceDefault.Settings.DialogWhenLarge.NoActionBar" parent="Theme.DeviceDefault.DialogWhenLarge.NoActionBar"/>
+ <style name="Theme.DeviceDefault.Settings.Dialog.Presentation" parent="Theme.DeviceDefault.Dialog.Presentation"/>
+ <style name="Theme.DeviceDefault.Settings.SearchBar" parent="Theme.DeviceDefault.SearchBar"/>
+
+ <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
+ <item name="windowIsFloating">false</item>
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <style name="Theme.DeviceDefault.Settings.CompactMenu" parent="Theme.Material.CompactMenu">
+ <item name="windowIsFloating">false</item>
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
+ regular dialog. -->
+ <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth">
+ <item name="windowIsFloating">false</item>
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar">
+ <item name="windowIsFloating">false</item>
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
+ for a regular dialog. -->
+ <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth">
+ <item name="windowIsFloating">false</item>
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller
+ screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
+ <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- DeviceDefault theme for a window without an action bar that will be displayed either
+ full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
+ xlarge). -->
+ <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- DeviceDefault theme for a presentation window on a secondary display. -->
+ <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- DeviceDefault theme for panel windows. This removes all extraneous window
+ decorations, so you basically have an empty rectangle in which to place your content. It makes
+ the window floating, with a transparent background, and turns off dimming behind the window. -->
+ <style name="Theme.DeviceDefault.Panel" parent="Theme.Material.Panel">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+ behind them. -->
+ <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Material.Wallpaper">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
+ behind them and without an action bar. -->
+ <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Material.Wallpaper.NoTitleBar">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <!-- DeviceDefault style for input methods, which is used by the
+ {@link android.service.voice.VoiceInteractionSession} class.-->
+ <style name="Theme.DeviceDefault.VoiceInteractionSession" parent="Theme.Material.VoiceInteractionSession">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
+ <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+
+ <!-- Color palette Dialog -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">?attr/colorBackgroundFloating</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar">
+ <!-- Color palette Dark -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">@color/background_device_default_dark</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
+
+ <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
+ <item name="windowIsFloating">false</item>
+ <!-- Color palette Dialog -->
+ <item name="colorPrimary">@color/primary_device_default_dark</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+ <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorBackground">?attr/colorBackgroundFloating</item>
+ <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
+ <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
+ <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+ </style>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 1bd1023..b67d6e2 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"手机选项"</string>
<string name="global_action_lock" msgid="2844945191792119712">"屏幕锁定"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"关机"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"紧急呼救"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"错误报告"</string>
<string name="bugreport_title" msgid="2667494803742548533">"提交错误报告"</string>
<string name="bugreport_message" msgid="398447048750350456">"这会收集有关当前设备状态的信息,并以电子邮件的形式进行发送。从开始生成错误报告到准备好发送需要一点时间,请耐心等待。"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> U 盘"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB存储器"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"修改"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"流量消耗提醒"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"点按即可查看使用情况和设置。"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已达到2G-3G流量上限"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已达到4G流量上限"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 4329c8f..62bb44a 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"手機選項"</string>
<string name="global_action_lock" msgid="2844945191792119712">"螢幕鎖定"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"關閉"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"緊急"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
<string name="bugreport_title" msgid="2667494803742548533">"取得錯誤報告"</string>
<string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,並以電郵傳送給您。從開始建立錯誤報告到準備傳送需要一段時間,請耐心等候。"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 驅動器"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"編輯"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"數據用量警告"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"輕按即可查看用量和設定。"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已達到 2G-3G 數據流量上限"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已達到 4G 數據流量上限"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index ec7a9a0..0500c07 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"電話選項"</string>
<string name="global_action_lock" msgid="2844945191792119712">"螢幕鎖定"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"關機"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"緊急電話"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"錯誤報告"</string>
<string name="bugreport_title" msgid="2667494803742548533">"取得錯誤報告"</string>
<string name="bugreport_message" msgid="398447048750350456">"這會收集您目前裝置狀態的相關資訊,以便透過電子郵件傳送。從錯誤報告開始建立到準備傳送的這段過程可能需要一點時間,敬請耐心等候。"</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB 隨身碟"</string>
<string name="storage_usb" msgid="3017954059538517278">"USB 儲存裝置"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"編輯"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"數據用量警告"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"輕觸即可查看用量和設定。"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"已達到 2G-3G 數據流量上限"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"已達到 4G 數據流量上限"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 3a19648..849f292 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -214,8 +214,7 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"Okukhethwa kukho kwefoni"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Ukuvala isikrini"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Vala amandla"</string>
- <!-- no translation found for global_action_emergency (7112311161137421166) -->
- <skip />
+ <string name="global_action_emergency" msgid="7112311161137421166">"Isimo esiphuthumayo"</string>
<string name="global_action_bug_report" msgid="7934010578922304799">"Umbiko wephutha"</string>
<string name="bugreport_title" msgid="2667494803742548533">"Thatha umbiko wesiphazamiso"</string>
<string name="bugreport_message" msgid="398447048750350456">"Lokhu kuzoqoqa ulwazi mayelana nesimo samanje sedivayisi yakho, ukuthumela imilayezo ye-imeyili. Kuzothatha isikhathi esincane kusuka ekuqaleni umbiko wesiphazamiso uze ulungele ukuthunyelwa; sicela ubekezele."</string>
@@ -1330,8 +1329,7 @@
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> idrayivu ye-USB"</string>
<string name="storage_usb" msgid="3017954059538517278">"Isitoreji se-USB"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Hlela"</string>
- <!-- no translation found for data_usage_warning_title (3620440638180218181) -->
- <skip />
+ <string name="data_usage_warning_title" msgid="3620440638180218181">"Izexwayiso zokusetshenziswa kwedatha"</string>
<string name="data_usage_warning_body" msgid="6660692274311972007">"Thepha ukuze ubuke ukusetshenziswa nezilungiselelo."</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G umkhawulo wedatha ufinyelelwe"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G umkhawulo wedatha ufinyelelwe"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f0a25aa..c3967e4 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3965,6 +3965,7 @@
</declare-styleable>
<declare-styleable name="ProgressBar">
+ <attr name="min" format="integer" />
<!-- Defines the maximum value the progress can take. -->
<attr name="max" format="integer" />
<!-- Defines the default progress value, between 0 and max. -->
@@ -7941,6 +7942,14 @@
<declare-styleable name="SeekBarPreference">
<attr name="layout" />
+ <!-- Attribute indicating whether the slider within this preference can be adjusted, that is
+ pressing left/right keys when this preference is focused will move the slider accordingly (e.g.
+ inline adjustable preferences). False, if the slider within the preference is read-only and
+ cannot be adjusted. By default, the seekbar is adjustable. -->
+ <attr name="adjustable" format="boolean" />
+ <!-- Flag indicating whether the TextView next to the seekbar that shows the current seekbar value will be
+ displayed. If true, the view is VISIBLE; if false, the view will be GONE. By default, this view is VISIBLE. -->
+ <attr name="showSeekBarValue" format="boolean" />
</declare-styleable>
<!-- Base attributes available to PreferenceFragment. -->
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 27ee27b..89691e9 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -32,4 +32,9 @@
<color name="accent_device_default_light">@color/accent_material_light</color>
<color name="accent_device_default_dark">@color/accent_material_dark</color>
<color name="accent_device_default_50">@color/material_deep_teal_50</color>
+
+ <color name="background_device_default_dark">@color/background_material_dark</color>
+ <color name="background_device_default_light">@color/background_material_light</color>
+ <color name="background_floating_device_default_dark">@color/background_floating_material_dark</color>
+ <color name="background_floating_device_default_light">@color/background_floating_material_light</color>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3ae6186..21587b7 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2212,9 +2212,6 @@
provisioning, availability etc -->
<bool name="config_carrier_volte_available">false</bool>
- <!-- Flag specifying whether VoLTE availability is based on provisioning -->
- <bool name="config_carrier_volte_provisioned">false</bool>
-
<!-- Flag specifying whether VoLTE TTY is supported -->
<bool name="config_carrier_volte_tty_supported">true</bool>
@@ -2234,6 +2231,11 @@
<!-- Flag specifying whether WFC over IMS is available on device -->
<bool name="config_device_wfc_ims_available">false</bool>
+ <!-- Flag specifying whether WFC over IMS should be available for carrier: independent of
+ carrier provisioning. If false: hard disabled. If true: then depends on carrier
+ provisioning, availability etc -->
+ <bool name="config_carrier_wfc_ims_available">false</bool>
+
<bool name="config_networkSamplingWakesDevice">true</bool>
<string-array translatable="false" name="config_cdma_home_system" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 7bce379..7999e7e 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2764,4 +2764,5 @@
<public-group type="id" first-id="0x01020041">
</public-group>
+ <public type="attr" name="min" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bf7317c..cce02f2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3561,7 +3561,7 @@
<!-- Button text for the edit menu in input method extract mode. [CHAR LIMIT=16] -->
<string name="extract_edit_menu_button">Edit</string>
- <!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
+ <!-- Notification title when data usage has exceeded warning threshold. [CHAR LIMIT=50] -->
<string name="data_usage_warning_title">Data usage alert</string>
<!-- Notification body when data usage has exceeded warning threshold. [CHAR LIMIT=32] -->
<string name="data_usage_warning_body">Tap to view usage and settings.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 30dd760..ddd93b68 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2219,12 +2219,12 @@
<java-symbol type="bool" name="imsServiceAllowTurnOff" />
<java-symbol type="bool" name="config_device_volte_available" />
<java-symbol type="bool" name="config_carrier_volte_available" />
- <java-symbol type="bool" name="config_carrier_volte_provisioned" />
<java-symbol type="bool" name="config_carrier_volte_tty_supported" />
<java-symbol type="bool" name="config_device_vt_available" />
<java-symbol type="bool" name="config_device_respects_hold_carrier_config" />
<java-symbol type="bool" name="config_carrier_vt_available" />
<java-symbol type="bool" name="config_device_wfc_ims_available" />
+ <java-symbol type="bool" name="config_carrier_wfc_ims_available" />
<java-symbol type="attr" name="touchscreenBlocksFocus" />
<java-symbol type="layout" name="resolver_list_with_default" />
<java-symbol type="string" name="whichApplicationNamed" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 0e98ade..b19858e 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -49,7 +49,7 @@
Type.DeviceDefault.Etc (for example, {@code Widget.DeviceDefault.Button} and
{@code TextAppearance.DeviceDefault.Widget.PopupMenu.Large}).</p>
-->
- <style name="Theme.DeviceDefault" parent="Theme.Material" >
+ <style name="Theme.DeviceDefaultBase" parent="Theme.Material" >
<!-- Text styles -->
<item name="textAppearance">@style/TextAppearance.DeviceDefault</item>
<item name="textAppearanceInverse">@style/TextAppearance.DeviceDefault.Inverse</item>
@@ -206,6 +206,8 @@
</style>
+ <style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase" />
+
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
<style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Material.NoActionBar">
<!-- Color palette -->
diff --git a/core/res/res/xml/preferred_time_zones.xml b/core/res/res/xml/preferred_time_zones.xml
deleted file mode 100644
index da8553f..0000000
--- a/core/res/res/xml/preferred_time_zones.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/default/default/data/preferred_time_zones.xml
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<timezones>
- <timezone offset="-18000000">America/New_York</timezone>
- <timezone offset="-21600000">America/Chicago</timezone>
- <timezone offset="-25200000">America/Denver</timezone>
- <timezone offset="-28800000">America/Los_Angeles</timezone>
-</timezones>
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index a9fa5e0d..29c6b79 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -57,6 +57,12 @@
<!-- Bulgaria: 4-5 digits, plus EU -->
<shortcode country="bg" pattern="\\d{4,5}" premium="18(?:16|423)|19(?:1[56]|35)" free="116\\d{3}" />
+ <!-- Bahrain: 1-5 digits (standard system default, not country specific) -->
+ <shortcode country="bh" pattern="\\d{1,5}" free="81181" />
+
+ <!-- Brazil: 1-5 digits (standard system default, not country specific) -->
+ <shortcode country="br" pattern="\\d{1,5}" free="6000[012]\\d" />
+
<!-- Belarus: 4 digits -->
<shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" />
@@ -129,7 +135,7 @@
<!-- Italy: 5 digits (premium=4xxxx), plus EU:
http://clients.txtnation.com/attachments/token/di5kfblvubttvlw/?name=Italy_CASP_EN.pdf -->
- <shortcode country="it" pattern="\\d{5}" premium="4\\d{4}" free="116\\d{3}|4112503" />
+ <shortcode country="it" pattern="\\d{5}" premium="4\\d{4}" free="116\\d{3}|4112503" standard="43\\d{3}" />
<!-- Japan: 8083 used by SOFTBANK_DCB_2 -->
<shortcode country="jp" free="8083" />
@@ -204,7 +210,7 @@
<shortcode country="si" pattern="\\d{4}" premium="[368]\\d{3}" free="116\\d{3}" />
<!-- Slovakia: 4 digits (premium), plus EU: http://www.cmtelecom.com/premium-sms/slovakia -->
- <shortcode country="sk" premium="\\d{4}" free="116\\d{3}" />
+ <shortcode country="sk" premium="\\d{4}" free="116\\d{3}|8000" />
<!-- Thailand: 4186001 used by AIS_TH_DCB -->
<shortcode country="th" free="4186001" />
@@ -220,9 +226,9 @@
<!-- USA: 5-6 digits (premium codes from https://www.premiumsmsrefunds.com/ShortCodes.htm),
visual voicemail code for T-Mobile: 122 -->
- <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567" free="122|87902" />
+ <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" standard="44567" free="122|87902|21696|24614|28003|30356|33669|40196|41064|41270|43753|44034|46645|52413|56139|57969|61785|66975|75136|76227|81398|83952|85140|86566|86799|95737|96684|99245" />
<!-- Vietnam: 1-5 digits (standard system default, not country specific) -->
- <shortcode country="vn" pattern="\\d{1,5}" free="5001" />
+ <shortcode country="vn" pattern="\\d{1,5}" free="5001|9055" />
</shortcodes>
diff --git a/core/res/res/xml/time_zones_by_country.xml b/core/res/res/xml/time_zones_by_country.xml
index 9b2bd50..a685e2b 100644
--- a/core/res/res/xml/time_zones_by_country.xml
+++ b/core/res/res/xml/time_zones_by_country.xml
@@ -31,11 +31,11 @@
<!-- ANTIGUA AND BARBUDA, -4:00 -->
- <timezone code="ag">America/Antigua</timezone>
+ <timezone code="ag">America/Port_of_Spain</timezone>
<!-- ANGUILLA, -4:00 -->
- <timezone code="ai">America/Anguilla</timezone>
+ <timezone code="ai">America/Port_of_Spain</timezone>
<!-- ALBANIA, 1:00 -->
@@ -45,18 +45,13 @@
<timezone code="am">Asia/Yerevan</timezone>
- <!-- NETHERLANDS ANTILLES, -4:00 -->
-
- <timezone code="an">America/Curacao</timezone>
-
<!-- ANGOLA, 1:00 -->
- <timezone code="ao">Africa/Luanda</timezone>
+ <timezone code="ao">Africa/Lagos</timezone>
<!-- ANTARCTICA, 12:00 -->
- <timezone code="aq">Antarctica/McMurdo</timezone>
- <timezone code="aq">Antarctica/South_Pole</timezone>
+ <timezone code="aq">Pacific/Auckland</timezone>
<!-- ANTARCTICA, 10:00 -->
@@ -70,15 +65,22 @@
<timezone code="aq">Antarctica/Davis</timezone>
- <!-- ANTARCTICA, 6:00 -->
+ <!-- ANTARCTICA, 5:00 -->
<timezone code="aq">Antarctica/Mawson</timezone>
+
+ <!-- ANTARCTICA, 6:00 -->
+
<timezone code="aq">Antarctica/Vostok</timezone>
<!-- ANTARCTICA, 3:00 -->
<timezone code="aq">Antarctica/Syowa</timezone>
+ <!-- ANTARCTICA, 0:00 -->
+
+ <timezone code="aq">Antarctica/Troll</timezone>
+
<!-- ANTARCTICA, -3:00 -->
<timezone code="aq">Antarctica/Rothera</timezone>
@@ -91,12 +93,14 @@
<timezone code="ar">America/Argentina/Buenos_Aires</timezone>
<timezone code="ar">America/Argentina/Cordoba</timezone>
+ <timezone code="ar">America/Argentina/Salta</timezone>
<timezone code="ar">America/Argentina/Jujuy</timezone>
<timezone code="ar">America/Argentina/Tucuman</timezone>
<timezone code="ar">America/Argentina/Catamarca</timezone>
<timezone code="ar">America/Argentina/La_Rioja</timezone>
<timezone code="ar">America/Argentina/San_Juan</timezone>
<timezone code="ar">America/Argentina/Mendoza</timezone>
+ <timezone code="ar">America/Argentina/San_Luis</timezone>
<timezone code="ar">America/Argentina/Rio_Gallegos</timezone>
<timezone code="ar">America/Argentina/Ushuaia</timezone>
@@ -117,6 +121,9 @@
<timezone code="au">Australia/Currie</timezone>
<timezone code="au">Australia/Lindeman</timezone>
+ <!-- AUSTRALIA, 11:00 -->
+ <timezone code="au">Antarctica/Macquarie</timezone>
+
<!-- AUSTRALIA, 10:30 -->
<timezone code="au">Australia/Lord_Howe</timezone>
@@ -137,11 +144,11 @@
<!-- ARUBA, -4:00 -->
- <timezone code="aw">America/Aruba</timezone>
+ <timezone code="aw">America/Curacao</timezone>
<!-- ALAND ISLANDS, 2:00 -->
- <timezone code="ax">Europe/Mariehamn</timezone>
+ <timezone code="ax">Europe/Helsinki</timezone>
<!-- AZERBAIJAN, 4:00 -->
@@ -149,7 +156,7 @@
<!-- BOSNIA AND HERZEGOVINA, 1:00 -->
- <timezone code="ba">Europe/Sarajevo</timezone>
+ <timezone code="ba">Europe/Belgrade</timezone>
<!-- BARBADOS, -4:00 -->
@@ -165,7 +172,7 @@
<!-- BURKINA FASO, 0:00 -->
- <timezone code="bf">Africa/Ouagadougou</timezone>
+ <timezone code="bf">Africa/Abidjan</timezone>
<!-- BULGARIA, 2:00 -->
@@ -173,15 +180,19 @@
<!-- BAHRAIN, 3:00 -->
- <timezone code="bh">Asia/Bahrain</timezone>
+ <timezone code="bh">Asia/Qatar</timezone>
<!-- BURUNDI, 2:00 -->
- <timezone code="bi">Africa/Bujumbura</timezone>
+ <timezone code="bi">Africa/Maputo</timezone>
<!-- BENIN, 1:00 -->
- <timezone code="bj">Africa/Porto-Novo</timezone>
+ <timezone code="bj">Africa/Lagos</timezone>
+
+ <!-- Saint Barthélemy, -4:00 -->
+
+ <timezone code="bl">America/Port_of_Spain</timezone>
<!-- BERMUDA, -4:00 -->
@@ -195,6 +206,10 @@
<timezone code="bo">America/La_Paz</timezone>
+ <!-- Caribbean Netherlands, -4:00 -->
+
+ <timezone code="bq">America/Curacao</timezone>
+
<!-- BRAZIL, -2:00 -->
<timezone code="br">America/Noronha</timezone>
@@ -208,6 +223,7 @@
<timezone code="br">America/Araguaina</timezone>
<timezone code="br">America/Maceio</timezone>
<timezone code="br">America/Bahia</timezone>
+ <timezone code="br">America/Santarem</timezone>
<!-- BRAZIL, -4:00 -->
@@ -216,6 +232,9 @@
<timezone code="br">America/Cuiaba</timezone>
<timezone code="br">America/Porto_Velho</timezone>
<timezone code="br">America/Boa_Vista</timezone>
+
+ <!-- BRAZIL, -5:00 -->
+
<timezone code="br">America/Eirunepe</timezone>
<timezone code="br">America/Rio_Branco</timezone>
@@ -229,9 +248,9 @@
<!-- BOTSWANA, 2:00 -->
- <timezone code="bw">Africa/Gaborone</timezone>
+ <timezone code="bw">Africa/Maputo</timezone>
- <!-- BELARUS, 2:00 -->
+ <!-- BELARUS, 3:00 -->
<timezone code="by">Europe/Minsk</timezone>
@@ -254,12 +273,10 @@
<!-- CANADA, -5:00 -->
<timezone code="ca">America/Toronto</timezone>
- <timezone code="ca">America/Montreal</timezone>
<timezone code="ca">America/Nipigon</timezone>
<timezone code="ca">America/Thunder_Bay</timezone>
<timezone code="ca">America/Iqaluit</timezone>
<timezone code="ca">America/Pangnirtung</timezone>
- <timezone code="ca">America/Resolute</timezone>
<timezone code="ca">America/Atikokan</timezone>
<!-- CANADA, -6:00 -->
@@ -269,6 +286,7 @@
<timezone code="ca">America/Rankin_Inlet</timezone>
<timezone code="ca">America/Rainy_River</timezone>
<timezone code="ca">America/Swift_Current</timezone>
+ <timezone code="ca">America/Resolute</timezone>
<!-- CANADA, -7:00 -->
@@ -277,6 +295,8 @@
<timezone code="ca">America/Yellowknife</timezone>
<timezone code="ca">America/Inuvik</timezone>
<timezone code="ca">America/Dawson_Creek</timezone>
+ <timezone code="ca">America/Creston</timezone>
+ <timezone code="ca">America/Fort_Nelson</timezone>
<!-- CANADA, -8:00 -->
@@ -290,19 +310,19 @@
<!-- CONGO, THE DEMOCRATIC REPUBLIC OF THE, 2:00 -->
- <timezone code="cd">Africa/Lubumbashi</timezone>
+ <timezone code="cd">Africa/Maputo</timezone>
<!-- CONGO, THE DEMOCRATIC REPUBLIC OF THE, 1:00 -->
- <timezone code="cd">Africa/Kinshasa</timezone>
+ <timezone code="cd">Africa/Lagos</timezone>
<!-- CENTRAL AFRICAN REPUBLIC, 1:00 -->
- <timezone code="cf">Africa/Bangui</timezone>
+ <timezone code="cf">Africa/Lagos</timezone>
<!-- CONGO, 1:00 -->
- <timezone code="cg">Africa/Brazzaville</timezone>
+ <timezone code="cg">Africa/Lagos</timezone>
<!-- SWITZERLAND, 1:00 -->
@@ -326,15 +346,15 @@
<!-- CAMEROON, 1:00 -->
- <timezone code="cm">Africa/Douala</timezone>
+ <timezone code="cm">Africa/Lagos</timezone>
<!-- CHINA, 8:00 -->
<timezone code="cn">Asia/Shanghai</timezone>
- <timezone code="cn">Asia/Harbin</timezone>
- <timezone code="cn">Asia/Chongqing</timezone>
+
+ <!-- CHINA, 6:00 -->
+
<timezone code="cn">Asia/Urumqi</timezone>
- <timezone code="cn">Asia/Kashgar</timezone>
<!-- COLOMBIA, -5:00 -->
@@ -352,6 +372,10 @@
<timezone code="cv">Atlantic/Cape_Verde</timezone>
+ <!-- Curaçao, -4:00 -->
+
+ <timezone code="cw">America/Curacao</timezone>
+
<!-- CHRISTMAS ISLAND, 7:00 -->
<timezone code="cx">Indian/Christmas</timezone>
@@ -367,10 +391,11 @@
<!-- GERMANY, 1:00 -->
<timezone code="de">Europe/Berlin</timezone>
+ <timezone code="de">Europe/Zurich</timezone>
<!-- DJIBOUTI, 3:00 -->
- <timezone code="dj">Africa/Djibouti</timezone>
+ <timezone code="dj">Africa/Nairobi</timezone>
<!-- DENMARK, 1:00 -->
@@ -378,7 +403,7 @@
<!-- DOMINICA, -4:00 -->
- <timezone code="dm">America/Dominica</timezone>
+ <timezone code="dm">America/Port_of_Spain</timezone>
<!-- DOMINICAN REPUBLIC, -4:00 -->
@@ -410,7 +435,7 @@
<!-- ERITREA, 3:00 -->
- <timezone code="er">Africa/Asmara</timezone>
+ <timezone code="er">Africa/Nairobi</timezone>
<!-- SPAIN, 1:00 -->
@@ -423,7 +448,7 @@
<!-- ETHIOPIA, 3:00 -->
- <timezone code="et">Africa/Addis_Ababa</timezone>
+ <timezone code="et">Africa/Nairobi</timezone>
<!-- FINLAND, 2:00 -->
@@ -433,7 +458,7 @@
<timezone code="fj">Pacific/Fiji</timezone>
- <!-- FALKLAND ISLANDS (MALVINAS), -4:00 -->
+ <!-- FALKLAND ISLANDS (MALVINAS), -3:00 -->
<timezone code="fk">Atlantic/Stanley</timezone>
@@ -444,7 +469,7 @@
<!-- MICRONESIA, FEDERATED STATES OF, 10:00 -->
- <timezone code="fm">Pacific/Truk</timezone>
+ <timezone code="fm">Pacific/Chuuk</timezone>
<!-- FAROE ISLANDS, 0:00 -->
@@ -456,7 +481,7 @@
<!-- GABON, 1:00 -->
- <timezone code="ga">Africa/Libreville</timezone>
+ <timezone code="ga">Africa/Lagos</timezone>
<!-- UNITED KINGDOM, 0:00 -->
@@ -464,7 +489,7 @@
<!-- GRENADA, -4:00 -->
- <timezone code="gd">America/Grenada</timezone>
+ <timezone code="gd">America/Port_of_Spain</timezone>
<!-- GEORGIA, 4:00 -->
@@ -476,7 +501,7 @@
<!-- GUERNSEY, 0:00 -->
- <timezone code="gg">Europe/Guernsey</timezone>
+ <timezone code="gg">Europe/London</timezone>
<!-- GHANA, 0:00 -->
@@ -504,19 +529,19 @@
<!-- GAMBIA, 0:00 -->
- <timezone code="gm">Africa/Banjul</timezone>
+ <timezone code="gm">Africa/Abidjan</timezone>
<!-- GUINEA, 0:00 -->
- <timezone code="gn">Africa/Conakry</timezone>
+ <timezone code="gn">Africa/Abidjan</timezone>
<!-- GUADELOUPE, -4:00 -->
- <timezone code="gp">America/Guadeloupe</timezone>
+ <timezone code="gp">America/Port_of_Spain</timezone>
<!-- EQUATORIAL GUINEA, 1:00 -->
- <timezone code="gq">Africa/Malabo</timezone>
+ <timezone code="gq">Africa/Lagos</timezone>
<!-- GREECE, 2:00 -->
@@ -552,7 +577,7 @@
<!-- CROATIA, 1:00 -->
- <timezone code="hr">Europe/Zagreb</timezone>
+ <timezone code="hr">Europe/Belgrade</timezone>
<!-- HAITI, -5:00 -->
@@ -585,11 +610,11 @@
<!-- ISLE OF MAN, 0:00 -->
- <timezone code="im">Europe/Isle_of_Man</timezone>
+ <timezone code="im">Europe/London</timezone>
<!-- INDIA, 5:30 -->
- <timezone code="in">Asia/Calcutta</timezone>
+ <timezone code="in">Asia/Kolkata</timezone>
<!-- BRITISH INDIAN OCEAN TERRITORY, 6:00 -->
@@ -613,7 +638,7 @@
<!-- JERSEY, 0:00 -->
- <timezone code="je">Europe/Jersey</timezone>
+ <timezone code="je">Europe/London</timezone>
<!-- JAMAICA, -5:00 -->
@@ -637,7 +662,7 @@
<!-- CAMBODIA, 7:00 -->
- <timezone code="kh">Asia/Phnom_Penh</timezone>
+ <timezone code="kh">Asia/Bangkok</timezone>
<!-- KIRIBATI, 14:00 -->
@@ -653,13 +678,13 @@
<!-- COMOROS, 3:00 -->
- <timezone code="km">Indian/Comoro</timezone>
+ <timezone code="km">Africa/Nairobi</timezone>
<!-- SAINT KITTS AND NEVIS, -4:00 -->
- <timezone code="kn">America/St_Kitts</timezone>
+ <timezone code="kn">America/Port_of_Spain</timezone>
- <!-- KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF, 9:00 -->
+ <!-- KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF, 8:30 -->
<timezone code="kp">Asia/Pyongyang</timezone>
@@ -669,11 +694,11 @@
<!-- KUWAIT, 3:00 -->
- <timezone code="kw">Asia/Kuwait</timezone>
+ <timezone code="kw">Asia/Riyadh</timezone>
<!-- CAYMAN ISLANDS, -5:00 -->
- <timezone code="ky">America/Cayman</timezone>
+ <timezone code="ky">America/Panama</timezone>
<!-- KAZAKHSTAN, 6:00 -->
@@ -688,7 +713,7 @@
<!-- LAO PEOPLE'S DEMOCRATIC REPUBLIC, 7:00 -->
- <timezone code="la">Asia/Vientiane</timezone>
+ <timezone code="la">Asia/Bangkok</timezone>
<!-- LEBANON, 2:00 -->
@@ -696,11 +721,11 @@
<!-- SAINT LUCIA, -4:00 -->
- <timezone code="lc">America/St_Lucia</timezone>
+ <timezone code="lc">America/Port_of_Spain</timezone>
<!-- LIECHTENSTEIN, 1:00 -->
- <timezone code="li">Europe/Vaduz</timezone>
+ <timezone code="li">Europe/Zurich</timezone>
<!-- SRI LANKA, 5:30 -->
@@ -712,7 +737,7 @@
<!-- LESOTHO, 2:00 -->
- <timezone code="ls">Africa/Maseru</timezone>
+ <timezone code="ls">Africa/Johannesburg</timezone>
<!-- LITHUANIA, 2:00 -->
@@ -744,11 +769,15 @@
<!-- MONTENEGRO, 1:00 -->
- <timezone code="me">Europe/Podgorica</timezone>
+ <timezone code="me">Europe/Belgrade</timezone>
+
+ <!-- Collectivity of Saint Martin, -4:00 -->
+
+ <timezone code="mf">America/Port_of_Spain</timezone>
<!-- MADAGASCAR, 3:00 -->
- <timezone code="mg">Indian/Antananarivo</timezone>
+ <timezone code="mg">Africa/Nairobi</timezone>
<!-- MARSHALL ISLANDS, 12:00 -->
@@ -757,15 +786,15 @@
<!-- MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF, 1:00 -->
- <timezone code="mk">Europe/Skopje</timezone>
+ <timezone code="mk">Europe/Belgrade</timezone>
<!-- MALI, 0:00 -->
- <timezone code="ml">Africa/Bamako</timezone>
+ <timezone code="ml">Africa/Abidjan</timezone>
<!-- MYANMAR, 6:30 -->
- <timezone code="mm">Asia/Rangoon</timezone>
+ <timezone code="mm">Asia/Yangon</timezone>
<!-- MONGOLIA, 8:00 -->
@@ -782,7 +811,7 @@
<!-- NORTHERN MARIANA ISLANDS, 10:00 -->
- <timezone code="mp">Pacific/Saipan</timezone>
+ <timezone code="mp">Pacific/Guam</timezone>
<!-- MARTINIQUE, -4:00 -->
@@ -790,11 +819,11 @@
<!-- MAURITANIA, 0:00 -->
- <timezone code="mr">Africa/Nouakchott</timezone>
+ <timezone code="mr">Africa/Abidjan</timezone>
<!-- MONTSERRAT, -4:00 -->
- <timezone code="ms">America/Montserrat</timezone>
+ <timezone code="ms">America/Port_of_Spain</timezone>
<!-- MALTA, 1:00 -->
@@ -810,20 +839,26 @@
<!-- MALAWI, 2:00 -->
- <timezone code="mw">Africa/Blantyre</timezone>
+ <timezone code="mw">Africa/Maputo</timezone>
<!-- MEXICO, -6:00 -->
<timezone code="mx">America/Mexico_City</timezone>
- <timezone code="mx">America/Cancun</timezone>
<timezone code="mx">America/Merida</timezone>
<timezone code="mx">America/Monterrey</timezone>
+ <timezone code="mx">America/Matamoros</timezone>
+ <timezone code="mx">America/Bahia_Banderas</timezone>
+
+ <!-- MEXICO, -5:00 -->
+
+ <timezone code="mx">America/Cancun</timezone>
<!-- MEXICO, -7:00 -->
<timezone code="mx">America/Chihuahua</timezone>
<timezone code="mx">America/Hermosillo</timezone>
<timezone code="mx">America/Mazatlan</timezone>
+ <timezone code="mx">America/Ojinaga</timezone>
<!-- MEXICO, -8:00 -->
@@ -848,7 +883,7 @@
<!-- NIGER, 1:00 -->
- <timezone code="ne">Africa/Niamey</timezone>
+ <timezone code="ne">Africa/Lagos</timezone>
<!-- NORFOLK ISLAND, 11:30 -->
@@ -892,7 +927,7 @@
<!-- OMAN, 4:00 -->
- <timezone code="om">Asia/Muscat</timezone>
+ <timezone code="om">Asia/Dubai</timezone>
<!-- PANAMA, -5:00 -->
@@ -918,6 +953,10 @@
<timezone code="pg">Pacific/Port_Moresby</timezone>
+ <!-- PAPUA NEW GUINEA, 11:00 -->
+
+ <timezone code="pg">Pacific/Bougainville</timezone>
+
<!-- PHILIPPINES, 8:00 -->
<timezone code="ph">Asia/Manila</timezone>
@@ -945,6 +984,7 @@
<!-- PALESTINE, 2:00 -->
<timezone code="ps">Asia/Gaza</timezone>
+ <timezone code="ps">Asia/Hebron</timezone>
<!-- PORTUGAL, 0:00 -->
@@ -987,15 +1027,19 @@
<!-- RUSSIAN FEDERATION, 11:00 -->
<timezone code="ru">Asia/Magadan</timezone>
+ <timezone code="ru">Asia/Sakhalin</timezone>
+ <timezone code="ru">Asia/Srednekolymsk</timezone>
<!-- RUSSIAN FEDERATION, 10:00 -->
<timezone code="ru">Asia/Vladivostok</timezone>
- <timezone code="ru">Asia/Sakhalin</timezone>
+ <timezone code="ru">Asia/Ust-Nera</timezone>
<!-- RUSSIAN FEDERATION, 9:00 -->
<timezone code="ru">Asia/Yakutsk</timezone>
+ <timezone code="ru">Asia/Chita</timezone>
+ <timezone code="ru">Asia/Khandyga</timezone>
<!-- RUSSIAN FEDERATION, 8:00 -->
@@ -1004,10 +1048,13 @@
<!-- RUSSIAN FEDERATION, 7:00 -->
<timezone code="ru">Asia/Krasnoyarsk</timezone>
+ <timezone code="ru">Asia/Novosibirsk</timezone>
+ <timezone code="ru">Asia/Barnaul</timezone>
+ <timezone code="ru">Asia/Novokuznetsk</timezone>
+ <timezone code="ru">Asia/Tomsk</timezone>
<!-- RUSSIAN FEDERATION, 6:00 -->
- <timezone code="ru">Asia/Novosibirsk</timezone>
<timezone code="ru">Asia/Omsk</timezone>
<!-- RUSSIAN FEDERATION, 5:00 -->
@@ -1017,11 +1064,15 @@
<!-- RUSSIAN FEDERATION, 4:00 -->
<timezone code="ru">Europe/Samara</timezone>
+ <timezone code="ru">Europe/Astrakhan</timezone>
+ <timezone code="ru">Europe/Ulyanovsk</timezone>
<!-- RUSSIAN FEDERATION, 3:00 -->
<timezone code="ru">Europe/Moscow</timezone>
<timezone code="ru">Europe/Volgograd</timezone>
+ <timezone code="ru">Europe/Kirov</timezone>
+ <timezone code="ru">Europe/Simferopol</timezone>
<!-- RUSSIAN FEDERATION, 2:00 -->
@@ -1029,7 +1080,7 @@
<!-- RWANDA, 2:00 -->
- <timezone code="rw">Africa/Kigali</timezone>
+ <timezone code="rw">Africa/Maputo</timezone>
<!-- SAUDI ARABIA, 3:00 -->
@@ -1057,57 +1108,65 @@
<!-- SAINT HELENA, 0:00 -->
- <timezone code="sh">Atlantic/St_Helena</timezone>
+ <timezone code="sh">Africa/Abidjan</timezone>
<!-- SLOVENIA, 1:00 -->
- <timezone code="si">Europe/Ljubljana</timezone>
+ <timezone code="si">Europe/Belgrade</timezone>
<!-- SVALBARD AND JAN MAYEN, 1:00 -->
- <timezone code="sj">Arctic/Longyearbyen</timezone>
+ <timezone code="sj">Europe/Oslo</timezone>
<!-- SLOVAKIA, 1:00 -->
- <timezone code="sk">Europe/Bratislava</timezone>
+ <timezone code="sk">Europe/Prague</timezone>
<!-- SIERRA LEONE, 0:00 -->
- <timezone code="sl">Africa/Freetown</timezone>
+ <timezone code="sl">Africa/Abidjan</timezone>
<!-- SAN MARINO, 1:00 -->
- <timezone code="sm">Europe/San_Marino</timezone>
+ <timezone code="sm">Europe/Rome</timezone>
<!-- SENEGAL, 0:00 -->
- <timezone code="sn">Africa/Dakar</timezone>
+ <timezone code="sn">Africa/Abidjan</timezone>
<!-- SOMALIA, 3:00 -->
- <timezone code="so">Africa/Mogadishu</timezone>
+ <timezone code="so">Africa/Nairobi</timezone>
<!-- SURINAME, -3:00 -->
<timezone code="sr">America/Paramaribo</timezone>
+ <!-- South Sudan, 3:00 -->
+
+ <timezone code="ss">Africa/Khartoum</timezone>
+
<!-- SAO TOME AND PRINCIPE, 0:00 -->
- <timezone code="st">Africa/Sao_Tome</timezone>
+ <timezone code="st">Africa/Abidjan</timezone>
<!-- EL SALVADOR, -6:00 -->
<timezone code="sv">America/El_Salvador</timezone>
+ <!-- Sint Maarten, -4:00 -->
+
+ <timezone code="sx">America/Curacao</timezone>
+
<!-- SYRIAN ARAB REPUBLIC, 2:00 -->
<timezone code="sy">Asia/Damascus</timezone>
<!-- SWAZILAND, 2:00 -->
- <timezone code="sz">Africa/Mbabane</timezone>
+ <timezone code="sz">Africa/Johannesburg</timezone>
- <!-- TURKS AND CAICOS ISLANDS, -5:00 -->
+ <!-- TURKS AND CAICOS ISLANDS, -4:00 -->
<timezone code="tc">America/Grand_Turk</timezone>
@@ -1119,9 +1178,13 @@
<timezone code="tf">Indian/Kerguelen</timezone>
+ <!-- FRENCH SOUTHERN TERRITORIES, 4:00 -->
+
+ <timezone code="tf">Indian/Reunion</timezone>
+
<!-- TOGO, 0:00 -->
- <timezone code="tg">Africa/Lome</timezone>
+ <timezone code="tg">Africa/Abidjan</timezone>
<!-- THAILAND, 7:00 -->
@@ -1131,7 +1194,7 @@
<timezone code="tj">Asia/Dushanbe</timezone>
- <!-- TOKELAU, -10:00 -->
+ <!-- TOKELAU, +13:00 -->
<timezone code="tk">Pacific/Fakaofo</timezone>
@@ -1151,7 +1214,7 @@
<timezone code="to">Pacific/Tongatapu</timezone>
- <!-- TURKEY, 2:00 -->
+ <!-- TURKEY, 3:00 -->
<timezone code="tr">Europe/Istanbul</timezone>
@@ -1169,18 +1232,17 @@
<!-- TANZANIA, UNITED REPUBLIC OF, 3:00 -->
- <timezone code="tz">Africa/Dar_es_Salaam</timezone>
+ <timezone code="tz">Africa/Nairobi</timezone>
<!-- UKRAINE, 2:00 -->
<timezone code="ua">Europe/Kiev</timezone>
<timezone code="ua">Europe/Uzhgorod</timezone>
<timezone code="ua">Europe/Zaporozhye</timezone>
- <timezone code="ua">Europe/Simferopol</timezone>
<!-- UGANDA, 3:00 -->
- <timezone code="ug">Africa/Kampala</timezone>
+ <timezone code="ug">Africa/Nairobi</timezone>
<!-- UNITED STATES MINOR OUTLYING ISLANDS, 12:00 -->
@@ -1188,11 +1250,11 @@
<!-- UNITED STATES MINOR OUTLYING ISLANDS, -10:00 -->
- <timezone code="um">Pacific/Johnston</timezone>
+ <timezone code="um">Pacific/Honolulu</timezone>
<!-- UNITED STATES MINOR OUTLYING ISLANDS, -11:00 -->
- <timezone code="um">Pacific/Midway</timezone>
+ <timezone code="um">Pacific/Pago_Pago</timezone>
<!-- UNITED STATES, -5:00 -->
@@ -1214,12 +1276,13 @@
<timezone code="us">America/Menominee</timezone>
<timezone code="us">America/North_Dakota/Center</timezone>
<timezone code="us">America/North_Dakota/New_Salem</timezone>
+ <timezone code="us">America/Indiana/Tell_City</timezone>
+ <timezone code="us">America/North_Dakota/Beulah</timezone>
<!-- UNITED STATES, -7:00 -->
<timezone code="us">America/Denver</timezone>
<timezone code="us">America/Boise</timezone>
- <timezone code="us">America/Shiprock</timezone>
<timezone code="us">America/Phoenix</timezone>
<!-- UNITED STATES, -8:00 -->
@@ -1232,6 +1295,8 @@
<timezone code="us">America/Juneau</timezone>
<timezone code="us">America/Yakutat</timezone>
<timezone code="us">America/Nome</timezone>
+ <timezone code="us">America/Metlakatla</timezone>
+ <timezone code="us">America/Sitka</timezone>
<!-- UNITED STATES, -10:00 -->
@@ -1249,27 +1314,28 @@
<!-- HOLY SEE (VATICAN CITY STATE), 1:00 -->
- <timezone code="va">Europe/Vatican</timezone>
+ <timezone code="va">Europe/Rome</timezone>
<!-- SAINT VINCENT AND THE GRENADINES, -4:00 -->
- <timezone code="vc">America/St_Vincent</timezone>
+ <timezone code="vc">America/Port_of_Spain</timezone>
- <!-- VENEZUELA, -4:30 -->
+ <!-- VENEZUELA, -4:00 -->
<timezone code="ve">America/Caracas</timezone>
<!-- VIRGIN ISLANDS, BRITISH, -4:00 -->
- <timezone code="vg">America/Tortola</timezone>
+ <timezone code="vg">America/Port_of_Spain</timezone>
<!-- VIRGIN ISLANDS, U.S., -4:00 -->
- <timezone code="vi">America/St_Thomas</timezone>
+ <timezone code="vi">America/Port_of_Spain</timezone>
<!-- VIET NAM, 7:00 -->
- <timezone code="vn">Asia/Saigon</timezone>
+ <timezone code="vn">Asia/Ho_Chi_Minh</timezone>
+ <timezone code="vn">Asia/Bangkok</timezone>
<!-- VANUATU, 11:00 -->
@@ -1279,17 +1345,17 @@
<timezone code="wf">Pacific/Wallis</timezone>
- <!-- SAMOA, -11:00 -->
+ <!-- SAMOA, 13:00 -->
<timezone code="ws">Pacific/Apia</timezone>
<!-- YEMEN, 3:00 -->
- <timezone code="ye">Asia/Aden</timezone>
+ <timezone code="ye">Asia/Riyadh</timezone>
<!-- MAYOTTE, 3:00 -->
- <timezone code="yt">Indian/Mayotte</timezone>
+ <timezone code="yt">Africa/Nairobi</timezone>
<!-- SOUTH AFRICA, 2:00 -->
@@ -1297,9 +1363,9 @@
<!-- ZAMBIA, 2:00 -->
- <timezone code="zm">Africa/Lusaka</timezone>
+ <timezone code="zm">Africa/Maputo</timezone>
<!-- ZIMBABWE, 2:00 -->
- <timezone code="zw">Africa/Harare</timezone>
+ <timezone code="zw">Africa/Maputo</timezone>
</timezones>
diff --git a/core/tests/benchmarks/src/android/os/ParcelBenchmark.java b/core/tests/benchmarks/src/android/os/ParcelBenchmark.java
index 4bd2d00..6c45ae8 100644
--- a/core/tests/benchmarks/src/android/os/ParcelBenchmark.java
+++ b/core/tests/benchmarks/src/android/os/ParcelBenchmark.java
@@ -20,12 +20,15 @@
import com.google.caliper.BeforeExperiment;
public class ParcelBenchmark {
+ private static final int INNER_REPS = 1000;
private Parcel mParcel;
@BeforeExperiment
protected void setUp() {
mParcel = Parcel.obtain();
+ mParcel.setDataPosition(0);
+ mParcel.setDataCapacity(INNER_REPS * 8);
}
@AfterExperiment
@@ -36,43 +39,58 @@
public void timeWriteByte(int reps) {
final byte val = 0xF;
- for (int i = 0; i < reps; i++) {
- mParcel.writeByte(val);
+ for (int i = 0; i < (reps / INNER_REPS); i++) {
+ mParcel.setDataPosition(0);
+ for (int j = 0; j < INNER_REPS; j++) {
+ mParcel.writeByte(val);
+ }
}
}
public void timeReadByte(int reps) {
- mParcel.setDataCapacity(reps);
- for (int i = 0; i < reps; i++) {
- mParcel.readByte();
+ for (int i = 0; i < (reps / INNER_REPS); i++) {
+ mParcel.setDataPosition(0);
+ for (int j = 0; j < INNER_REPS; j++) {
+ mParcel.readByte();
+ }
}
}
public void timeWriteInt(int reps) {
final int val = 0xF;
- for (int i = 0; i < reps; i++) {
- mParcel.writeInt(val);
+ for (int i = 0; i < (reps / INNER_REPS); i++) {
+ mParcel.setDataPosition(0);
+ for (int j = 0; j < INNER_REPS; j++) {
+ mParcel.writeInt(val);
+ }
}
}
public void timeReadInt(int reps) {
- mParcel.setDataCapacity(reps << 2);
- for (int i = 0; i < reps; i++) {
- mParcel.readInt();
+ for (int i = 0; i < (reps / INNER_REPS); i++) {
+ mParcel.setDataPosition(0);
+ for (int j = 0; j < INNER_REPS; j++) {
+ mParcel.readInt();
+ }
}
}
public void timeWriteLong(int reps) {
final long val = 0xF;
- for (int i = 0; i < reps; i++) {
- mParcel.writeLong(val);
+ for (int i = 0; i < (reps / INNER_REPS); i++) {
+ mParcel.setDataPosition(0);
+ for (int j = 0; j < INNER_REPS; j++) {
+ mParcel.writeLong(val);
+ }
}
}
public void timeReadLong(int reps) {
- mParcel.setDataCapacity(reps << 3);
- for (int i = 0; i < reps; i++) {
- mParcel.readLong();
+ for (int i = 0; i < (reps / INNER_REPS); i++) {
+ mParcel.setDataPosition(0);
+ for (int j = 0; j < INNER_REPS; j++) {
+ mParcel.readLong();
+ }
}
}
}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index ee78613..ba1a55d 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1323,17 +1323,6 @@
</meta-data>
</service>
- <activity
- android:name="android.print.mockservice.SettingsActivity"
- android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
- android:exported="true">
- </activity>
-
- <activity
- android:name="android.print.mockservice.AddPrintersActivity"
- android:exported="true">
- </activity>
-
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/core/tests/coretests/res/xml/printservice.xml b/core/tests/coretests/res/xml/printservice.xml
index b105a0f0..3bd2b04 100644
--- a/core/tests/coretests/res/xml/printservice.xml
+++ b/core/tests/coretests/res/xml/printservice.xml
@@ -16,6 +16,4 @@
limitations under the License.
-->
-<print-service xmlns:android="http://schemas.android.com/apk/res/android"
- android:settingsActivity="android.print.mockservice.SettingsActivity"
- android:addPrintersActivity="android.print.mockservice.AddPrintersActivity" />
+<print-service xmlns:android="http://schemas.android.com/apk/res/android" />
diff --git a/core/tests/coretests/src/android/print/WorkflowTest.java b/core/tests/coretests/src/android/print/WorkflowTest.java
deleted file mode 100644
index 35cfe22..0000000
--- a/core/tests/coretests/src/android/print/WorkflowTest.java
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.print;
-
-import android.graphics.pdf.PdfDocument;
-import android.os.Bundle;
-import android.os.CancellationSignal;
-import android.os.ParcelFileDescriptor;
-import android.print.mockservice.AddPrintersActivity;
-import android.print.mockservice.MockPrintService;
-
-import android.print.mockservice.PrinterDiscoverySessionCallbacks;
-import android.print.mockservice.StubbablePrinterDiscoverySession;
-import android.print.pdf.PrintedPdfDocument;
-import android.support.test.filters.LargeTest;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiSelector;
-import android.util.Log;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-import java.util.function.Supplier;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Tests for the basic printing workflows
- */
-public class WorkflowTest extends BasePrintTest {
- private static final String LOG_TAG = WorkflowTest.class.getSimpleName();
-
- private static float sWindowAnimationScaleBefore;
- private static float sTransitionAnimationScaleBefore;
- private static float sAnimatiorDurationScaleBefore;
-
- interface InterruptableConsumer<T> {
- void accept(T t) throws InterruptedException;
- }
-
- /**
- * Execute {@code waiter} until {@code condition} is met.
- *
- * @param condition Conditions to wait for
- * @param waiter Code to execute while waiting
- */
- private void waitWithTimeout(Supplier<Boolean> condition, InterruptableConsumer<Long> waiter)
- throws TimeoutException, InterruptedException {
- long startTime = System.currentTimeMillis();
- while (condition.get()) {
- long timeLeft = OPERATION_TIMEOUT - (System.currentTimeMillis() - startTime);
- if (timeLeft < 0) {
- throw new TimeoutException();
- }
-
- waiter.accept(timeLeft);
- }
- }
-
- /**
- * Executes a shell command using shell user identity, and return the standard output in
- * string.
- *
- * @param cmd the command to run
- *
- * @return the standard output of the command
- */
- private static String runShellCommand(String cmd) throws IOException {
- try (FileInputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
- getInstrumentation().getUiAutomation().executeShellCommand(cmd))) {
- byte[] buf = new byte[64];
- int bytesRead;
-
- StringBuilder stdout = new StringBuilder();
- while ((bytesRead = is.read(buf)) != -1) {
- stdout.append(new String(buf, 0, bytesRead));
- }
-
- return stdout.toString();
- }
- }
-
- @BeforeClass
- public static void disableAnimations() throws Exception {
- try {
- sWindowAnimationScaleBefore = Float.parseFloat(runShellCommand(
- "settings get global window_animation_scale"));
-
- runShellCommand("settings put global window_animation_scale 0");
- } catch (NumberFormatException e) {
- sWindowAnimationScaleBefore = Float.NaN;
- }
- try {
- sTransitionAnimationScaleBefore = Float.parseFloat(runShellCommand(
- "settings get global transition_animation_scale"));
-
- runShellCommand("settings put global transition_animation_scale 0");
- } catch (NumberFormatException e) {
- sTransitionAnimationScaleBefore = Float.NaN;
- }
- try {
- sAnimatiorDurationScaleBefore = Float.parseFloat(runShellCommand(
- "settings get global animator_duration_scale"));
-
- runShellCommand("settings put global animator_duration_scale 0");
- } catch (NumberFormatException e) {
- sAnimatiorDurationScaleBefore = Float.NaN;
- }
- }
-
- @AfterClass
- public static void enableAnimations() throws Exception {
- if (sWindowAnimationScaleBefore != Float.NaN) {
- runShellCommand(
- "settings put global window_animation_scale " + sWindowAnimationScaleBefore);
- }
- if (sTransitionAnimationScaleBefore != Float.NaN) {
- runShellCommand(
- "settings put global transition_animation_scale " +
- sTransitionAnimationScaleBefore);
- }
- if (sAnimatiorDurationScaleBefore != Float.NaN) {
- runShellCommand(
- "settings put global animator_duration_scale " + sAnimatiorDurationScaleBefore);
- }
- }
-
- /** Add a printer with a given name and supported mediasize to a session */
- private void addPrinter(StubbablePrinterDiscoverySession session,
- String name, PrintAttributes.MediaSize mediaSize) {
- PrinterId printerId = session.getService().generatePrinterId(name);
- List<PrinterInfo> printers = new ArrayList<>(1);
-
- PrinterCapabilitiesInfo.Builder builder =
- new PrinterCapabilitiesInfo.Builder(printerId);
-
- builder.setMinMargins(new PrintAttributes.Margins(0, 0, 0, 0))
- .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
- PrintAttributes.COLOR_MODE_COLOR)
- .addMediaSize(mediaSize, true)
- .addResolution(new PrintAttributes.Resolution("300x300", "300x300", 300, 300),
- true);
-
- printers.add(new PrinterInfo.Builder(printerId, name,
- PrinterInfo.STATUS_IDLE).setCapabilities(builder.build()).build());
-
- session.addPrinters(printers);
- }
-
- /** Find a certain element in the UI and click on it */
- private void clickOn(UiSelector selector) throws UiObjectNotFoundException {
- Log.i(LOG_TAG, "Click on " + selector);
- UiObject view = getUiDevice().findObject(selector);
- view.click();
- getUiDevice().waitForIdle();
- }
-
- /** Find a certain text in the UI and click on it */
- private void clickOnText(String text) throws UiObjectNotFoundException {
- clickOn(new UiSelector().text(text));
- }
-
- /** Set the printer in the print activity */
- private void setPrinter(String printerName) throws UiObjectNotFoundException {
- clickOn(new UiSelector().resourceId("com.android.printspooler:id/destination_spinner"));
-
- clickOnText(printerName);
- }
-
- /**
- * Init mock print servic that returns a single printer by default.
- *
- * @param sessionRef Where to store the reference to the session once started
- */
- private void setMockPrintServiceCallbacks(StubbablePrinterDiscoverySession[] sessionRef) {
- MockPrintService.setCallbacks(createMockPrintServiceCallbacks(
- inv -> createMockPrinterDiscoverySessionCallbacks(inv2 -> {
- synchronized (sessionRef) {
- sessionRef[0] = ((PrinterDiscoverySessionCallbacks) inv2.getMock())
- .getSession();
-
- addPrinter(sessionRef[0], "1st printer",
- PrintAttributes.MediaSize.ISO_A0);
-
- sessionRef.notifyAll();
- }
- return null;
- },
- null, null, null, null, null, inv2 -> {
- synchronized (sessionRef) {
- sessionRef[0] = null;
- sessionRef.notifyAll();
- }
- return null;
- }
- ), null, null));
- }
-
- /**
- * Start print operation that just prints a single empty page
- *
- * @param printAttributesRef Where to store the reference to the print attributes once started
- */
- private void print(PrintAttributes[] printAttributesRef) {
- print(new PrintDocumentAdapter() {
- @Override
- public void onStart() {
- }
-
- @Override
- public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
- CancellationSignal cancellationSignal, LayoutResultCallback callback,
- Bundle extras) {
- callback.onLayoutFinished((new PrintDocumentInfo.Builder("doc")).build(),
- !newAttributes.equals(printAttributesRef[0]));
-
- synchronized (printAttributesRef) {
- printAttributesRef[0] = newAttributes;
- printAttributesRef.notifyAll();
- }
- }
-
- @Override
- public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
- CancellationSignal cancellationSignal, WriteResultCallback callback) {
- try {
- try {
- PrintedPdfDocument document = new PrintedPdfDocument(getActivity(),
- printAttributesRef[0]);
- try {
- PdfDocument.Page page = document.startPage(0);
- document.finishPage(page);
- try (FileOutputStream os = new FileOutputStream(
- destination.getFileDescriptor())) {
- document.writeTo(os);
- os.flush();
- }
- } finally {
- document.close();
- }
- } finally {
- destination.close();
- }
-
- callback.onWriteFinished(pages);
- } catch (IOException e) {
- callback.onWriteFailed(e.getMessage());
- }
- }
- }, null);
- }
-
- @Test
- @LargeTest
- public void addAndSelectPrinter() throws Exception {
- final StubbablePrinterDiscoverySession session[] = new StubbablePrinterDiscoverySession[1];
- final PrintAttributes printAttributes[] = new PrintAttributes[1];
-
- setMockPrintServiceCallbacks(session);
- print(printAttributes);
-
- // We are now in the PrintActivity
- Log.i(LOG_TAG, "Waiting for session");
- synchronized (session) {
- waitWithTimeout(() -> session[0] == null, session::wait);
- }
-
- setPrinter("1st printer");
-
- Log.i(LOG_TAG, "Waiting for print attributes to change");
- synchronized (printAttributes) {
- waitWithTimeout(
- () -> printAttributes[0] == null || !printAttributes[0].getMediaSize().equals(
- PrintAttributes.MediaSize.ISO_A0), printAttributes::wait);
- }
-
- setPrinter("All printers\u2026");
-
- // We are now in the SelectPrinterActivity
- clickOnText("Add printer");
-
- // We are now in the AddPrinterActivity
- AddPrintersActivity.addObserver(
- () -> addPrinter(session[0], "2nd printer", PrintAttributes.MediaSize.ISO_A1));
-
- // This executes the observer registered above
- clickOn(new UiSelector().text(MockPrintService.class.getCanonicalName())
- .resourceId("com.android.printspooler:id/title"));
-
- getUiDevice().pressBack();
- AddPrintersActivity.clearObservers();
-
- // We are now in the SelectPrinterActivity
- clickOnText("2nd printer");
-
- // We are now in the PrintActivity
- Log.i(LOG_TAG, "Waiting for print attributes to change");
- synchronized (printAttributes) {
- waitWithTimeout(
- () -> printAttributes[0] == null || !printAttributes[0].getMediaSize().equals(
- PrintAttributes.MediaSize.ISO_A1), printAttributes::wait);
- }
-
- getUiDevice().pressBack();
-
- // We are back in the test activity
- Log.i(LOG_TAG, "Waiting for session to end");
- synchronized (session) {
- waitWithTimeout(() -> session[0] != null, session::wait);
- }
- }
-
- @Test
- @LargeTest
- public void abortSelectingPrinter() throws Exception {
- final StubbablePrinterDiscoverySession session[] = new StubbablePrinterDiscoverySession[1];
- final PrintAttributes printAttributes[] = new PrintAttributes[1];
-
- setMockPrintServiceCallbacks(session);
- print(printAttributes);
-
- // We are now in the PrintActivity
- Log.i(LOG_TAG, "Waiting for session");
- synchronized (session) {
- waitWithTimeout(() -> session[0] == null, session::wait);
- }
-
- setPrinter("1st printer");
-
- Log.i(LOG_TAG, "Waiting for print attributes to change");
- synchronized (printAttributes) {
- waitWithTimeout(
- () -> printAttributes[0] == null || !printAttributes[0].getMediaSize().equals(
- PrintAttributes.MediaSize.ISO_A0), printAttributes::wait);
- }
-
- setPrinter("All printers\u2026");
-
- // We are now in the SelectPrinterActivity
- clickOnText("Add printer");
-
- // We are now in the AddPrinterActivity
- AddPrintersActivity.addObserver(
- () -> addPrinter(session[0], "2nd printer", PrintAttributes.MediaSize.ISO_A1));
-
- // This executes the observer registered above
- clickOn(new UiSelector().text(MockPrintService.class.getCanonicalName())
- .resourceId("com.android.printspooler:id/title"));
-
- getUiDevice().pressBack();
- AddPrintersActivity.clearObservers();
-
- // Do not select a new printer, just press back
- getUiDevice().pressBack();
-
- // We are now in the PrintActivity
- // The media size should not change
- Log.i(LOG_TAG, "Make sure print attributes did not change");
- Thread.sleep(100);
- assertEquals(PrintAttributes.MediaSize.ISO_A0, printAttributes[0].getMediaSize());
-
- getUiDevice().pressBack();
-
- // We are back in the test activity
- Log.i(LOG_TAG, "Waiting for session to end");
- synchronized (session) {
- waitWithTimeout(() -> session[0] != null, session::wait);
- }
- }
-}
diff --git a/core/tests/coretests/src/android/util/LocalLogTest.java b/core/tests/coretests/src/android/util/LocalLogTest.java
new file mode 100644
index 0000000..a63c8a0
--- /dev/null
+++ b/core/tests/coretests/src/android/util/LocalLogTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import junit.framework.TestCase;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+
+public class LocalLogTest extends TestCase {
+
+ public void testA() {
+ String[] lines = {
+ "foo",
+ "bar",
+ "baz"
+ };
+ String[] want = lines;
+ testcase(new LocalLog(10), lines, want);
+ }
+
+ public void testB() {
+ String[] lines = {
+ "foo",
+ "bar",
+ "baz"
+ };
+ String[] want = {};
+ testcase(new LocalLog(0), lines, want);
+ }
+
+ public void testC() {
+ String[] lines = {
+ "dropped",
+ "dropped",
+ "dropped",
+ "dropped",
+ "dropped",
+ "dropped",
+ "foo",
+ "bar",
+ "baz",
+ };
+ String[] want = {
+ "foo",
+ "bar",
+ "baz",
+ };
+ testcase(new LocalLog(3), lines, want);
+ }
+
+ void testcase(LocalLog logger, String[] input, String[] want) {
+ for (String l : input) {
+ logger.log(l);
+ }
+ verifyAllLines(want, dump(logger).split("\n"));
+ verifyAllLines(reverse(want), reverseDump(logger).split("\n"));
+ }
+
+ void verifyAllLines(String[] wantLines, String[] gotLines) {
+ for (int i = 0; i < wantLines.length; i++) {
+ String want = wantLines[i];
+ String got = gotLines[i];
+ String msg = String.format("%s did not contain %s", quote(got), quote(want));
+ assertTrue(msg, got.contains(want));
+ }
+ }
+
+ static String dump(LocalLog logger) {
+ StringWriter buffer = new StringWriter();
+ PrintWriter writer = new PrintWriter(buffer);
+ logger.dump(null, writer, new String[0]);
+ return buffer.toString();
+ }
+
+ static String reverseDump(LocalLog logger) {
+ StringWriter buffer = new StringWriter();
+ PrintWriter writer = new PrintWriter(buffer);
+ logger.reverseDump(null, writer, new String[0]);
+ return buffer.toString();
+ }
+
+ static String quote(String s) {
+ return '"' + s + '"';
+ }
+
+ static String[] reverse(String[] ary) {
+ List<String> ls = Arrays.asList(ary);
+ Collections.reverse(ls);
+ return ls.toArray(new String[ary.length]);
+ }
+}
diff --git a/core/tests/coretests/src/android/util/TimeUtilsTest.java b/core/tests/coretests/src/android/util/TimeUtilsTest.java
deleted file mode 100644
index 2370627..0000000
--- a/core/tests/coretests/src/android/util/TimeUtilsTest.java
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (C) 2008 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.util;
-
-import junit.framework.TestCase;
-
-import java.util.Calendar;
-import java.util.TimeZone;
-
-/**
- * TimeUtilsTest tests the time zone guesser.
- */
-public class TimeUtilsTest extends TestCase {
- public void testMainstream() throws Exception {
- String[] mainstream = new String[] {
- "America/New_York", // Eastern
- "America/Chicago", // Central
- "America/Denver", // Mountain
- "America/Los_Angeles", // Pacific
- "America/Anchorage", // Alaska
- "Pacific/Honolulu", // Hawaii, no DST
- };
-
- for (String name : mainstream) {
- TimeZone tz = TimeZone.getTimeZone(name);
- Calendar c = Calendar.getInstance(tz);
- TimeZone guess;
-
- c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00);
- guess = guess(c, "us");
- assertEquals(name, guess.getID());
-
- c.set(2009, Calendar.JANUARY, 20, 12, 00, 00);
- guess = guess(c, "us");
- assertEquals(name, guess.getID());
- }
- }
-
- public void testWeird() throws Exception {
- String[] weird = new String[] {
- "America/Phoenix", // Mountain, no DST
- "America/Adak", // Same as Hawaii, but with DST
- };
-
- for (String name : weird) {
- TimeZone tz = TimeZone.getTimeZone(name);
- Calendar c = Calendar.getInstance(tz);
- TimeZone guess;
-
- c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00);
- guess = guess(c, "us");
- assertEquals(name, guess.getID());
- }
- }
-
- public void testOld() throws Exception {
- String[] old = new String[] {
- "America/Indiana/Indianapolis", // Eastern, formerly no DST
- };
-
- for (String name : old) {
- TimeZone tz = TimeZone.getTimeZone(name);
- Calendar c = Calendar.getInstance(tz);
- TimeZone guess;
-
- c.set(2005, Calendar.OCTOBER, 20, 12, 00, 00);
- guess = guess(c, "us");
- assertEquals(name, guess.getID());
- }
- }
-
- public void testWorld() throws Exception {
- String[] world = new String[] {
- "ad", "Europe/Andorra",
- "ae", "Asia/Dubai",
- "af", "Asia/Kabul",
- "ag", "America/Antigua",
- "ai", "America/Anguilla",
- "al", "Europe/Tirane",
- "am", "Asia/Yerevan",
- "an", "America/Curacao",
- "ao", "Africa/Luanda",
- "aq", "Antarctica/McMurdo",
- "aq", "Antarctica/DumontDUrville",
- "aq", "Antarctica/Casey",
- "aq", "Antarctica/Davis",
- "aq", "Antarctica/Mawson",
- "aq", "Antarctica/Syowa",
- "aq", "Antarctica/Rothera",
- "aq", "Antarctica/Palmer",
- "ar", "America/Argentina/Buenos_Aires",
- "as", "Pacific/Pago_Pago",
- "at", "Europe/Vienna",
- "au", "Australia/Sydney",
- "au", "Australia/Adelaide",
- "au", "Australia/Perth",
- "au", "Australia/Eucla",
- "aw", "America/Aruba",
- "ax", "Europe/Mariehamn",
- "az", "Asia/Baku",
- "ba", "Europe/Sarajevo",
- "bb", "America/Barbados",
- "bd", "Asia/Dhaka",
- "be", "Europe/Brussels",
- "bf", "Africa/Ouagadougou",
- "bg", "Europe/Sofia",
- "bh", "Asia/Bahrain",
- "bi", "Africa/Bujumbura",
- "bj", "Africa/Porto-Novo",
- "bm", "Atlantic/Bermuda",
- "bn", "Asia/Brunei",
- "bo", "America/La_Paz",
- "br", "America/Noronha",
- "br", "America/Sao_Paulo",
- "br", "America/Manaus",
- "bs", "America/Nassau",
- "bt", "Asia/Thimphu",
- "bw", "Africa/Gaborone",
- "by", "Europe/Minsk",
- "bz", "America/Belize",
- "ca", "America/St_Johns",
- "ca", "America/Halifax",
- "ca", "America/Toronto",
- "ca", "America/Winnipeg",
- "ca", "America/Edmonton",
- "ca", "America/Vancouver",
- "cc", "Indian/Cocos",
- "cd", "Africa/Lubumbashi",
- "cd", "Africa/Kinshasa",
- "cf", "Africa/Bangui",
- "cg", "Africa/Brazzaville",
- "ch", "Europe/Zurich",
- "ci", "Africa/Abidjan",
- "ck", "Pacific/Rarotonga",
- "cl", "America/Santiago",
- "cl", "Pacific/Easter",
- "cm", "Africa/Douala",
- "cn", "Asia/Shanghai",
- "co", "America/Bogota",
- "cr", "America/Costa_Rica",
- "cu", "America/Havana",
- "cv", "Atlantic/Cape_Verde",
- "cx", "Indian/Christmas",
- "cy", "Asia/Nicosia",
- "cz", "Europe/Prague",
- "de", "Europe/Berlin",
- "dj", "Africa/Djibouti",
- "dk", "Europe/Copenhagen",
- "dm", "America/Dominica",
- "do", "America/Santo_Domingo",
- "dz", "Africa/Algiers",
- "ec", "America/Guayaquil",
- "ec", "Pacific/Galapagos",
- "ee", "Europe/Tallinn",
- "eg", "Africa/Cairo",
- "eh", "Africa/El_Aaiun",
- "er", "Africa/Asmara",
- "es", "Europe/Madrid",
- "es", "Atlantic/Canary",
- "et", "Africa/Addis_Ababa",
- "fi", "Europe/Helsinki",
- "fj", "Pacific/Fiji",
- "fk", "Atlantic/Stanley",
- "fm", "Pacific/Ponape",
- "fm", "Pacific/Truk",
- "fo", "Atlantic/Faroe",
- "fr", "Europe/Paris",
- "ga", "Africa/Libreville",
- "gb", "Europe/London",
- "gd", "America/Grenada",
- "ge", "Asia/Tbilisi",
- "gf", "America/Cayenne",
- "gg", "Europe/Guernsey",
- "gh", "Africa/Accra",
- "gi", "Europe/Gibraltar",
- "gl", "America/Danmarkshavn",
- "gl", "America/Scoresbysund",
- "gl", "America/Godthab",
- "gl", "America/Thule",
- "gm", "Africa/Banjul",
- "gn", "Africa/Conakry",
- "gp", "America/Guadeloupe",
- "gq", "Africa/Malabo",
- "gr", "Europe/Athens",
- "gs", "Atlantic/South_Georgia",
- "gt", "America/Guatemala",
- "gu", "Pacific/Guam",
- "gw", "Africa/Bissau",
- "gy", "America/Guyana",
- "hk", "Asia/Hong_Kong",
- "hn", "America/Tegucigalpa",
- "hr", "Europe/Zagreb",
- "ht", "America/Port-au-Prince",
- "hu", "Europe/Budapest",
- "id", "Asia/Jayapura",
- "id", "Asia/Makassar",
- "id", "Asia/Jakarta",
- "ie", "Europe/Dublin",
- "il", "Asia/Jerusalem",
- "im", "Europe/Isle_of_Man",
- "in", "Asia/Calcutta",
- "io", "Indian/Chagos",
- "iq", "Asia/Baghdad",
- "ir", "Asia/Tehran",
- "is", "Atlantic/Reykjavik",
- "it", "Europe/Rome",
- "je", "Europe/Jersey",
- "jm", "America/Jamaica",
- "jo", "Asia/Amman",
- "jp", "Asia/Tokyo",
- "ke", "Africa/Nairobi",
- "kg", "Asia/Bishkek",
- "kh", "Asia/Phnom_Penh",
- "ki", "Pacific/Kiritimati",
- "ki", "Pacific/Enderbury",
- "ki", "Pacific/Tarawa",
- "km", "Indian/Comoro",
- "kn", "America/St_Kitts",
- "kp", "Asia/Pyongyang",
- "kr", "Asia/Seoul",
- "kw", "Asia/Kuwait",
- "ky", "America/Cayman",
- "kz", "Asia/Almaty",
- "kz", "Asia/Aqtau",
- "la", "Asia/Vientiane",
- "lb", "Asia/Beirut",
- "lc", "America/St_Lucia",
- "li", "Europe/Vaduz",
- "lk", "Asia/Colombo",
- "lr", "Africa/Monrovia",
- "ls", "Africa/Maseru",
- "lt", "Europe/Vilnius",
- "lu", "Europe/Luxembourg",
- "lv", "Europe/Riga",
- "ly", "Africa/Tripoli",
- "ma", "Africa/Casablanca",
- "mc", "Europe/Monaco",
- "md", "Europe/Chisinau",
- "me", "Europe/Podgorica",
- "mg", "Indian/Antananarivo",
- "mh", "Pacific/Majuro",
- "mk", "Europe/Skopje",
- "ml", "Africa/Bamako",
- "mm", "Asia/Rangoon",
- "mn", "Asia/Choibalsan",
- "mn", "Asia/Hovd",
- "mo", "Asia/Macau",
- "mp", "Pacific/Saipan",
- "mq", "America/Martinique",
- "mr", "Africa/Nouakchott",
- "ms", "America/Montserrat",
- "mt", "Europe/Malta",
- "mu", "Indian/Mauritius",
- "mv", "Indian/Maldives",
- "mw", "Africa/Blantyre",
- "mx", "America/Mexico_City",
- "mx", "America/Chihuahua",
- "mx", "America/Tijuana",
- "my", "Asia/Kuala_Lumpur",
- "mz", "Africa/Maputo",
- "na", "Africa/Windhoek",
- "nc", "Pacific/Noumea",
- "ne", "Africa/Niamey",
- "nf", "Pacific/Norfolk",
- "ng", "Africa/Lagos",
- "ni", "America/Managua",
- "nl", "Europe/Amsterdam",
- "no", "Europe/Oslo",
- "np", "Asia/Katmandu",
- "nr", "Pacific/Nauru",
- "nu", "Pacific/Niue",
- "nz", "Pacific/Auckland",
- "nz", "Pacific/Chatham",
- "om", "Asia/Muscat",
- "pa", "America/Panama",
- "pe", "America/Lima",
- "pf", "Pacific/Gambier",
- "pf", "Pacific/Marquesas",
- "pf", "Pacific/Tahiti",
- "pg", "Pacific/Port_Moresby",
- "ph", "Asia/Manila",
- "pk", "Asia/Karachi",
- "pl", "Europe/Warsaw",
- "pm", "America/Miquelon",
- "pn", "Pacific/Pitcairn",
- "pr", "America/Puerto_Rico",
- "ps", "Asia/Gaza",
- "pt", "Europe/Lisbon",
- "pt", "Atlantic/Azores",
- "pw", "Pacific/Palau",
- "py", "America/Asuncion",
- "qa", "Asia/Qatar",
- "re", "Indian/Reunion",
- "ro", "Europe/Bucharest",
- "rs", "Europe/Belgrade",
- "ru", "Asia/Kamchatka",
- "ru", "Asia/Magadan",
- "ru", "Asia/Vladivostok",
- "ru", "Asia/Yakutsk",
- "ru", "Asia/Irkutsk",
- "ru", "Asia/Krasnoyarsk",
- "ru", "Asia/Novosibirsk",
- "ru", "Asia/Yekaterinburg",
- "ru", "Europe/Samara",
- "ru", "Europe/Moscow",
- "ru", "Europe/Kaliningrad",
- "rw", "Africa/Kigali",
- "sa", "Asia/Riyadh",
- "sb", "Pacific/Guadalcanal",
- "sc", "Indian/Mahe",
- "sd", "Africa/Khartoum",
- "se", "Europe/Stockholm",
- "sg", "Asia/Singapore",
- "sh", "Atlantic/St_Helena",
- "si", "Europe/Ljubljana",
- "sj", "Arctic/Longyearbyen",
- "sk", "Europe/Bratislava",
- "sl", "Africa/Freetown",
- "sm", "Europe/San_Marino",
- "sn", "Africa/Dakar",
- "so", "Africa/Mogadishu",
- "sr", "America/Paramaribo",
- "st", "Africa/Sao_Tome",
- "sv", "America/El_Salvador",
- "sy", "Asia/Damascus",
- "sz", "Africa/Mbabane",
- "tc", "America/Grand_Turk",
- "td", "Africa/Ndjamena",
- "tf", "Indian/Kerguelen",
- "tg", "Africa/Lome",
- "th", "Asia/Bangkok",
- "tj", "Asia/Dushanbe",
- "tk", "Pacific/Fakaofo",
- "tl", "Asia/Dili",
- "tm", "Asia/Ashgabat",
- "tn", "Africa/Tunis",
- "to", "Pacific/Tongatapu",
- "tr", "Europe/Istanbul",
- "tt", "America/Port_of_Spain",
- "tv", "Pacific/Funafuti",
- "tw", "Asia/Taipei",
- "tz", "Africa/Dar_es_Salaam",
- "ua", "Europe/Kiev",
- "ug", "Africa/Kampala",
- "um", "Pacific/Wake",
- "um", "Pacific/Johnston",
- "um", "Pacific/Midway",
- "us", "America/New_York",
- "us", "America/Chicago",
- "us", "America/Denver",
- "us", "America/Los_Angeles",
- "us", "America/Anchorage",
- "us", "Pacific/Honolulu",
- "uy", "America/Montevideo",
- "uz", "Asia/Tashkent",
- "va", "Europe/Vatican",
- "vc", "America/St_Vincent",
- "ve", "America/Caracas",
- "vg", "America/Tortola",
- "vi", "America/St_Thomas",
- "vn", "Asia/Saigon",
- "vu", "Pacific/Efate",
- "wf", "Pacific/Wallis",
- "ws", "Pacific/Apia",
- "ye", "Asia/Aden",
- "yt", "Indian/Mayotte",
- "za", "Africa/Johannesburg",
- "zm", "Africa/Lusaka",
- "zw", "Africa/Harare",
- };
-
- for (int i = 0; i < world.length; i += 2) {
- String country = world[i];
- String name = world[i + 1];
-
- TimeZone tz = TimeZone.getTimeZone(name);
- Calendar c = Calendar.getInstance(tz);
- TimeZone guess;
-
- c.set(2009, Calendar.JULY, 20, 12, 00, 00);
- guess = guess(c, country);
- assertEquals(name, guess.getID());
-
- c.set(2009, Calendar.JANUARY, 20, 12, 00, 00);
- guess = guess(c, country);
- assertEquals(name, guess.getID());
- }
- }
-
- public void testWorldWeird() throws Exception {
- String[] world = new String[] {
- // Distinguisable from Sydney only when DST not in effect
- "au", "Australia/Lord_Howe",
- };
-
- for (int i = 0; i < world.length; i += 2) {
- String country = world[i];
- String name = world[i + 1];
-
- TimeZone tz = TimeZone.getTimeZone(name);
- Calendar c = Calendar.getInstance(tz);
- TimeZone guess;
-
- c.set(2009, Calendar.JULY, 20, 12, 00, 00);
- guess = guess(c, country);
- assertEquals(name, guess.getID());
- }
- }
-
- private static TimeZone guess(Calendar c, String country) {
- return TimeUtils.getTimeZone(c.get(c.ZONE_OFFSET) + c.get(c.DST_OFFSET),
- c.get(c.DST_OFFSET) != 0,
- c.getTimeInMillis(),
- country);
- }
-
- public void testFormatDuration() {
- assertFormatDuration("0", 0);
- assertFormatDuration("-1ms", -1);
- assertFormatDuration("+1ms", 1);
- assertFormatDuration("+10ms", 10);
- assertFormatDuration("+100ms", 100);
- assertFormatDuration("+101ms", 101);
- assertFormatDuration("+330ms", 330);
- assertFormatDuration("+1s0ms", 1000);
- assertFormatDuration("+1s330ms", 1330);
- assertFormatDuration("+10s24ms", 10024);
- assertFormatDuration("+1m0s30ms", 60030);
- assertFormatDuration("+1h0m0s30ms", 3600030);
- assertFormatDuration("+1d0h0m0s30ms", 86400030);
- }
-
- public void testFormatHugeDuration() {
- assertFormatDuration("+15542d1h11m11s555ms", 1342833071555L);
- assertFormatDuration("-15542d1h11m11s555ms", -1342833071555L);
- }
-
- private void assertFormatDuration(String expected, long duration) {
- StringBuilder sb = new StringBuilder();
- TimeUtils.formatDuration(duration, sb);
- assertEquals("formatDuration(" + duration + ")", expected, sb.toString());
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/os/DebugTest.java b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
index 88c7d1b..efb78d7 100644
--- a/core/tests/coretests/src/com/android/internal/os/DebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
@@ -64,4 +64,12 @@
public void testGetCallers() {
assertTrue(callDepth1().matches(EXPECTED_GET_CALLERS));
}
+
+ /**
+ * Regression test for b/31943543. Note: must be run under CheckJNI to detect the issue.
+ */
+ public void testGetMemoryInfo() {
+ Debug.MemoryInfo info = new Debug.MemoryInfo();
+ Debug.getMemoryInfo(-1, info);
+ }
}
diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk
index ffc1282..e16c367 100644
--- a/core/tests/systemproperties/Android.mk
+++ b/core/tests/systemproperties/Android.mk
@@ -11,7 +11,6 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
LOCAL_CERTIFICATE := platform
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index 8ddb982..6185dab 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -289,6 +289,8 @@
to: /design/patterns/app-structure.html
- from: /guide/practices/ui_guidelines/menu_design.html
to: /design/patterns/actionbar.html
+- from: /design/patterns/accessibility.html
+ to: https://material.google.com/usability/accessibility.html
- from: /design/get-started/ui-overview.html
to: /design/handhelds/index.html
- from: /design/building-blocks/buttons.html
@@ -430,7 +432,13 @@
- from: /training/cloudsync/aesync.html
to: /google/gcm/index.html
- from: /training/cloudsync/index.html
- to: /training/backup/index.html
+ to: /guide/topics/data/backup.html
+- from: /training/backup/index.html
+ to: /guide/topics/data/backup.html
+- from: /training/backup/autosyncapi.html
+ to: /guide/topics/data/autobackup.html
+- from: /training/backup/backupapi.html
+ to: /guide/topics/data/keyvaluebackup.html
- from: /training/basics/location/...
to: /training/location/...
- from: /training/monetization/index.html
@@ -796,11 +804,11 @@
- from: /preview/features/app-linking.html
to: /training/app-links/index.html
- from: /preview/backup/index.html
- to: /training/backup/autosyncapi.html
+ to: /guide/topics/data/backup/autobackup.html
- from: /preview/features/power-mgmt.html
to: /training/monitoring-device-state/doze-standby.html
- from: /preview/dev-community
- to: https://plus.google.com/communities/103655397235276743411
+ to: https://plus.google.com/communities/105153134372062985968
- from: /preview/bug
to: https://source.android.com/source/report-bugs.html
- from: /preview/bug/...
@@ -842,6 +850,10 @@
to: /topic/performance/power/network/gather-data.html
- from: /training/performance/battery/network/index.html
to: /topic/performance/power/network/index.html
+- from: /training/articles/memory.html
+ to: /topic/performance/memory.html
+- from: /topic/performance/optimizing-view-hierarchies.html
+ to: /topic/performance/rendering/optimizing-view-hierarchies.html
# Redirects for the new [dac]/topic/libraries/ area
@@ -1242,6 +1254,46 @@
to: /studio/write/lint.html?utm_source=android-studio
- from: /r/studio-ui/gradle-console.html
to: /studio/run/index.html?utm_source=android-studio#gradle-console
+- from: /r/studio-ui/app-indexing-test.html
+ to: /studio/write/app-link-indexing.html#appindexingtest?utm_source=android-studio
+- from: /r/studio-ui/vcs.html
+ to: /studio/intro/index.html#version_control_basics?utm_source=android-studio
+- from: /r/studio-ui/create-new-module.html
+ to: /studio/projects/index.html#ApplicationModules?utm_source=android-studio
+- from: /r/studio-ui/build-variants.html
+ to: /studio/run/index.html#changing-variant?utm_source=android-studio
+- from: /r/studio-ui/generate-signed-apk.html
+ to: /studio/publish/app-signing.html#release-mode?utm_source=android-studio
+- from: /r/studio-ui/import-project-vcs.html
+ to: /studio/projects/create-project.html#ImportAProject?utm_source=android-studio
+- from: /r/studio-ui/apk-analyzer.html
+ to: /studio/build/apk-analyzer.html?utm_source=android-studio
+- from: /r/studio-ui/breakpoints.html
+ to: /studio/debug/index.html#breakPointsView?utm_source=android-studio
+- from: /r/studio-ui/attach-debugger-to-process.html
+ to: /studio/debug/index.html?utm_source=android-studio
+- from: /r/studio-ui/import-sample.html
+ to: /samples/index.html?utm_source=android-studio
+- from: /r/studio-ui/import-module.html
+ to: /studio/projects/add-app-module.html#ImportAModule?utm_source=android-studio
+- from: /r/studio-ui/import-project.html
+ to: /studio/projects/create-project.html#ImportAProject?utm_source=android-studio
+- from: /r/studio-ui/create-project.html
+ to: /studio/projects/create-project.html?utm_source=android-studio
+- from: /r/studio-ui/new-activity.html
+ to: /studio/projects/template.html?utm_source=android-studio
+- from: /r/studio-ui/new-resource-file.html
+ to: /studio/write/add-resources.html?utm_source=android-studio
+- from: /r/studio-ui/new-resource-dir.html
+ to: /studio/write/add-resources.html#add_a_resource_directory?utm_source=android-studio
+- from: /r/studio-ui/configure-component.html
+ to: /studio/write/add-resources.html?utm_source=android-studio
+- from: /r/studio-ui/ninepatch.html
+ to: /studio/write/draw9patch.html?utm_source=android-studio
+- from: /r/studio-ui/firebase-assistant.html
+ to: /studio/write/firebase.html?utm_source=android-studio
+- from: /r/studio-ui/ir-flight-recorder.html
+ to: /studio/run/index.html?utm_source=android-studio#submit-feedback
# Redirects from (removed) N Preview documentation
- from: /preview/features/afw.html
diff --git a/docs/html/about/versions/_project.yaml b/docs/html/about/versions/_project.yaml
new file mode 100644
index 0000000..3f0e85e
--- /dev/null
+++ b/docs/html/about/versions/_project.yaml
@@ -0,0 +1,6 @@
+name: "Versions"
+home_url: /about/versions/
+description: "Android, the world's most popular mobile platform"
+content_license: cc3-apache2
+buganizer_id: 30209417
+parent_project_metadata_path: /about/_project.yaml
diff --git a/docs/html/about/versions/nougat/android-7.0-samples.jd b/docs/html/about/versions/nougat/android-7.0-samples.jd
index e283a7a..ff63bef 100644
--- a/docs/html/about/versions/nougat/android-7.0-samples.jd
+++ b/docs/html/about/versions/nougat/android-7.0-samples.jd
@@ -6,7 +6,7 @@
<p>
Use the code samples below to learn about Android 7.0 capabilities and APIs. To
- download the samples in Android Studio, select the <b>File > Import
+ download the samples in Android Studio, select the <b>File > New > Import
Samples</b> menu option.
</p>
diff --git a/docs/html/auto/_project.yaml b/docs/html/auto/_project.yaml
new file mode 100644
index 0000000..fc4ab2b
--- /dev/null
+++ b/docs/html/auto/_project.yaml
@@ -0,0 +1,6 @@
+name: "Auto"
+home_url: /auto/
+description: "Let drivers listen to and control content in your music and other audio apps."
+content_license: cc3-apache2
+buganizer_id: 30209417
+parent_project_metadata_path: /about/_project.yaml
diff --git a/docs/html/design/_book.yaml b/docs/html/design/_book.yaml
index 18b4719..8ffa9a4 100644
--- a/docs/html/design/_book.yaml
+++ b/docs/html/design/_book.yaml
@@ -117,8 +117,6 @@
path: /design/patterns/pure-android.html
- title: Compatibility
path: /design/patterns/compatibility.html
- - title: Accessibility
- path: /design/patterns/accessibility.html
- title: Help
path: /design/patterns/help.html
diff --git a/docs/html/design/patterns/accessibility.jd b/docs/html/design/patterns/accessibility.jd
deleted file mode 100644
index b910294..0000000
--- a/docs/html/design/patterns/accessibility.jd
+++ /dev/null
@@ -1,98 +0,0 @@
-page.title=Accessibility
-page.tags="accessibility","navigation","input"
-page.metaDescription=Design an app that's universally accessible to people with visual impairment, color deficiency, hearing loss, and limited dexterity.
-@jd:body
-
-<a class="notice-designers-material"
- href="http://www.google.com/design/spec/usability/accessibility.html">
- <div>
- <h3>Material Design</h3>
- <p>Accessibility<p>
- </div>
-</a>
-
-<a class="notice-developers" href="{@docRoot}training/accessibility/index.html">
- <div>
- <h3>Developer Docs</h3>
- <p>Implementing Accessibility</p>
- </div>
-</a>
-
-<p>One of Android's missions is to organize the world's information and make it universally accessible and useful. Accessibility is the measure of how successfully a product can be used by people with varying abilities. Our mission applies to all users-including people with disabilities such as visual impairment, color deficiency, hearing loss, and limited dexterity.</p>
-<p><a href="https://www.google.com/#hl=en&q=universal+design&fp=1">Universal design</a> is the practice of making products that are inherently accessible to all users, regardless of ability. The Android design patterns were created in accordance with universal design principles, and following them will help your app meet basic usability standards. Adhering to universal design and enabling Android's accessibility tools will make your app as accessible as possible.</p>
-<p>Robust support for accessibility will increase your app's user base. It may also be required for adoption by some organizations.</p>
-<p><a href="http://www.google.com/accessibility/">Learn more about Google and accessibility.</a></p>
-
-<h2 id="tools">Android's Accessibility Tools</h2>
-<p>Android includes several features that support access for users with visual impairments; they don't require drastic visual changes to your app.</p>
-
-<ul>
- <li><strong><a href="https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback">TalkBack</a></strong> is a pre-installed screen reader service provided by Google. It uses spoken feedback to describe the results of actions such as launching an app, and events such as notifications.</li>
- <li><strong>Explore by Touch</strong> is a system feature that works with TalkBack, allowing you to touch your device's screen and hear what's under your finger via spoken feedback. This feature is helpful to users with low vision.</li>
- <li><strong>Accessibility settings</strong> let you modify your device's display and sound options, such as increasing the text size, changing the speed at which text is spoken, and more.</li>
-</ul>
-
-<p>Some users use hardware or software directional controllers (such as a D-pad, trackball, keyboard) to jump from selection to selection on a screen. They interact with the structure of your app in a linear fashion, similar to 4-way remote control navigation on a television.</p>
-
-<h2 id="tools">Guidelines</h2>
-<p>The Android design principle "I should always know where I am" is key for accessibility concerns. As a user navigates through an application, they need feedback and a mental model of where they are. All users benefit from a strong sense of information hierarchy and an architecture that makes sense. Most users benefit from visual and haptic feedback during their navigation (such as labels, colors, icons, touch feedback) Low vision users benefit from explicit verbal descriptions and large visuals with high contrast.</p>
-<p>As you design your app, think about the labels and notations needed to navigate your app by sound. When using Explore by Touch, the user enables an invisible but audible layer of structure in your application. Like any other aspect of app design, this structure can be simple, elegant, and robust. The following are Android's recommended guidelines to enable effective navigation for all users.</p>
-
-<h4>Make navigation intuitive</h4>
-<p>Design well-defined, clear task flows with minimal navigation steps, especially for major user tasks. Make sure those tasks are navigable via focus controls. </p>
-
-<h4>Use recommended touch target sizes</h4>
-<p>48 dp is the recommended touch target size for on screen elements. Read about <a href="{@docRoot}design/style/metrics-grids.html">Android Metrics and Grids</a> to learn about implementation strategies to help most of your users. For certain users, it may be appropriate to use larger touch targets. An example of this is educational apps, where buttons larger than the minimum recommendations are appropriate for children with developing motor skills and people with manual dexterity challenges.</p>
-
-
-<h4>Label visual UI elements meaningfully</h4>
-<p>In your wireframes, <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#label-ui">label functional UI components</a> that have no visible text. Those components might be buttons, icons, tabs with icons, and icons with state (like stars). Developers can use the <code><a href="{@docRoot}guide/topics/ui/accessibility/apps.html#label-ui">contentDescription</a></code> attribute to set the label.</p>
-
-<div class ="cols">
- <div class="col-8">
- <img src="{@docRoot}design/media/accessibility_contentdesc.png">
- </div>
- <div class="col-5 with-callouts">
- <ol>
- <li class="value-1">group</li>
- <li class="value-2">all contacts</li>
- <li class="value-3">favorites</li>
- <li class="value-4">search</li>
- <li class="value-5">action overflow button</li>
- <li class="value-6">
- <em>when starred:</em> remove from favorites </br>
- <em>when not starred:</em> add to favorties</li>
- <li class="value-7">action overflow button</li>
- <li class="value-8">text message</li>
- </ol>
- </div>
-</div>
-
-<h4>Provide alternatives to affordances that time out</h4>
-<p>Your app may have icons or controls that disappear after a certain amount of time. For example, five seconds after starting a video, playback controls may fade from the screen.</p>
-
-<p>Due to the way that TalkBack works, those controls are not read out loud unless they are focused on. If they fade out from the screen quickly, your user may not even be aware that they are available. Therefore, make sure that you are not relying on timed out controls for high priority task flows. (This is a good universal design guideline too.) If the controls enable an important function, make sure that the user can turn on the controls again and/or their function is duplicated elsewhere. You can also change the behavior of your app when accessibility services are turned on. Your developer may be able to make sure that timed-out controls won't disappear.</p>
-
-<h4>Use standard framework controls or enable TalkBack for custom controls</h4>
-<p>Standard Android framework controls work automatically with accessibility services and have ContentDescriptions built in by default.</p>
-
-<p>An oft-overlooked system control is font size. Users can turn on a system-wide large font size in Settings; using the default system font size in your application will enable the user's preferences in your app as well. To enable system font size in your app, mark text and their associated containers to be measured in <a href="{@docRoot}guide/practices/screens_support.html#screen-independence">scale pixels</a>.</p>
-
-<p>Also, keep in mind that when users have large fonts enabled or speak a different language than you, their type might be larger than the space you've allotted for it. Read <a href="{@docRoot}design/style/devices-displays.html">Devices and Displays</a> and <a href="http://developer.android.com/guide/practices/screens_support.html">Supporting Multiple Screens</a> for design strategies.</p>
-
-<p>If you use custom controls, Android has the developer tools in place to allow adherence to the above guidelines and provide meaningful descriptions about the UI. Provide adequate notation on your wireframes and direct your developer to the <a href="{@docRoot}guide/topics/ui/accessibility/apps.html#custom-views">Custom Views</a> documentation.</p>
-
-<h4>Try it out yourself</h4>
-<p>Turn on the TalkBack service in <strong>Settings > Accessibility</strong> and navigate your application using directional controls or eyes-free navigation.</p>
-
-
-
-<h2>Checklist</h2>
-<ul>
- <li>Make navigation intuitive</li>
- <li>Use recommended touch target sizes</li>
- <li>Label visual UI elements meaningfully</li>
- <li>Provide alternatives to affordances that time out</li>
- <li>Use standard framework controls or enable TalkBack for custom controls</li>
- <li>Try it out yourself</li>
-</ul>
diff --git a/docs/html/distribute/stories/apps.jd b/docs/html/distribute/stories/apps.jd
index 76e9f5a..47f4f7f 100644
--- a/docs/html/distribute/stories/apps.jd
+++ b/docs/html/distribute/stories/apps.jd
@@ -25,8 +25,7 @@
<h2 class="norule">Articles</h2>
<div class="resource-widget resource-flow-layout col-16"
- data-query="type:distribute+tag:developerstory+tag:apps"
- data-sortOrder="-timestamp"
+ data-query="collection:distribute/stories/apps/docs"
data-cardSizes="6x6"
data-items-per-page="15"
data-initial-results="6"></div>
diff --git a/docs/html/distribute/stories/apps/condenast-shopping.jd b/docs/html/distribute/stories/apps/condenast-shopping.jd
new file mode 100644
index 0000000..37c2b1f
--- /dev/null
+++ b/docs/html/distribute/stories/apps/condenast-shopping.jd
@@ -0,0 +1,76 @@
+page.title=Glamour.de Connects Offline and Online Shopping Experiences with Google Play Billing
+page.metaDescription=Condé Nast improves features on its Glamour app.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/glamour.png
+page.timestamp=null
+
+@jd:body
+
+
+<h3>Background</h3>
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/glamour-icon.png" />
+</div>
+
+<p>
+ Glamour is one of the main
+ <a class="external-link"
+ href="https://play.google.com/store/apps/developer?id=Cond%C3%A9%20Nast%20Verlag%20GmbH&hl=en">
+ Condé Nast</a> traditional brands. Every year, Glamour hosts a
+ successful shopping event called
+ <a class="external-link"
+ href="https://play.google.com/store/apps/details?id=de.glamour.android&e=-EnableAppDetailsPageRedesign">
+ <em>GLAMOUR Shopping-Week</em></a> in Germany, Austria, and Switzerland.
+ This event has always been print-focused, as readers received a shopping
+ card with the magazine to redeem discounts in selected shops, both offline
+ and online, for one week.
+</p>
+
+<p>
+ In March 2016, Glamour digitized this experience.
+</p>
+
+<h3>What they did</h3>
+
+<p>
+ To make the most of <em>GLAMOUR Shopping-Week</em>, Condé Nast relaunched the
+ <a class="external-link"
+ href="https://play.google.com/store/apps/details?id=de.condenast.glamourde&e=-EnableAppDetailsPageRedesign">
+ GLAMOUR app</a> with a more appealing design and an improved user experience:
+<ul>
+ <li>The main features updated for the shopping week included a shop finder, online offers, and
+ a digital shopping card.</li>
+ <li>The current e-paper magazine was made available through the app and sold via Google Play
+ Billing.</li>
+ <li>They offered readers the in-app purchase of digital shopping cards and activation codes
+ through Google Play Billing. Readers can activate digital shopping cards via in-app
+ purchases or with the print shopping card activation code.</li>
+ <li>The online and offline shopping experience was also supported by online shopping discount
+ codes in the app or offline through the shop finder.</li>
+</ul>
+</p>
+
+<h3>Results</h3>
+
+<p>
+ The offline and online combination resulted in positive engagement both in terms of app
+ installs and sales:
+<ul>
+ <li>There were 130,000 new app downloads, and 100,000 users enabled location access to use
+ the shop finder.</li>
+ <li><strong>Sessions increased by 140%</strong> compared to previous weeks. Session length
+ doubled and <strong>the number of active users grew by five times</strong>.</li>
+ <li>12,000 in-app purchases were generated, increasing general e-paper sales by six times,
+ which resulted in <strong>an increase in total magazine circulation</strong>.</li>
+ <li>The digital shopping card was shown more than 200,000 times to redeem offers in shops.</li>
+</ul>
+</p>
+
+<h3>Get started</h3>
+
+<p>
+ Find out more about
+ <a href="https://developer.android.com/google/play/billing/billing_overview.html">
+ in-app purchases</a>.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/stories/apps/drupe-communications.jd b/docs/html/distribute/stories/apps/drupe-communications.jd
new file mode 100644
index 0000000..4284077
--- /dev/null
+++ b/docs/html/distribute/stories/apps/drupe-communications.jd
@@ -0,0 +1,98 @@
+page.title=drupe Launches Android First and Finds Global Success with Beta Testing
+page.metaDescription=Drupe uses beta testing to increase its global reach.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/drupe.jpg
+page.timestamp=1468901832
+
+@jd:body
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/drupe-icon.png" />
+</div>
+
+<h3>
+ Background
+</h3>
+
+<p>
+ In 2015, <a class="external-link" href=
+ "https://play.google.com/store/apps/dev?id=8486231504544197967">
+ drupe mobile</a>, founded by Assaf Ziv and Barak Witkowski, launched the
+ <a class="external-link" href=
+ "https://play.google.com/store/apps/details?id=mobi.drupe.app">drupe app</a>
+ on Android first. With a unique, people-first approach, their communications
+ app is focused on reinventing the way people use their phone to do basic
+ actions. By constantly improving and expanding their cross-app
+ functionality, the app is used globally and was recently awarded Google
+ Play’s Editor’s Choice recognition.
+</p>
+
+<h3>
+ What they did
+</h3>
+
+<dl>
+ <dt><strong>Android openness</strong></dt>
+ <dd>From the start, drupe knew Android was their ideal mobile platform.
+ <em>"Thanks to the openness of the system, we can build a truly native
+ experience on Android. The real way to supply a people-centric experience
+ requires such an openness, not always existing on other platforms,"</em>
+ said Barak Witkowski, co-founder and CEO of drupe. Key to their innovative
+ approach, drupe uses the current context of the user to show them the
+ right contacts and actions to optimize the drupe experience.</dd>
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/drupe-screenshot.png">
+</div>
+
+ <dt><strong>Beta testing</strong></dt>
+ <dd>They have a large community of 20,000 <em>druper</em> beta users on
+ Android, which has been critical to their success. To minimize risk and seek
+ feedback from valued users, the team built beta testing into their regular
+ development process. By having a dialogue with users worldwide, they are able
+ to gauge interest in new app versions, collect feature requests, and more.
+ This has helped the team achieve a 99.7% crash-free user ratio, as well
+ as verify new versions in real-life scenarios, on various devices, before
+ full launch.</dd>
+
+ <dt><strong>Going global</strong></dt>
+ <dd>With initial focus on building a high quality app, drupe then set out
+ to take advantage of Android’s global scale. Key to their international
+ growth, the app is now translated in 17 languages, and the store listing
+ page is available in 28 languages. This led to an increase in conversion
+ and retention rates. Additionally, when entering India, the team noticed
+ several user reviews requesting integration with a specific messaging app
+ widely used in the Indian market. Through a combination of this integration,
+ adding Hindi language translation, and other new features, drupe saw improved
+ performance. In six months, <strong>daily active users increased 300%, and
+ actions per average daily user increased 25% in the Indian
+ market</strong>.</dd>
+</dl>
+
+<h3>
+ Results
+</h3>
+
+<p>
+ Drupe’s focus on innovation and building a truly contextual and intuitive
+ app proved to be a model of success for attaining growth in both engagement
+ and new global reach. The team has continued to increase its relevance
+ through feedback loops and feature adoptions. <strong>This has led to 700%
+ growth in daily active users, and 550% growth in number of interactions
+ triggered via drupe</strong> in the past six months. The team is focused on
+ enhancing their recommendation engine to add even more contextual abilities
+ for their users while continuing to grow a successful business on Google
+ Play.
+</p>
+
+<h3>
+ Get started
+</h3>
+
+<p>
+ Learn more about
+ <a href="{@docRoot}distribute/engage/beta.html">beta testing</a>
+ and find out how to
+ <a href="{@docRoot}distribute/tools/localization-checklist.html">
+ localize your app</a> to create a high-quality experience for global users.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/stories/apps/economist-espresso.jd b/docs/html/distribute/stories/apps/economist-espresso.jd
new file mode 100644
index 0000000..441393b
--- /dev/null
+++ b/docs/html/distribute/stories/apps/economist-espresso.jd
@@ -0,0 +1,70 @@
+page.title=The Economist Espresso Increases Ratings by Launching Rating Requests
+page.metaDescription=The Economist improves ratings through user participation.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/economist-espresso.png
+page.timestamp=null
+
+@jd:body
+
+
+<h3>Background</h3>
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/economist-espresso-icon.png" />
+</div>
+
+<p>
+ <a class="external-link" href="https://play.google.com/store/apps/details?id=uk.co.economist">
+ The Economist</a> launched the
+ <a class="external-link" href="https://play.google.com/store/apps/details?id=com.economist.darwin">
+ Espresso</a> app in November 2014. Espresso offers a morning briefing from the editors of The
+ Economist, six days a week. Delivered to readers’ mobile phones first thing in the morning, it
+ provides an overview of the global agenda for the coming day. It informs readers about what to
+ look out for in business, finance, and politics, and most importantly, what to make of it.
+</p>
+
+<p>
+ While the app received a lot of positive feedback from users on traditional customer support
+ channels, it received less feedback through direct app reviews. The Economist decided to run
+ tests to increase app reviews, resulting in improved ratings.
+
+<h3>What they did</h3>
+
+<p>
+ In April 2016, The Economist began testing to determine if asking for reviews would improve
+ user participation. They introduced rating requests into the app whereby users received a
+ notification asking them to rate the app while using it.
+</p>
+
+<p>
+ They prompted only users who had fully experienced the app, notifying those who had read more
+ than 25 articles after using it for more than a week. The prompt text was branded:
+ <em>Are you enjoying the Economist Espresso?</em> Upon clicking <em>yes</em>, the user was
+ taken to the Google Play store to review and rate the app.
+
+<h3>Results</h3>
+
+<p>
+ By capturing readers’ feedback in the Play store, The Economist was able to share the goodwill
+ and positive sentiment, <strong>further increasing its star rating and the number of app
+ installs</strong>.
+</p>
+
+<p>
+ After just one week following the launch of rating requests, The Espresso app's star rating
+ increased by 5%, with <strong>the average number of ratings received growing 40 times</strong>.
+</p>
+
+<h3>Get started</h3>
+
+<p>
+ Find out more about
+ <a class="external-link" href="https://support.google.com/googleplay/android-developer/answer/138230">
+ ratings and reviews</a>.
+</p>
+
+<p>
+ Get best practices for news publishers in
+ <a class="external-link" href="https://play.google.com/store/books/details/Google_Inc_The_News_Publisher_Playbook_for_Android?id=O7T3CwAAQBAJ&hl=en_GB&e=-EnableAppDetailsPageRedesign">
+ The News Publisher Playbook (for Android development)</a>.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/stories/apps/expressen-sports.jd b/docs/html/distribute/stories/apps/expressen-sports.jd
new file mode 100644
index 0000000..b53cb62
--- /dev/null
+++ b/docs/html/distribute/stories/apps/expressen-sports.jd
@@ -0,0 +1,57 @@
+page.title=Expressen Sport App Improves Content Engagement with New Onboarding and Navigation
+page.metaDescription=Expressen enhances their Sport app.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/expressen-sport.png
+page.timestamp=null
+
+@jd:body
+
+
+<h3>Background</h3>
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/expressen-icon.png" />
+</div>
+
+<p>
+ In January 2016,
+ <a class="external-link" href="https://play.google.com/store/apps/details?id=se.expressen.launcher&hl=en">
+ Expressen</a> launched a new sports app to reach sports enthusiasts directly
+ and to better optimize the app for sports content. They decided to analyze
+ users' behavior by looking at user paths in existing sports content,
+ combined with user research and testing various prototypes with real users.
+ They found that readers have different needs and preferences. For example,
+ some people like a specific sport, league, or player that others have no
+ interest in. Following these results, they integrated two main changes to
+ increase appeal to different types of readers.
+</p>
+
+<h3>What they did</h3>
+
+<p>
+ Expressen introduced a new onboarding flow that allows users to select the
+ type of push notifications they want to subscribe to. They also implemented
+ contextual navigation where the top header navigational links change,
+ showing the most relevant links to the reader at that moment in time. For
+ example, if you're reading about football, relevant links about that sport
+ are displayed.
+</p>
+
+<h3>Results</h3>
+
+<p>
+ After the new release of the app, <strong>results showed a higher opt-in
+ rate for push notifications in the Sport app (+16.9%)</strong> compared to
+ their main app, and content consumption increased +7% for page views and
+ +8.3% for video views.
+</p>
+
+<h3>Get started</h3>
+
+<p>
+ Learn more about the
+ <a href="https://developer.android.com/training/tv/playback/onboarding.html?hl=mk">
+ user onboarding flow</a> and find out how to
+ <a href="https://developer.android.com/design/patterns/navigation.html">
+ implement contextual navigation</a>.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/stories/apps/lifesum-health.jd b/docs/html/distribute/stories/apps/lifesum-health.jd
new file mode 100644
index 0000000..2d3f203
--- /dev/null
+++ b/docs/html/distribute/stories/apps/lifesum-health.jd
@@ -0,0 +1,60 @@
+page.title=Lifesum Doubles Retention of Google Fit Users Following Integration on Android
+page.metaDescription=Lifesum integrates Google Fit into their app.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/lifesum.png
+page.timestamp=null
+
+@jd:body
+
+
+<h3>Background</h3>
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/lifesum-icon.png" />
+</div>
+
+<p>
+ <a class="external-link" href="https://play.google.com/store/apps/details?id=com.sillens.shapeupclub">
+ Lifesum</a> is a health and fitness app from Sweden that was launched on Android in 2012.
+ Since then, the app has had more than five million installs on Android, and Lifesum collaborated
+ with Google for the launch of <a class="external-link" href="http://www.google.com/fit/">
+ Google Fit</a> in 2014. Google Fit soon became a key component of user activity outside the
+ app and has enabled Lifesum to scale partner integrations, accelerate development cycle, and
+ increase user satisfaction and engagement.
+</p>
+
+<h3>What they did</h3>
+
+<p>
+ Lifesum integrated Google Fit APIs to gather more insightful data, leading to a shift in
+ focus from simply gathering large amounts of user data to actual analysis of it. Google Fit has
+ also made direct integrations with partners much easier to scale and sometimes even
+ unnecessary, and has largely reduced app development time. Lifesum used findings from the
+ integration to launch their second app, <em>Movesum</em>, a step-counter app that imports steps
+ and calories and displays the information in a fun way. Thanks to the integration, the app was
+ developed in just two weeks.
+</p>
+
+<h3>Results</h3>
+
+<p>
+ Lifesum’s users now actively request integration with Google Fit, resulting in an improvement
+ in the app's ratings and reviews on the Google Play store. Engagement is also much higher for
+ Google Fit-connected users, whose <strong>retention rate is twice that of other Android
+ users</strong>. User retention on Android is 5-10% better than on other platforms.
+</p>
+
+<p>
+ Joakim Hammer, Android developer at Lifesum, says "Google Fit is our infrastructure for
+ integrating with other apps. It's great for the user as it increases the trustworthiness of the
+ data. Personally, it’s been a great experience leading the integration. The implementation was
+ fast and easy, and it has helped us with everything from product development and user
+ engagement, to partnerships."
+</p>
+
+<h3>Get started</h3>
+
+<p>
+ Find out more about <a class="external-link" href="https://developers.google.com/fit/">
+ The Google Fit SDK</a>.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/stories/apps/noom-health.jd b/docs/html/distribute/stories/apps/noom-health.jd
new file mode 100644
index 0000000..c99efac
--- /dev/null
+++ b/docs/html/distribute/stories/apps/noom-health.jd
@@ -0,0 +1,115 @@
+page.title=Noom Grows International Revenue by 80% Through Localization on Google Play
+page.metaDescription=Noom increases revenue by localizing their app.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/noom.jpg
+page.timestamp=1468901832
+
+@jd:body
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/noom-icon.png" />
+</div>
+
+<h3>
+ Background
+</h3>
+
+<p>
+ With a mission to help people live healthier lives,
+ <a class="external-link" href=
+ "https://play.google.com/store/apps/developer?id=Noom+Inc.">Noom</a> guides
+ their users through behavior change programs to create lifestyle habits and
+ target global health challenges. Available initially on Google Play,
+ Android first and Noom have achieved success expanding to international
+ markets, taking advantage of the broad reach of Android.
+</p>
+
+<h3>
+ What they did
+</h3>
+
+<p>
+ Launching first in the US, Noom created a series of programs tailored to
+ their users’ specific <a class="external-link" href=
+ "https://play.google.com/store/apps/details?id=com.wsl.noom">
+ health goals</a>. Key to their approach is offering a holistic solution,
+ including simple personalized tasks, progress tracking, meal feedback, and
+ support from both personal coaches and peers. The team has a strategic
+ approach to expanding their user base globally. Noom localized their app to
+ better connect with users in the following areas:
+</p>
+
+<ul>
+ <li><strong>Localized product</strong>
+ <ul style="list-style: none;">
+ <li>In addition to translating their app to five languages and their store
+ listing page to 11 languages, Noom conducted extensive analysis to
+ determine the right financial model tailored to each international
+ market. This included evaluation of their competitive landscape and
+ local health and wellness spending behavior, in addition to running
+ pricing experiments to determine the optimal offering between
+ subscriptions, IAPs, or a premium app.</li>
+ </ul>
+ </li>
+
+ <li><strong>Localized cuisines</strong>
+ <ul style="list-style: none;">
+ <li>When Noom started researching the Korean, Japanese, German, and Latin
+ American markets, they immediately focused on localizing their food
+ database. Using a combination of local food editors, existing food
+ databases, and user suggestions, their app now includes local cuisine
+ and popular packaged food brands, offering a simpler and more
+ comprehensive experience for users.</li>
+ </ul>
+ </li>
+
+ <li><strong>Localized coaches</strong>
+ <ul style="list-style: none;">
+ <li>Hiring local coaches not only removed language barriers, but also
+ reduced response times as they are located within the same time zone
+ as their users. Using various notification types, Noom has increased
+ user engagement by three to four times.</li>
+ </ul>
+ </li>
+</ul>
+
+<img src="{@docRoot}images/distribute/stories/noom-screenshot.png">
+ <p class="img-caption">
+ <strong>Figure 1.</strong> German Play Store listing page, Korean recipes,
+ and Japanese meal plan
+ </p>
+
+<h3>
+ Results
+</h3>
+
+<p>
+ <em>"Android's global focus and great localization tooling made the decision
+ to go global much easier. Localization to new markets has been a consistent
+ growth driver at Noom,"</em> said Artem Petakov, co-founder and President
+ at Noom.
+</p>
+
+<p>
+ Over the last three years, Noom’s localization efforts led to an <strong>80%
+ increase in international revenue growth on Android</strong>. In Japan
+ alone, <strong>revenue increased more than 480%</strong> during the same
+ time period. To identify future expansion opportunities, the team looks
+ towards countries with strong Android penetration and install growth
+ using the English product and plans to apply their localization methods to
+ achieve even greater success.
+</p>
+
+<h3>
+ Get started
+</h3>
+
+<p>
+ Learn more about <a class="external-link" href=
+ "https://material.google.com/patterns/notifications.html">Notifications</a>,
+ and find out about
+ <a href="{@docRoot}distribute/tools/localization-checklist.html">
+ app localization</a> and how to
+ <a href="{@docRoot}distribute/users/expand-to-new-markets.html">
+ Expand Into New Markets</a>.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/stories/games.jd b/docs/html/distribute/stories/games.jd
index daaac0d..cd31aae 100644
--- a/docs/html/distribute/stories/games.jd
+++ b/docs/html/distribute/stories/games.jd
@@ -25,8 +25,7 @@
<h2 class="norule">Articles</h2>
<div class="resource-widget resource-flow-layout col-16"
- data-query="type:distribute+tag:developerstory+tag:games"
- data-sortOrder="-timestamp"
+ data-query="collection:distribute/stories/games/docs"
data-cardSizes="6x6"
data-items-per-page="15"
data-initial-results="6"></div>
diff --git a/docs/html/distribute/stories/games/animoca-star-girl.jd b/docs/html/distribute/stories/games/animoca-star-girl.jd
new file mode 100644
index 0000000..a38eed2
--- /dev/null
+++ b/docs/html/distribute/stories/games/animoca-star-girl.jd
@@ -0,0 +1,89 @@
+page.title=Star Girl Increases In-App Purchases by 3.5X Through More Flexible Minimum Pricing on Google Play
+page.metaDescription=Star Girl Increases In-App Purchases by 3.5X.
+page.tags="developerstory", "games", "googleplay", "google play"
+page.image=images/cards/distribute/stories/animoca.jpg
+
+@jd:body
+
+<style type="text/css">
+ span.positive{
+ color:green;
+ font-size: 125%;
+ font-weight:bold;">
+ }
+ span.negative{
+ color:red;
+ font-size: 125%;
+ font-weight:bold;">
+ }
+</style>
+
+<h3>Background</h3>
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/animoca-logo.png" />
+</div>
+
+<p>
+ <a class="external-link"
+ href="https://play.google.com/store/apps/details?id=com.animoca.google.starGirl&hl=en&e=-EnableAppDetailsPageRedesign">
+ Star Girl</a> is a series of SIM/role playing games published by <a class="external-link"
+ href="https://play.google.com/store/apps/dev?id=8271704752057011334&hl=en&e=-EnableAppDetailsPageRedesign">
+ Animoca</a>, a Hong Kong based game developer. The Star Girl series has more than 70 million
+ downloads and is localized in 18 languages. With a fast-growing user base in markets
+ including SEA, India, and Latin America, Animoca is exploring ways to effectively increase
+ monetization with a localized pricing strategy.
+</p>
+
+<h3>What they did</h3>
+
+<p>
+ Following the introduction of
+ <a class="external-link" href="http://android-developers.blogspot.com/2015/11/minimum-purchase-price-for-apps-and-in.html">
+ more flexible minimum pricing</a> in November 2015, Animoca took the opportunity to test
+ sachet pricing models across Thailand, Malaysia, Philippines, Indonesia, Brazil, and Russia:
+</p>
+
+<p>
+ <img src="{@docRoot}images/distribute/stories/animoca-flow.jpg" />
+</p>
+
+<p>
+ Animoca created a new sachet SKU, which offered 100 diamonds and 5,000 coins, at the new lower
+ minimum price available in these markets. The new SKU is approximately 60% cheaper than the
+ previous minimum-priced product and is accessible only through geo-targeted, in-game
+ banners in localized languages.
+</p>
+
+<h3>Results</h3>
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/animoca-graph.jpg" />
+</div>
+
+<p>
+ The changes to minimum prices across these markets resulted in positive results, with the
+ number of transactions increasing 3.5X in the three months following launch.
+</p>
+
+<p>
+ Also, 90% of these transactions were first-time new buyers, half of which
+ followed up with purchases of regular packages. This helps to create a more sustainable revenue
+ impact, as described by Yusuf Goolamabbas, CTO of Animoca:
+</p>
+
+<p>
+ <em>“Sachet marketing has made IAPs more affordable to users in emerging markets. We are seeing
+ significant growth in new buyers as well as returning buyers and a positive impact on revenue in
+ emerging markets.”</em>
+</p>
+
+<h3>Get started</h3>
+
+<p>
+ <a class="external-link" href="https://support.google.com/googleplay/android-developer/answer/6334373?hl=en-GB">
+ Learn more about flexible minimum pricing</a> and
+ <a class="external-link" href="http://g.co/play/playbook-dac-writtenstudies-evergreen">
+ get the Playbook for Developers app</a> to grow your business and improve
+ monetization with Google Play.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/stories/games/happy-labs-experiment.jd b/docs/html/distribute/stories/games/happy-labs-experiment.jd
new file mode 100644
index 0000000..e317e21
--- /dev/null
+++ b/docs/html/distribute/stories/games/happy-labs-experiment.jd
@@ -0,0 +1,105 @@
+page.title=Happy Labs Increases Installs by 32% on Google Play with Store Listing Experiments
+page.metaDescription=Happy Labs Increases Installs by 32%.
+page.tags="developerstory", "games", "googleplay", "google play"
+page.image=images/cards/distribute/stories/happylabs-logo.png
+
+@jd:body
+
+<style type="text/css">
+ span.positive{
+ color:green;
+ font-size: 125%;
+ font-weight:bold;">
+ }
+ span.negative{
+ color:red;
+ font-size: 125%;
+ font-weight:bold;">
+ }
+</style>
+
+<h3>Background</h3>
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/happylabs-logo.png" />
+</div>
+
+<p>
+ <a class="external-link"
+ href="https://play.google.com/store/apps/dev?id=5211519071117278745&hl=en">
+ Happy Labs</a>, founded in 2012, is a successful game developer in Southeast Asia with 13
+ game titles and over 30 million downloads. Its flagship free-to-play virtual sim game,
+ <a class="external-link"
+ href="https://play.google.com/store/apps/dev?id=5211519071117278745&hl=en">Happy Pet Story</a>,
+ launched in February 2016 and is designed for female gamers of all ages.
+</p>
+
+<p>
+ Following the announcement of Store Listing Experiments in May, Happy Labs decided to test
+ variations of their game icon and screenshots to optimize their store listing.
+</p>
+
+<h3>What they did</h3>
+
+<p>
+ Happy Labs used the Store Listing Experiments feature in the Google Play Developer Console to
+ test three new variations of their new game icon. Encouraged by early results, they then
+ optimized the game screenshots displayed in their store listing.
+</p>
+
+<h3>Results</h3>
+
+<p>
+ The results showed that the new icon, <em>Sweet Bubbles</em> without a frame, outperformed
+ the initial <em>Mojo</em> icon and two other variants, with a 38.6% increase in installs:
+</p>
+
+<p>
+ <img src="{@docRoot}images/distribute/stories/happylabs-happy_pet_icon.png" />
+</p>
+
+<p>
+ Based on these findings, Happy Labs changed the Happy Pet Story icon to the new image globally
+ on Google Play.
+</p>
+
+<p>
+ Following the positive icon testing results, Happy Labs ran global store listing experiments
+ with a combination of screenshots from their store listing over a five week period. They then took
+ their best performing screenshots from the experiments and tested them across three specific
+ countries: Indonesia, Thailand, and Japan. The results showed an average increase of 19.87% in
+ installs.
+</p>
+
+<p>
+ Migrating from the original images to the variants shown in the following figure increased organic
+ installs in Thailand by 13.9%:
+</p>
+
+<p>
+ <img src="{@docRoot}images/distribute/stories/happylabs-variant.png" />
+</p>
+
+<p>
+ With the combination of both store listing experiments, Happy Pet Story saw an average increase of
+ 32% in month-on-month organic daily downloads globally, as described by Jeffrey Chee, CEO of Happy
+ Labs:
+</p>
+
+<p>
+ <em>“Store listing experiments have been an invaluable tool for us in optimizing our Play store
+ presence. I am really happy that we were able to get an uplift of 32% in organic installs with
+ minimal investment in terms of resources.”</em>
+</p>
+
+<h3>Get started</h3>
+
+<p>
+ Learn how to run
+ <a class="external-link" href="https://support.google.com/googleplay/android-developer/answer/6227309">
+ Store Listing Experiments</a> and read our best practices for
+ <a href="https://developer.android.com/distribute/users/experiments.html">
+ running successful experiments</a>. For more best practices on growing your business with Google
+ Play, <a class="external-link" href="http://g.co/play/playbook-dac-writtenstudies-evergreen">
+ get the Playbook for Developers app</a>.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/stories/games/playlab-puzzles.jd b/docs/html/distribute/stories/games/playlab-puzzles.jd
new file mode 100644
index 0000000..ef1ccff
--- /dev/null
+++ b/docs/html/distribute/stories/games/playlab-puzzles.jd
@@ -0,0 +1,87 @@
+page.title=Playlab Increases Juice Cubes Conversions by 25% with Store Listing Experiments
+page.metaDescription=Playlab uses store listing experiments to refresh their Juice Cubes icon.
+page.tags="developerstory", "apps", "googleplay"
+page.image=images/cards/distribute/stories/playlab.jpg
+page.timestamp=1468901832
+
+@jd:body
+
+<div class="figure">
+ <img src="{@docRoot}images/distribute/stories/playlab-icon.png" />
+</div>
+
+<h3>
+ Background
+</h3>
+
+<p>
+ <a class="external-link" href=
+ "https://play.google.com/store/apps/dev?id=9190927840679184784&e=-EnableAppDetailsPageRedesign">
+ Playlab</a> is a game developer and publisher based in Hong Kong, with
+ production studios in Bangkok and Manila. Playlab apps include
+ <a class="external-link" href=
+ "https://play.google.com/store/apps/details?id=ppl.unity.JuiceCubesBeta">
+ Juice Cubes</a>, <a class="external-link" href=
+ "https://play.google.com/store/apps/details?id=ppl.unity.junglecubes">
+ Jungle Cubes</a>, and <a class="external-link" href=
+ "https://play.google.com/store/apps/details?id=ppl.cocos2dx.ranchrun&hl=en">
+ Ranch Run</a>.
+
+ Released in 2013, <a class="external-link" href=
+ "https://play.google.com/store/apps/details?id=ppl.unity.JuiceCubesBeta">
+ Juice Cubes</a> is a strategy puzzle game with over 25 million downloads
+ worldwide and over 100,000 five-star reviews on Google Play. The game has
+ gained success in Southeast Asian markets such as Indonesia and Thailand,
+ and in Western markets such as the US, Australia, the UK, and Canada.
+</p>
+
+<h3>
+ What they did
+</h3>
+
+<p>
+ As part of Juice Cubes’ content update in April 2016, Playlab decided to
+ refresh its Play Store icon and test whether different icons could increase
+ their conversion rate.
+</p>
+
+<p>
+ Playlab used the <em>Store Listing Experiments</em> feature on the Google
+ Play Developer Console to test three variations of their new game icon.
+</p>
+
+<h3>
+ Results
+</h3>
+
+<p>
+ Within three days of running the store listing experiment, Playlab saw
+ positive results which led them to make an informed decision to change the
+ current icon to the best-performing version. Variant C outperformed the
+ initial control icon and the two other variants, with a <strong>25% increase
+ in installs</strong>. One month after applying the best-performing icon,
+ Juice Cubes continued to see a 25% increase in the number of conversions
+ from store visitors who made organic installs.
+</p>
+
+<img src="{@docRoot}images/distribute/stories/playlab-screenshot.png">
+
+<p>
+ <em>"Google Play Store Listing Experiments offer a fast, easy, and free way
+ to do A/B testing on an icon. The data provided after each test helped us
+ to make a decision really quickly. The best part is the team no longer needs
+ so many resources to decide which icon to use because we can let the
+ users decide."</em> said Jakob Lykkegaard, CEO and co-founder of Playlab.
+</p>
+
+<h3>
+ Get started
+</h3>
+
+<p>
+ Learn how to use <a class="external-link" href=
+ "https://support.google.com/googleplay/android-developer/answer/6227309">
+ A/B testing</a> and find out more about how to run
+ <a href="{@docRoot}distribute/users/experiments.html">
+ store listing experiments</a> on Google Play.
+</p>
\ No newline at end of file
diff --git a/docs/html/distribute/stories/index.jd b/docs/html/distribute/stories/index.jd
index 1745535..7d84ce4 100644
--- a/docs/html/distribute/stories/index.jd
+++ b/docs/html/distribute/stories/index.jd
@@ -21,11 +21,11 @@
<h3 class="norule">Articles</h3>
<div class="resource-widget resource-flow-layout col-16"
- data-query="type:distribute+tag:developerstory+tag:apps"
- data-sortOrder="-timestamp"
+ data-query="collection:distribute/stories/apps/docs"
data-cardSizes="6x6"
data-items-per-page="15"
data-initial-results="6"></div>
+
</div></section>
<section class="dac-section dac-small" id="latest-games"><div class="wrap">
@@ -43,9 +43,9 @@
<h3 class="norule">Articles</h3>
<div class="resource-widget resource-flow-layout col-16"
- data-query="type:distribute+tag:developerstory+tag:games"
- data-sortOrder="-timestamp"
+ data-query="collection:distribute/stories/games/docs"
data-cardSizes="6x6"
data-items-per-page="15"
data-initial-results="6"></div>
+
</div></section>
diff --git a/docs/html/google/play/billing/billing_admin.jd b/docs/html/google/play/billing/billing_admin.jd
index ad09f1f..9936489 100644
--- a/docs/html/google/play/billing/billing_admin.jd
+++ b/docs/html/google/play/billing/billing_admin.jd
@@ -51,9 +51,9 @@
listed on an app's product list. Each app has its own product list; you cannot sell
items that appear on another app's product list.</p>
-<p>You can access an app's product list by opening the <strong>In-app Products</strong>
+<p>You can access an app's product list by opening the <em>In-app Products</em>
page for an app that is listed in your developer account. The link to the
-<strong>In-app Products</strong> page appears only if you have a Google payments merchant
+<em>In-app Products</em> page appears only if you have a Google payments merchant
account and the app's manifest includes the
<code>com.android.vending.BILLING</code> permission. For more information about this
permission, see <a href="{@docRoot}google/play/billing/billing_integrate.html#billing-permission">
@@ -73,7 +73,7 @@
supported; instead, you must publish it to the alpha or beta distribution
channel. For more information, see <a
href="{@docRoot}google/play/billing/billing_testing.html#draft_apps">Draft Apps
-are No Longer Supported</a>.
+are No Longer Supported</a>.</p>
<p>In addition, an app package can have only one product list. If you create a product
list for an app, and you use the <a
@@ -82,8 +82,8 @@
associated with the app listing. You cannot create individual product lists for each APK if
you are using the multiple APK feature.</p>
-<p>You can add items to a product list two ways: you can add items one at a time on the <strong>In-app
-Products</strong> page, or you can add a batch of items by importing the items from a
+<p>You can add items to a product list two ways: you can add items one at a time on the <em>In-app
+Products</em> page, or you can add a batch of items by importing the items from a
comma-separated values (CSV) file. Adding items one at a time is useful if your
app has only a few in-app items or you are adding only a few items to a
product list for testing purposes. The CSV file method is useful if your app has a large
@@ -100,14 +100,14 @@
<ol>
<li><a href="http://play.google.com/apps/publish">Log in</a> to your publisher account.</li>
- <li>In the <strong>All applications</strong> panel, click on the
- app name, then open the <strong>In-app Products</strong> page.</li>
+ <li>In the <em>All applications</em> panel, click on the
+ app name, then open the <em>In-app Products</em> page.</li>
<li><p>Click <strong>Add new product</strong>. After you provide the product type and ID for the item you are
selling, click <strong>Continue</strong>.</p>
<dl>
<dt>Product Type</dt>
<dd>
- <p>The product type can be <strong>Managed product</strong> or <strong>Subscription</strong>. You cannot
+ <p>The product type can be "Managed product" or "Subscription." You cannot
change an item's product type after you create the item. For more information, see
<a href="#billing-purchase-type">Choosing a Product Type</a>.</p>
<p class="note"><strong>Note: </strong>For subscription items, you cannot change the
@@ -169,7 +169,7 @@
<p>You can also change prices for other currencies manually, but you can do
this only if a currency is used in one of the target countries for your
app. You can specify target countries for your app on the
- <strong>Pricing & Distribution</strong> page in the Google Play
+ <em>Pricing & Distribution</em> page in the Google Play
Developer Console.</p>
</dd>
</dl>
@@ -187,266 +187,412 @@
<h3 id="billing-bulk-add">Adding a batch of items to a product list</h3>
-<p>To add a batch of items to a product list using a CSV file, you first need to create your CSV
-file. The data values that you specify in the CSV file represent the same data values you specify
-manually through the In-app Products UI (see <a href="#billing-form-add">Adding items one at a time
-to a product list</a>).
+<p>To add a batch of items to a product list using a CSV file, you first need to
+create your CSV file. The data values that you specify in the CSV file represent
+the options that you set when adding in-app products to a product list using the
+Google Play Developer Console UI. For more information about using this UI, see
+<a href="#billing-form-add">Adding items one at a time to a product list</a>.
-<p>If you are importing and exporting CSV files with in-app products, keep
-country-specific pricing in mind. If you use auto-fill, you can provide a
-tax-exclusive default price, and tax-inclusive prices will be auto-filled. If you
-do not use auto-fill, prices you provide must include tax.</p>
+<p class="note"><strong>Note:</strong> Batch upload of in-app product lists
+containing subscriptions is not supported. Also, when updating existing items in
+a batch upload, you cannot include changes to in-app products that are linked to
+a <a href="#pricing-template">pricing template</a>.</p>
-<p class="note"><strong>Note:</strong> Batch upload of product lists containing
-subscriptions is not supported. Also, when updating existing items in a batch
-upload, you cannot include changes to in-app products that are linked to a
-<a href="#pricing-template">pricing template</a>.</p>
-
-<p>To import the items that are specified in your CSV file, do the following:</p>
+<p>To import the in-app products that are specified in your CSV file, do the
+following:</p>
<ol>
- <li><a href="http://play.google.com/apps/publish">Log in</a> to your publisher account.</li>
- <li>In the <strong>All applications</strong> panel, select the app
- name, then open the <strong>In-app Products</strong> page.</li>
- <li>On the In-app Products List page, click <strong>Import/Export</strong>
- > <strong>Import in-app products from CSV file</strong>, then select your
- CSV file.
- <p>The CSV file must be on your local computer or on a local disk that is connected to your
- computer.</p>
+ <li>
+ <a href="http://play.google.com/apps/publish">Log in</a> to your
+ publisher account.
</li>
- <li>Select the <strong>Overwrite</strong> checkbox if you want to overwrite existing items in
- your product list.
- <p>This option overwrites values of existing items only if the value of the <em>product_id</em>
- in the CSV file matches the In-app Product ID for an existing item in the product list.
- Overwriting doesn't delete items that are on a product list but not present in the CSV
- file.</p>
+ <li>In the <em>All applications</em> panel, select the app
+ name, then open the <em>In-app Products</em> page.</li>
+ <li>
+ <p>On the <em>In-app Products</em> page, click
+ <strong>Import/Export</strong> > <strong>Import in-app products from CSV
+ file</strong> to open the <em>Import In-app Products</em> dialog.</p>
+ </li>
+ <li>
+ <p>
+ If you want to overwrite existing in-app products in your product list
+ during the import process, select the <strong>Overwrite existing
+ products</strong> checkbox.
+ </p>
+ <p>
+ This option overwrites values of existing items only if the value of the
+ <code>Product ID</code> in the CSV file matches the in-app product ID for
+ an existing in-app product in the product list. The overwriting process
+ doesn't delete in-app products that exist in a product list but aren't
+ included in the CSV file
+ </p>
+ <p class="note"><strong>Note: </strong>If you choose not to overwrite
+ existing items, the <code>Product ID</code> given to each item in the CSV
+ file must be different from any of the <code>Product ID</code> values
+ assigned to existing in-app products.
+ </p>
+ </li>
+ <li>
+ Select <strong>Browse files</strong>, then choose the CSV file that contains
+ the items you want to import. The CSV file must be stored locally.
</li>
</ol>
-<p>You can also export an existing product list to a CSV file by clicking <strong>Export to CSV
-</strong> on the In-app Product List page. This is useful if you have manually added items to
-a product list and you want to start managing the product list through a CSV file.</p>
+<p>
+ You can also export an existing product list to a CSV file by clicking
+ <strong>Import/Export</strong> > <strong>Export in-app products to CSV file
+ </strong> on the <em>In-app Products page</em>. This is useful if you have
+ used the UI to add in-app products to your app but you want to start managing
+ the product list through a CSV file instead.
+</p>
<h4 id="billing-bulk-format">Formatting batches of items</h4>
-<p>The CSV file uses commas (,) and semicolons (;) to separate data values.
-Commas are used to separate primary data values, and semicolons are used to
-separate subvalues. For example, the syntax for the CSV file is as follows:</p>
-
-<p>"<em>product_id</em>","<em>publish_state</em>","<em>purchase_type</em>","<em>autotranslate</em>
-","<em>locale</em>; <em>title</em>; <em>description</em>","<em>autofill</em>","<em>country</em>;
-<em>price</em>", "<em>pricing_template_id</em>"
+<p>
+ The CSV file uses commas (<code>,</code>) and semicolons (<code>;</code>) to
+ separate data values. Commas are used to separate primary data values, and
+ semicolons are used to separate subvalues. Each item must appear entirely on a
+ single line within the CSV file.
+</p>
+<p>
+ When creating a CSV file that represents a list of items, you must specify the
+ CSV syntax on the first row, followed by the items themselves on subsequent
+ rows, as shown in the following example:
</p>
-<p>Descriptions and usage details are provided below.</p>
+<pre class="no-pretty-print">
+Product ID,Published State,Purchase Type,Auto Translate,Locale; Title; Description,Auto Fill Prices,Price,Pricing Template ID
+basic_sleeping_potion,published,managed_by_android,false,en_US; Basic Sleeping Potion; Puts small creatures to sleep.; es_ES; Poción básica de dormir; Causa las criaturas pequeñas ir a dormir.,false,,4637138456024710495
+standard_sleeping_potion,published,managed_by_android,false,en_US; Standard Sleeping Potion; Puts all creatures to sleep for 2 minutes.,true, 1990000,
+invisibility_potion,published,managed_by_android,false,en_US; Invisibility Potion; Invisible to all enemies for 5 minutes.,false, US; 1990000; BR; 6990000; RU; 129000000; IN; 130000000; ID; 27000000000; MX; 37000000;
+</pre>
+
+<p>
+ This example contains details for three items, each of which represents an
+ in-app product:
+</p>
+<ul>
+ <li>
+ The first item defines a title and description for the <code>en_US</code>
+ and <code>es_ES</code> locales. A pricing template defines the item's
+ price.
+ </li>
+ <li>
+ The second item doesn't use a pricing template. Instead, it specifies a
+ price for the default country (US). The Google Play Developer Console
+ uses current exchange rates and locally relevant pricing patterns to
+ automatically set the prices in all other countries where the app is
+ distributed.
+ </li>
+ <li>
+ The third item also doesn't use a pricing template. The item's price is
+ specified manually for each country where the app is distributed.
+ </li>
+</ul>
+
+<p>
+ Each row in a CSV file can contain the following values, though at least one
+ of these values is undefined in each row:
+</p>
<dl>
- <dt>product_id</dt>
- <dd>
- This is equivalent to the In-app Product ID setting in the In-app Products UI. If you specify
- a <em>product_id</em> that already exists in a product list, and you choose to overwrite
- the product list while importing the CSV file, the data for the existing item is overwritten with
- the values specified in the CSV file. The overwrite feature does not delete items that are on a
- product list but not present in the CSV file.
- </dd>
- <dt>publish_state</dt>
- <dd>
- This is equivalent to the Publishing State setting in the In-app Products UI. Can be <code>
- published</code> or <code>unpublished</code>.
- </dd>
- <dt>purchase_type</dt>
- <dd>
- This is equivalent to the Product Type setting in the In-app Products UI. Can be <code>
- managed_by_android</code>, which is equivalent to <strong>Managed per user account
- </strong> in the In-app Products UI, or <code>managed_by_publisher</code>, which is equivalent
- to <strong>Unmanaged</strong> in the In-app Products UI.
- </dd>
- <dt>autotranslate</dt>
- <dd>
- This is equivalent to selecting the <strong>Fill fields with auto translation</strong>
- checkbox in the In-app Products UI. Can be <code>true</code> or <code>false</code>.
- </dd>
- <dt>locale</dt>
- <dd>
- <p>This is equivalent to the Language setting in the In-app Products UI. You must have an entry
- for the default locale. The default locale must be the first entry in the list of
- locales, and it must include a <em>title</em> and <em>description</em>. If you want to provide
- translated versions of the <em>title</em> and <em>description</em> in addition to the default,
- you must use the following syntax rules:</p>
- <ul>
- <li>
- <p>If <em>autotranslate</em> is <code>true</code>, you must specify the default locale,
- default title, default description, and other locales using the following format:</p>
- <p>"true,"<em>default_locale</em>; <em>default_locale_title</em>;
- <em>default_locale_description</em>; <em>locale_2</em>; <em>locale_3</em>, ..."</p>
- </li>
- <li>
- <p>If <em>autotranslate</em> is <code>false</code>, you must specify the default locale,
- default title, and default description as well as the translated titles and descriptions using
- the following format:</p>
- <p>"false,"<em>default_locale</em>; <em>default_locale_title</em>;
- <em>default_locale_description</em>; <em>locale_2</em>; <em>locale_2_title</em>;
- <em>local_2_description</em>; <em>locale_3</em>; <em>locale_3_title</em>;
- <em>locale_3_description</em>; ..."</p>
- </li>
- </ul>
- <p>See table 1 for a list of the language codes you can use with the <em>locale</em> field.</p>
- </dd>
- <dt>title</dt>
- <dd>
- This is equivalent to the Title setting in the In-app Products UI. If the <em>title</em>
- contains a semicolon, it must be escaped with a backslash (for example, <code>\;</code>). Also, a backslash
- must be escaped with a backslash (for example, <code>\\</code>).
- </dd>
- <dt>description</dt>
- <dd>
- This is equivalent to the Description in the In-app Products UI. If the <em>description</em>
- contains a semicolon, it must be escaped with a backslash (for example, <code>\;</code>). Also, a backslash
- must be escaped with a backslash (for example, <code>\\</code>).
- </dd>
- <dt>autofill</dt>
- <dd>
- <p>This is equivalent to clicking <strong>Auto Fill</strong> in the In-app Products UI. Can be
- <code>true</code> or <code>false</code>. The syntax for specifying the <em>country</em>
- and <em>price</em> varies depending on which <em>autofill</em> setting you use:</p>
- <ul>
- <li>
- <p>If <em>autofill</em> is set to <code>true</code>, you need to specify only the default
- price in your home currency, and you must use this syntax:</p>
- <p>"true","<em>default_price_in_home_currency</em>"
- </li>
- <li>
- <p>If <em>autofill</em> is set to <code>false</code>, you need to either specify the <em>pricing_template_id</em>
- that is linked to the in-app product or specify a <em>country</em> and a <em>price</em> for each currency.
- If you choose to specify countries and prices, you must use the following syntax:</p>
- <p>"false", "<em>home_country</em>; <em>default_price_in_home_currency</em>; <em>country_2</em>;
- <em>country_2_price</em>; <em>country_3</em>; <em>country_3_price</em>; ..."</p>
- </li>
- </ul>
- <p class="note"><strong>Note: </strong>If you use an <em>autofill</em> value of <code>false</code>
- and set country prices manually, you must incorporate country-specific
- pricing patterns, including tax rates, into the prices you provide.</p>
- </dd>
- <dt>country</dt>
- <dd>
- The country for which you are specifying a price. You can only list countries that your
- app is targeting. The country codes are two-letter uppercase
- ISO country codes (such as "US"), as defined by
- <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-2</a>.
- </dd>
- <dt>price</dt>
+ <dt><code>Product ID</code></dt>
<dd>
<p>
- If you use this value, you shouldn't specify a value for the <em>pricing_template_id</em>.
+ Setting this value in the CSV file has the same effect as entering a
+ <em>Product ID</em> when creating a new in-app product.
</p>
<p>
- This is equivalent to the Price in the In-app Products UI. The price must be specified in
- micro-units. To convert a currency value to micro-units, you multiply the real value by
- 1,000,000.
- For example, if you want to sell an in-app item for $1.99, you specify <code>1990000</code> in the
- <em>price</em> field.
+ If you specify a <code>Product ID</code> assigned to an in-app product that already
+ exists in a product list, and you've checked the <strong>Overwrite
+ existing products</strong> checkbox in the <em>Import In-app Products</em>
+ dialog, the data for the existing in-app product is overwritten with the
+ values that you specify in the CSV file.
</p>
</dd>
- <dt>pricing_template_id</dt>
+ <dt><code>Publish State</code></dt>
+ <dd>
+ <p>
+ This value must be set to <code>published</code>
+ or <code>unpublished</code>.
+ </p>
+ <p>
+ Setting this value to <code>published</code> has the same effect as
+ navigating to an item's <em>Managed Product Details</em> page and choosing
+ <strong>Active</strong> in the drop-down list next to the in-app product's
+ title and product ID. Setting the value to <code>unpublished</code>
+ has the same effect as choosing <strong>Inactive</strong> in the same
+ drop-down list.
+ </p>
+ </dd>
+ <dt><code>Purchase Type</code></dt>
+ <dd>
+ <p>
+ This value must be set to <code>managed_by_android</code> because batch
+ upload of product lists containing subscriptions is not supported.
+ </p>
+ <p>
+ Setting this value to <code>managed_by_android</code> has the same effect
+ as selecting <strong>Managed product</strong> in the <em>Add New
+ Product</em> dialog when creating an in-app product.
+ </p>
+ </dd>
+ <dt><code>Auto Translate</code></dt>
+ <dd>
+ <p>
+ This value must be set to <code>false</code> because auto-translation of
+ in-app product details isn't supported.
+ </p>
+ <p>
+ If you want to provide translations of an in-app product's title and
+ description, you need to specify these translations explicitly within the
+ <code>Locale</code> value.
+ </p>
+ </dd>
+ <dt><code>Locale</code>, <code>Title</code>, and <code>Description</code></dt>
+ <dd>
+ <p>
+ If you include only one locale for an item, you must specify your app's
+ default locale and the item's default title and description:
+ </p>
+
+<pre class="no-pretty-print">
+<var>app_default_locale</var>; <var>item_default_title</var>; <var>item_default_description</var>;
+</pre>
+
+ <p>
+ Setting these values has the same effect as performing the following
+ sequence of actions:
+ </p>
+ <ol>
+ <li>
+ Choosing a default language when you add a new app to your
+ publisher account.
+ </li>
+ <li>
+ Navigating to an in-app product's <em>Managed Product Details</em> page.
+ </li>
+ <li>
+ Specifying the in-app product's default title and description.
+ </li>
+ </ol>
+ <p>
+ When setting the <code>Locale</code> value, you can use any of the
+ language codes that appear within the <em>Add Your Own Translations</em>
+ dialog. You can access this dialog by navigating to an in-app product's
+ <em>Managed Product Details</em> page and clicking <strong>Add
+ translations</strong> or <strong>Manage translations</strong>.
+ </p>
+ <p class="note">
+ <strong>Note: </strong>When specifying the <code>Title</code> and
+ <code>Description</code> values, use backslashes to escape the semicolon
+ (<code>\;</code>) and backslash (<code>\\</code>) characters.
+ </p>
+ <p>
+ If you want to include translated versions of the item's title and
+ description, you must list the default locale, title, and description,
+ followed by the locales, titles, and descriptions for each translation.
+ In the following example, the in-app product uses <code>en_US</code>
+ (United States English) as the default locale and <code>es_ES</code>
+ (Spain Spanish) as a translation:
+ </p>
+<pre class="no-pretty-print">
+en_US; Invisibility Cloak; Makes you invisible.; es_ES; Capote Invisible; Se vuelven invisible.
+</pre>
+ <p class="note">
+ <strong>Note: </strong>An app contains a single default language, but each
+ in-app product maintains its own list of translations. Therefore, although
+ the first locale in each item's <code>Locale</code> value must be the same
+ throughout the CSV file, the other locales can differ from one item to
+ another.
+ </p>
+ <p>
+ Providing values for multiple translations has the same effect as
+ performing the following sequence of actions:
+ </p>
+ <ol>
+ <li>
+ Navigating to an in-app product's <em>Managed Product Details</em> page.
+ </li>
+ <li>
+ Clicking <strong>Add translations</strong>.
+ </li>
+ <li>
+ Selecting the languages for the translations and clicking
+ <strong>Add</strong>.
+ </li>
+ <li>
+ Choosing one of the languages you added in the previous step.
+ </li>
+ <li>
+ Specifying a new title and description, which serve as translations into
+ the selected language.
+ </li>
+ <li>
+ Repeating steps 4 and 5 to add translations into all other non-default
+ languages.
+ </li>
+ </ol>
+ </dd>
+ <dt><code>Auto Fill Prices</code>, <code>Country</code>, and
+ <code>Price</code></dt>
+ <dd>
+ <p>
+ You can set <code>Auto Fill Prices</code> to <code>true</code> or
+ <code>false</code>.
+ If an in-app product uses a <a href="#pricing-template">pricing
+ template</a>, you should set <code>Auto Fill Prices</code> to
+ <code>false</code>, and you shouldn't set a value for the
+ <code>Price</code>.
+ </p>
+ <p class="note">
+ <strong>Note: </strong>When you specify an item's price in a CSV file, you
+ provide a price in <em>micro-units</em>, where 1,000,000 micro-units is
+ equivalent to 1 unit of real currency.
+ </p>
+ <p>
+ The following sections describe how the value of
+ <code>Auto Fill Prices</code> affects the syntax and meaning of the
+ <code>Country</code> and <code>Price</code> values.
+ </p>
+ <h5>Using auto-filled prices</h5>
+ <p>
+ If you set <code>Auto Fill Prices</code> to <code>true</code>, you specify
+ only the item's default price; you don't include a <code>Country</code>
+ value. Setting <code>Auto Fill Prices</code> to <code>true</code> has the
+ same effect as performing the following sequence of actions:
+ </p>
+ <ol>
+ <li>
+ Navigating to an in-app product's <em>Managed Product Details</em> page.
+ </li>
+ <li>
+ Selecting <strong>Edit</strong> in the <em>Price</em> section.
+ </li>
+ <li>
+ Entering a default, tax-exclusive price. Auto-filled prices include tax.
+ </li>
+ <li>
+ Clicking the checkbox next to <em>COUNTRY</em> in the <em>Edit Local
+ Prices</em> dialog that appears.
+ </li>
+ <li>
+ Selecting <strong>Refresh exchange rates</strong>.
+ </li>
+ <li>
+ Selecting <strong>Apply</strong>.
+ </li>
+ </ol>
+ <p>
+ For example, under the following conditions:
+ </p>
+ <ul>
+ <li>Your app's default locale is <code>en_US</code>.</li>
+ <li>An in-app product's default, tax-exclusive price is $1.99.</li>
+ <li>You want the prices for other countries auto-filled.</li>
+ </ul>
+ <p>
+ ...you'd set the values of <code>Auto Fill Prices</code> and
+ <code>Price</code> at the end of a row in the CSV file as follows:
+ </p>
+
+<pre class="no-pretty-print">
+true,1990000,
+</pre>
+
+ <h5>Not using auto-filled prices</h5>
+ <p>
+ If you set <code>Auto Fill Prices</code> to <code>false</code> instead,
+ you specify a series of <code>Country</code> and <code>Price</code>
+ values for all countries where you distribute your app, including the country corresponding to your app's default locale.
+ Each <code>Country</code> value is the two-letter uppercase <a
+ class="external-link"
+ href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO country
+ code</a> that represents a country where your app is distributed.
+ </p>
+ <p class="note">
+ <strong>Note: </strong>You must provide a country code and price for each
+ country that your app is targeting. To view and edit the list of countries
+ that your app targets, open your app's <em>Pricing & Distribution</em>
+ page.
+ </p>
+ <p>
+ Each <code>Price</code> value represents the cost of the item in
+ micro-units of the currency used in that country. Setting <code>Auto Fill
+ Prices</code> to <code>false</code> has the same effect as performing
+ the following sequence of actions:
+ </p>
+ <ol>
+ <li>
+ Navigating to an in-app product's <em>Managed Product Details</em> page.
+ </li>
+ <li>
+ Selecting <strong>Edit</strong> in the <em>Price</em> section.
+ </li>
+ <li>
+ Explicitly setting tax-inclusive prices for different countries in the
+ <em>Edit Local Prices</em> dialog that appears.
+ </li>
+ <li>
+ Selecting <strong>Apply</strong>.
+ </li>
+ </ol>
+ <p>
+ For example, if you're offering your app for the following prices (all
+ taxes included) in other countries:
+ </p>
+ <ul>
+ <li>R$6.99 in Brazil.</li>
+ <li>129 ₽ in Russia.</li>
+ <li>₹130 in India.</li>
+ <li>Rp 27,000 in Indonesia.</li>
+ <li>$37 in Mexico.</li>
+ </ul>
+ <p>
+ ...you'd set the values of <code>Auto Fill Prices</code>,
+ <code>Country</code>, and <code>Price</code> at the end of a row in the
+ CSV file as follows:
+ </p>
+
+<pre class="no-pretty-print">
+false, BR; 6990000; RU; 129000000; IN; 130000000; ID; 27000000000; MX; 37000000;
+</pre>
+
+ </dd>
+ <dt><code>Pricing Template ID</code></dt>
<dd>
<p>
- If you use this value, you should set <em>autofill</em> to
- <code>false</code> and leave the <em>price</em> column empty.
+ If an item is linked to a pricing template, you should set <code>Auto Fill
+ Prices</code> to <code>false</code>, and you shouldn't set a value for the
+ <code>Price</code> column. If the item isn't linked to a pricing template,
+ you shouldn't set a value for the <code>Pricing Template ID</code>; instead,
+ you should set <code>Auto Fill Prices</code>, <code>Country</code>, and
+ <code>Price</code> based on how you want to set the in-app product's prices.
</p>
<p>
- This value represents the ID of the pricing template that you've linked to
- the in-app product. This ID appears under a pricing template's name
- on the <strong>Pricing template</strong> page. If an in-app product isn't
- linked to a pricing template, its <em>pricing_template_id</em> value is
- empty.
+ Setting this value has the same effect as navigating to an in-app product's
+ <em>Managed Product Details</em> page and linking the product's price to the
+ pricing template that has the same pricing template ID as the one specified
+ in the CSV file. This pricing template ID appears underneath a pricing
+ template's name on the <em>Pricing template</em> page.
</p>
<p>
- If you import a CSV file and choose to overwrite the product list, you can
- update the links between in-app products and pricing templates by changing
- the value of an in-app product's <em>pricing_template_id</em>. Leave the
- value empty to unlink an in-app product from all pricing templates.
+ If you import a CSV file, and you've checked the <strong>Overwrite existing
+ products</strong> checkbox in the <em>Import In-app Products</em> dialog,
+ you can update the links between in-app products and pricing templates. To
+ link the product to a specific pricing template, set the <code>Pricing
+ Template ID</code> value to that pricing template's ID. To unlink an in-app
+ product from all pricing templates, don't set a value for its <code>Pricing
+ Template ID</code>.
</p>
<p>
- <strong>Note: </strong>You can link up to 100 app prices or in-app product
- prices with a particular pricing template. Therefore, don't specify the same
- <em>pricing_template_id</em> value in more than 100 rows of your CSV file.
+ You can link up to 100 app prices or in-app product prices to a particular
+ pricing template. Therefore, don't specify the same <code>Pricing Template
+ ID</code> value in more than 100 rows of a CSV file.
</p>
</dd>
</dl>
-<p class="table-caption" id="language-table"><strong>Table 1.</strong> Language codes you can use
-with the <em>locale</em> field.</p>
-
-<table>
-
-<tr>
-<th>Language</th>
-<th>Code</th>
-<th>Language</th>
-<th>Code</th>
-</tr>
-<tr>
-<td>Chinese</td>
-<td>zh_TW</td>
-<td>Italian</td>
-<td>it_IT</td>
-</tr>
-<tr>
-<td>Czech</td>
-<td>cs_CZ</td>
-<td>Japanese</td>
-<td>ja_JP</td>
-</tr>
-<tr>
-<td>Danish</td>
-<td>da_DK</td>
-<td>Korean</td>
-<td>ko_KR</td>
-</tr>
-<tr>
-<td>Dutch</td>
-<td>nl_NL</td>
-<td>Norwegian</td>
-<td>no_NO</td>
-</tr>
-<tr>
-<td>English</td>
-<td>en_US</td>
-<td>Polish</td>
-<td>pl_PL</td>
-</tr>
-<tr>
-<td>French</td>
-<td>fr_FR</td>
-<td>Portuguese</td>
-<td>pt_PT</td>
-</tr>
-<tr>
-<td>Finnish</td>
-<td>fi_FI</td>
-<td>Russian</td>
-<td>ru_RU</td>
-</tr>
-<tr>
-<td>German</td>
-<td>de_DE</td>
-<td>Spanish</td>
-<td>es_ES</td>
-</tr>
-<tr>
-<td>Hebrew</td>
-<td>iw_IL</td>
-<td>Swedish</td>
-<td>sv_SE</td>
-</tr>
-<tr>
-<td>Hindi</td>
-<td>hi_IN</td>
-<td>--</td>
-<td>--</td>
-</tr>
-</table>
-
<h2 id="pricing-template">
Pricing Templates
</h2>
@@ -466,7 +612,8 @@
can apply to paid apps and in-app products. You can link the prices of up to
100 apps and in-app products to a single pricing template.
</p>
-</p>
+
+<p>
To add a pricing template, do the following:
</p>
@@ -476,14 +623,14 @@
account.
</li>
- <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
- template</strong> page.
+ <li>In the <em>Settings</em> panel, open the <em>Pricing
+ template</em> page.
</li>
<li>
<p>
- If you are adding your first pricing template, the <strong>Add a Pricing
- Template</strong> banner appears. Select <strong>Add template</strong> to
+ If you are adding your first pricing template, the <em>Add a Pricing
+ Template</em> banner appears. Select <strong>Add template</strong> to
create a new template. The new template's <em>Pricing</em> tab appears.
</p>
@@ -544,8 +691,8 @@
account.
</li>
- <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
- template</strong> page. This page shows the list of pricing templates you have
+ <li>In the <em>Settings</em> panel, open the <em>Pricing
+ template</em> page. This page shows the list of pricing templates you have
created for your account.
</li>
@@ -605,8 +752,8 @@
account.
</li>
- <li>In the <strong>All applications</strong> panel, select the app name, then
- open the <strong>In-app Products</strong> page.
+ <li>In the <em>All applications</em> panel, select the app name, then
+ open the <em>In-app Products</em> page.
</li>
<li>Choose the in-app product that you want to link to a pricing template.
@@ -625,7 +772,7 @@
<p>
To link the price of a paid app to a pricing template, you follow a similar
- process on the app's <strong>Pricing & Distribution</strong> page.
+ process on the app's <em>Pricing & Distribution</em> page.
</p>
<h3 id="delete-linked-item">
@@ -657,7 +804,7 @@
<li>Select the app that contains the in-app product you want to delete.
</li>
- <li>Open the app's <strong>In-app Products</strong> page.
+ <li>Open the app's <em>In-app Products</em> page.
</li>
<li>Choose the in-app product that you want to delete.
@@ -731,8 +878,8 @@
account.
</li>
- <li>In the <strong>Settings</strong> panel, open the <strong>Pricing
- template</strong> page, which shows the list of pricing templates you have
+ <li>In the <em>Settings</em> panel, open the <em>Pricing
+ template</em> page, which shows the list of pricing templates you have
created for your account.
</li>
@@ -746,15 +893,15 @@
</li>
</ol>
-<h2 id="billing-purchase-type">Choosing a Product Type</h3>
+<h2 id="billing-purchase-type">Choosing a Product Type</h2>
<p>An item's product type controls how Google Play manages the purchase of the item. The supported
product types include "managed product" and "subscription." Since support for different product
types can vary among versions of the In-app Billing API, make sure that you choose a product
-type that's valid for the version of the In-app Billing API that your app uses. </p>
+type that's valid for the version of the In-app Billing API that your app uses.</p>
<p>For details, refer to the documentation for the <a
-href="{@docRoot}google/play/billing/api.html#producttype">In-app Billing API</a>.
+href="{@docRoot}google/play/billing/api.html#producttype">In-app Billing API</a>.</p>
<h2 id="billing-refunds">Handling Refunds</h2>
@@ -782,9 +929,10 @@
intent.</p>
<p class="note">
- <strong>Note:</strong> Test purchases don't have an <code>orderId</code>
- field. To track test transactions, you use the <code>purchaseToken</code>
- field instead. For more information about working with test purchases, see <a
+ <strong>Note:</strong> When a user completes a test purchase, the
+ <code>orderId</code> field remains blank. To track test transactions, use
+ the <code>purchaseToken</code> field instead. For more information about
+ working with test purchases, see <a
href="{@docRoot}google/play/billing/billing_testing.html">Testing In-app
Billing</a>.
</p>
@@ -799,14 +947,14 @@
<p>For transactions dated 5 December 2012 or later, Google payments assigns a
Merchant Order Number (rather than a Google Order Number) and reports the Merchant
-Order Number as the value of <code>orderId</code>. Here's an
+Order Number as the value of <code>orderID</code>. Here's an
example:</p>
<pre>"orderId" : "GPA.1234-5678-9012-34567"</pre>
<p>For transactions dated previous to 5 December 2012, Google checkout assigned
a Google Order Number and reported that number as the value of
-<code>orderId</code>. Here's an example of an <code>orderId</code> holding a
+<code>orderID</code>. Here's an example of an <code>orderID</code> holding a
Google Order Number:</p>
<pre>"orderId" : "556515565155651"</pre>
@@ -853,8 +1001,8 @@
<p>To locate the key for an app, follow these steps:</p>
<ol>
- <li>Open the <strong>All applications</strong> panel.</li>
- <li>Click on the app name, then open the <strong>Services & APIs</strong>
+ <li>Open the <em>All applications</em> panel.</li>
+ <li>Click on the app name, then open the <em>Services & APIs</em>
page.</li>
<li>Scroll down to the section of the page labeled Your License Key for This
Application, as shown in figure 5.</li>
@@ -869,7 +1017,7 @@
width="700" alt="">
<figcaption>
<b>Figure 5. </b>You can find the license key for each app on the
- <strong>Services & APIs</strong> page.
+ <em>Services & APIs</em> page.
</figcaption>
</figure>
diff --git a/docs/html/guide/_book.yaml b/docs/html/guide/_book.yaml
index 13c948c..f09fe77 100644
--- a/docs/html/guide/_book.yaml
+++ b/docs/html/guide/_book.yaml
@@ -396,6 +396,13 @@
path: /guide/topics/data/data-storage.html
- title: Data Backup
path: /guide/topics/data/backup.html
+ section:
+ - title: Auto Backup
+ path: /guide/topics/data/autobackup.html
+ - title: Key/Value Backup
+ path: /guide/topics/data/keyvaluebackup.html
+ - title: Testing Backup and Restore
+ path: /guide/topics/data/testingbackup.html
- title: App Install Location
path: /guide/topics/data/install-location.html
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 9257a76..8fe3f20 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -545,9 +545,16 @@
<li><a href="<?cs var:toroot ?>guide/topics/data/data-storage.html">
<span class="en">Storage Options</span>
</a></li>
- <li><a href="<?cs var:toroot ?>guide/topics/data/backup.html">
+ <li class="nav-section">
+ <div class="nav-section-header"><a href="<?cs var:toroot ?>guide/topics/data/backup.html">
<span class="en">Data Backup</span>
- </a></li>
+ </a></div>
+ <ul>
+ <li><a href="<?cs var:toroot ?>guide/topics/data/autobackup.html">Auto Backup</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/data/keyvaluebackup.html">Key/Value Backup</a></li>
+ <li><a href="<?cs var:toroot ?>guide/topics/data/testingbackup.html">Testing Backup and Restore</a></li>
+ </ul>
+ </li>
<li><a href="<?cs var:toroot ?>guide/topics/data/install-location.html">
<span class="en">App Install Location</span>
</a></li>
diff --git a/docs/html/guide/topics/data/autobackup.jd b/docs/html/guide/topics/data/autobackup.jd
new file mode 100644
index 0000000..3be09d7
--- /dev/null
+++ b/docs/html/guide/topics/data/autobackup.jd
@@ -0,0 +1,257 @@
+page.title=Auto Backup for Apps
+page.tags=backup, marshmallow, androidm
+page.keywords=backup, autobackup
+page.image=images/cards/card-auto-backup_2x.png
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#Files">Files that are backed up</a></li>
+ <li><a href="#BackupLocation">Backup location</a></li>
+ <li><a href="#BackupSchedule">Backup schedule</a></li>
+ <li><a href="#RestoreSchedule">Restore schedule</a></li>
+ <li><a href="#EnablingAutoBackup">Enabling and disabling Auto Backup</a></li>
+ <li><a href="#IncludingFiles">Including and excluding files</a><ul>
+ <li><a href="#XMLSyntax">XML config syntax</a></li>
+ </ul></li>
+ <li><a href="#ImplementingBackupAgent">Implementing BackupAgent</a></li>
+ </ol>
+
+ <h2>Key classes</h2>
+ <ol>
+ <li>{@link android.app.backup.BackupAgent}</li>
+ <li><a href="{@docRoot}reference/android/R.attr.html">R.attr</a></li>
+ </ol>
+
+</div>
+</div>
+
+Since Android 6.0 (API 23), Android has offered the <em>Auto Backup for Apps</em> feature as
+a way for developers to quickly add backup functionality to their apps. Auto
+Backup preserves app data by uploading it to the user’s Google Drive account.
+The amount of data is limited to 25MB per user of your app and there is no
+charge for storing backup data.
+
+<h2 id="Files">Files that are backed up</h2>
+<p>By default, Auto Backup includes files in most of the directories that are
+assigned to your app by the system:
+<ul>
+ <li>Shared preferences files.
+ <li>Files in the directory returned by {@link android.content.Context#getFilesDir()}.
+ <li>Files in the directory returned by {@link android.content.Context#getDatabasePath(String)},
+ which also includes files created with the
+ {@link android.database.sqlite.SQLiteOpenHelper} class.
+ <li>Files in directories created with {@link android.content.Context#getDir(String,int)}.
+ <li>Files on external storage in the directory returned by
+ {@link android.content.Context#getExternalFilesDir(String)}.</li></ul>
+
+<p>Auto Backup excludes files in directories returned by
+ {@link android.content.Context#getCacheDir()},
+ {@link android.content.Context#getCodeCacheDir()}, or
+ {@link android.content.Context#getNoBackupFilesDir()}. The files saved
+ in these locations are only needed temporarily, or are intentionally
+ excluded from backup operations.
+
+<p>You can configure your app to include and exclude particular files.
+For more information, see the <a href="#IncludingFiles">Include and exclude files</a>
+section.
+
+<h2 id="BackupLocation">Backup location</h2>
+<p>Backup data is stored in a private folder in the user's Google Drive account,
+limited to 25MB per app. The saved data does not count towards the user's
+personal Google Drive quota. Only the most recent backup is stored. When a
+backup is made, the previous backup (if one exists) is deleted.
+
+<p>Users can see a list of apps that have been backed up in the Google Drive app under
+<strong>Settings -> Auto Backup for apps -> Manage backup</strong>. The
+backup data cannot be read by the user or other applications on the device.
+
+<p>Backups from each device-setup-lifetime are stored in separate datasets
+as shown in the following examples:
+<ul>
+ <li>If the user owns two devices, then a backup dataset exists for each device.
+ <li>If the user factory resets a device and then sets up the device with the
+ same account, the backup is stored in a new dataset. Obsolete datasets are
+ automatically deleted after a period of inactivity.</li></ul>
+
+<p class="caution"><strong>Caution:</strong> Once the amount of data reaches
+25MB, the app is banned from sending data to the
+cloud, even if the amount of data later falls under the 25MB threshold. The ban
+affects only the offending device (not other devices that the user owns) and
+lasts for the entire device-setup-lifetime. For example, if the user removes and
+reinstalls the application, the ban is still in effect. The ban is lifted when
+the user performs factory reset on the device.
+
+<h2 id="BackupSchedule">Backup schedule</h2>
+<p>Backups occur automatically when all of the following conditions are met:
+<ul>
+ <li>The user has enabled backup on the device in <strong>Settings</strong> >
+ <strong>Backup & Reset</strong>.
+ <li>At least 24 hours have elapsed since the last backup.
+ <li>The device is idle and charging.
+ <li>The device is connected to a Wi-Fi network. If the device is never connected
+ to a wifi network, then Auto Backup never occurs.</li></ul>
+
+<p>In practice, these conditions occur roughly every night. To conserve network
+bandwidth, upload takes place only if app data has changed.
+
+<p>During Auto Backup, the system shuts down the app to make sure it is no longer
+writing to the file system. By default, the backup system ignores apps that are
+running in the foreground because users would notice their apps being shut down.
+You can override the default behavior by setting the
+<a href="{@docRoot}reference/android/R.attr.html#backupInForeground">backupInForeground</a>
+attribute to true.
+
+<p>To simplify testing, Android includes tools that let you manually initiate
+a backup of your app. For more information, see
+<a href="{@docRoot}guide/topics/data/testingbackup.html">Testing Backup and Restore</a>.
+
+<h2 id="RestoreSchedule">Restore schedule</h2>
+<p>Data is restored whenever the app is installed, either from the Play store,
+during device setup (when the system installs previously installed apps), or
+from running adb install. The restore operation occurs after the APK is
+installed, but before the app is available to be launched by the user.
+
+<p>During the initial device setup wizard, the user is shown a list of available backup
+datasets and is asked which one to restore the data from. Whichever backup
+dataset is selected becomes the ancestral dataset for the device. The device can
+restore from either its own backups or the ancestral dataset. The device
+prioritize its own backup if backups from both sources are available. If the
+user didn't go through the device setup wizard, then the device can restore only from
+its own backups.
+
+<p>To simplify testing, Android includes tools that let you manually initiate
+a restore of your app. For more information, see
+<a href="{@docRoot}guide/topics/data/testingbackup.html">Testing Backup and Restore</a>.
+
+<h2 id="EnablingAutoBackup">Enabling and disabling backup</h2>
+<p>Apps that target Android 6.0 (API level 23) or higher automatically participate
+in Auto Backup. This is because the
+<a href="{@docRoot}reference/android/R.attr.html#allowBackup">android:allowBackup</a>
+attribute, which enables/disables backup, defaults to <code>true</code> if omitted.
+To avoid confusion, we recommend you explicitly set the attribute in the <code><application></code>
+element of your <code>AndroidManifest.xml</code>. For example:
+
+<pre class="prettyprint"><application ...
+ android:allowBackup="true">
+</app></pre>
+
+<p>To disable Auto Backup, add either of the following attributes to the
+application element in your manifest file:
+
+<ul>
+ <li>set <code>android:allowBackup</code> to <code>false</code>. This completely disables data
+ backup. You may want to disable backups when your app can recreate its state
+ through some other mechanism or when your app deals with sensitive
+ information that should not be backed up.</li>
+ <li>set <code>android:allowBackup</code> to <code>true</code> and
+ <code>android:fullBackupOnly</code> to <code>false</code>. With these settings,
+ your app always participates in Key/Value Backup, even when running on devices that
+ support Auto Backup.</li></ul>
+
+<h2 id="IncludingFiles">Including and excluding files</h2>
+<p>By default, the system backs up almost all app data. For more information,
+see <a href="#Files">Files that are backed up</a>. This section shows you how to
+define custom XML rules to control what gets backed up.
+
+<ol>
+ <li>In <code>AndroidManifest.xml</code>, add the <a href="{@docRoot}reference/android/R.attr.html#fullBackupContent">android:fullBackupContent</a> attribute to the
+ <code><application></code> element. This attribute points to an XML file that contains backup
+ rules. For example:
+ <pre class="prettyprint"><application ...
+ android:fullBackupContent="@xml/my_backup_rules">
+ </app></pre></li>
+ <li>Create an XML file called <code>my_backup_rules.xml</code> in the <code>res/xml/</code> directory. Inside the file, add rules with the <code><include></code> and <code><exclude></code> elements. The following sample backs up all shared preferences except <code>device.xml</code>:
+ <pre><?xml version="1.0" encoding="utf-8"?>
+<full-backup-content>
+ <include domain="sharedpref" path="."/>
+ <exclude domain="sharedpref" path="device.xml"/>
+</full-backup-content></pre></li>
+
+<h3 id="XMLSyntax">XML Config Syntax</h3>
+<p>The XML syntax for the configuration file is shown below:
+
+<pre class="prettyprint"><full-backup-content>
+ <include domain=["file" | "database" | "sharedpref" | "external" | "root"]
+ path="string" />
+ <exclude domain=["file" | "database" | "sharedpref" | "external" | "root"]
+ path="string" />
+</full-backup-content></pre>
+
+<p>Inside the <code><full-backup-content></code> tag, you can define <code><include></code> and <code><exclude></code>
+elements:
+
+<ul>
+ <li><code><include></code> - Specifies a file or folder to backup. By default, Auto Backup
+includes almost all app files. If you specify an <include> element, the system
+no longer includes any files by default and backs up <em>only the files
+specified</em>. To include multiple files, use multiple <include> elements.
+ <p>note: Files in directories returned by <code>getCacheDir()</code>, <code>getCodeCacheDir()</code>, or
+<code>getNoBackupFilesDir()</code> are always excluded even if you try to include them.</li>
+
+ <li><code><exclude></code> - Specifies a file or folder to exclude during backup. Here are
+some files that are typically excluded from backup: <ul>
+ <li>Files that have device specific identifiers, either issued by a server or
+generated on the device. For example, <a href="https://developers.google.com/cloud-messaging/android/start">Google Cloud Messaging (GCM)</a> needs to
+generate a registration token every time a user installs your app on a new
+device. If the old registration token is restored, the app may behave
+unexpectedly.
+ <li>Account credentials or other sensitive information. Consider asking the
+user to reauthenticate the first time they launch a restored app rather than
+allowing for storage of such information in the backup.
+ <li>Files related to app debugging, such as <a href="{@docRoot}studio/run/index.html#instant-run">instant run files</a>. To exclude instant run files, add the rule <code><exclude
+domain="file" path="instant-run"/></code>
+ <li>Large files that cause the app to exceed the 25MB backup quota.</li> </ul>
+ </li> </ul>
+
+<p class="note"><strong>Note:</strong> If your configuration file specifies both elements, then the
+backup contains everything captured by the <code><include></code> elements minus the
+resources named in the <code><exclude></code> elements. In other words,
+<code><exclude></code> takes precedence.
+
+<p>Each element must include the following two attributes:
+<ul>
+ <li><code>domain</code> - specifies the location of resource. Valid values for this attribute
+include the following: <ul>
+ <li><code>root</code> - the directory on the filesystem where all private files belonging to
+this app are stored.
+ <li><code>file</code> - directories returned by {@link android.content.Context#getFilesDir()}.
+ <li><code>database</code> - directories returned by {@link android.content.Context#getDatabasePath(String) getDatabasePath()}.
+Databases created with {@link android.database.sqlite.SQLiteOpenHelper}
+are stored here.
+ <li><code>sharedpref</code> - the directory where {@link android.content.SharedPreferences}
+are stored.
+ <li><code>external</code> the directory returned by {@link android.content.Context#getExternalFilesDir(String) getExternalFilesDir()}
+ <p>Note: You cannot backup files outside of these locations.</li></ul>
+ <li><code>path</code>: Specifies a file or folder to include in or exclude from backup. Note
+that: <ul>
+ <li>This attribute does not support wildcard or regex syntax.
+ <li>You can use <code>.</code> to reference the current directory, however, you cannot
+reference the parent directory <code>..</code> for security reasons.
+ <li>If you specify a directory, then the rule applies to all files in the
+directory and recursive sub-directories.</li></ul></li></ul>
+
+<h2 id="ImplementingBackupAgent">Implementing BackupAgent</h2>
+<p>Apps that implement Auto Backup do not need to implement {@link android.app.backup.BackupAgent}. However, you can optionally implement a custom {@link android.app.backup.BackupAgent}. Typically, there are two reasons for doing this:
+<ul>
+ <li>You want to receive notification of backup events such as,
+{@link android.app.backup.BackupAgent#onRestoreFinished()} or {@link android.app.backup.BackupAgent#onQuotaExceeded(long,long)}. These callback methods are executed
+even if the app is not running.
+<li>You can't easily express the set of files you want to backup with XML rules.
+In these very rare cases, you can implement a BackupAgent that overrides {@link android.app.backup.BackupAgent#onFullBackup(FullBackupDataOutput)} to
+store what you want. To retain the system's default implementation, call the
+corresponding method on the superclass with <code>super.onFullBackup()</code>.</li></ul>
+
+<p class="note"><strong>Note:</strong> Your <code>BackupAgent</code> must
+implement the abstract methods
+{@link android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor) onBackup()}
+and {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
+Those methods are used for Key/Value Backup. So if
+you are not using Key/Value Backup, implement those methods and leave them blank.
+
+<p>For more information, see
+<a href="{@docRoot}guide/topics/data/keyvaluebackup.html#BackupAgent">Extending
+BackupAgent</a>.
\ No newline at end of file
diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
index 619c790..a688c6e 100644
--- a/docs/html/guide/topics/data/backup.jd
+++ b/docs/html/guide/topics/data/backup.jd
@@ -1,930 +1,34 @@
-page.title=Data Backup
+page.title=Backing up App Data to the Cloud
+page.tags=cloud,sync,backup
+
+startpage=true
+
@jd:body
+<p>Users often invest significant time and effort creating data and setting
+preferences within apps. Preserving that data for users if they replace a broken
+device or upgrade to a new one is an important part of ensuring a great user
+experience. This section covers techniques for backing up data to the cloud so
+that users can restore their data.
-<div id="qv-wrapper">
-<div id="qv">
+<p>Android provides two ways for apps to backup their data to the cloud:
+<a href="{@docRoot}guide/topics/data/autobackup.html">Auto Backup for Apps</a> and
+<a href="{@docRoot}guide/topics/data/keyvaluebackup.html">Key/Value Backup</a>.
+Auto Backup, which is available starting API 23, preserves app data by uploading
+it to the user’s Google Drive account. The Key/Value Backup feature (formerly
+known as the Backup API and the Android Backup Service) preserves app data by
+uploading it to the <a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
- <h2>Quickview</h2>
- <ul>
- <li>Back up the user's data to the cloud in case the user loses it</li>
- <li>If the user upgrades to a new Android-powered device, your app can restore the user's
-data onto the new device</li>
- <li>Easily back up SharedPreferences and private files with BackupAgentHelper</li>
- <li>Requires API Level 8</li>
- </ul>
+<p>Generally, we recommend Auto Backup because it requires no work to implement.
+Apps that target Android 6.0 (API level 23) or higher are automatically enabled
+for Auto Backup. The Auto Backup feature does have some limitations in terms of
+what data it can backup and it's availability on Android 6.0 and higher devices.
+Consider using the Key/Value Backup feature if you have more specific needs for
+backing up your app data. For more information, see <a href="{@docRoot}guide/topics/data/keyvaluebackup.html#Comparison">Comparison of Key/Value and Auto Backup</a></p>
- <h2>In this document</h2>
- <ol>
- <li><a href="#Basics">The Basics</a></li>
- <li><a href="#BackupManifest">Declaring the Backup Agent in Your Manifest</a></li>
- <li><a href="#BackupKey">Registering for Android Backup Service</a></li>
- <li><a href="#BackupAgent">Extending BackupAgent</a>
- <ol>
- <li><a href="#RequiredMethods">Required Methods</a></li>
- <li><a href="#PerformingBackup">Performing backup</a></li>
- <li><a href="#PerformingRestore">Performing restore</a></li>
- </ol>
- </li>
- <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
- <ol>
- <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li>
- <li><a href="#Files">Backing up Private Files</a></li>
- </ol>
- </li>
- <li><a href="#RestoreVersion">Checking the Restore Data Version</a></li>
- <li><a href="#RequestingBackup">Requesting Backup</a></li>
- <li><a href="#RequestingRestore">Requesting Restore</a></li>
- <li><a href="#Testing">Testing Your Backup Agent</a></li>
- </ol>
-
- <h2>Key classes</h2>
- <ol>
- <li>{@link android.app.backup.BackupManager}</li>
- <li>{@link android.app.backup.BackupAgent}</li>
- <li>{@link android.app.backup.BackupAgentHelper}</li>
- </ol>
-
- <h2>See also</h2>
- <ol>
- <li><a href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a></li>
- </ol>
-
-</div>
-</div>
-
-<p>Android's {@link android.app.backup backup} service allows you to copy your persistent
-application data to remote "cloud" storage, in order to provide a restore point for the
-application data and settings. If a user performs a factory reset or converts to a new
-Android-powered device, the system automatically restores your backup data when the application
-is re-installed. This way, your users don't need to reproduce their previous data or
-application settings. This process is completely transparent to the user and does not affect the
-functionality or user experience in your application.</p>
-
-<p>During a backup operation (which your application can request), Android's Backup Manager ({@link
-android.app.backup.BackupManager}) queries your application for backup data, then hands it to
-a backup transport, which then delivers the data to the cloud storage. During a
-restore operation, the Backup Manager retrieves the backup data from the backup transport and
-returns it to your application so your application can restore the data to the device. It's
-possible for your application to request a restore, but that shouldn't be necessary—Android
-automatically performs a restore operation when your application is installed and there exists
-backup data associated with the user. The primary scenario in which backup data is restored is when
-a user resets their device or upgrades to a new device and their previously installed
-applications are re-installed.</p>
-
-<p class="note"><strong>Note:</strong> The backup service is <em>not</em> designed for
-synchronizing application data with other clients or saving data that you'd like to access during
-the normal application lifecycle. You cannot read or write backup data on demand and cannot access
-it in any way other than through the APIs provided by the Backup Manager.</p>
-
-<p>The backup transport is the client-side component of Android's backup framework, which is
-customizable by
-the device manufacturer and service provider. The backup transport may differ from device to device
-and which backup transport is available on any given device is transparent to your application. The
-Backup Manager APIs isolate your application from the actual backup transport available on a given
-device—your application communicates with the Backup Manager through a fixed set of APIs,
-regardless of the underlying transport.</p>
-
-<p>Data backup is <em>not</em> guaranteed to be available on all Android-powered
-devices. However, your application is not adversely affected in the event
-that a device does not provide a backup transport. If you believe that users will benefit from data
-backup in your application, then you can implement it as described in this document, test it, then
-publish your application without any concern about which devices actually perform backup. When your
-application runs on a device that does not provide a backup transport, your application operates
-normally, but will not receive callbacks from the Backup Manager to backup data.</p>
-
-<p>Although you cannot know what the current transport is, you are always assured that your
-backup data cannot be read by other applications on the device. Only the Backup Manager and backup
-transport have access to the data you provide during a backup operation.</p>
-
-<p class="caution"><strong>Caution:</strong> Because the cloud storage and transport service can
-differ from device to device, Android makes no guarantees about the security of your data while
-using backup. You should always be cautious about using backup to store sensitive data, such as
-usernames and passwords.</p>
-
-
-<h2 id="Basics">The Basics</h2>
-
-<p>To backup your application data, you need to implement a backup agent. Your backup
-agent is called by the Backup Manager to provide the data you want to back up. It is also called
-to restore your backup data when the application is re-installed. The Backup Manager handles all
-your data transactions with the cloud storage (using the backup transport) and your backup agent
-handles all your data transactions on the device.</p>
-
-<p>To implement a backup agent, you must:</p>
-
-<ol>
- <li>Declare your backup agent in your manifest file with the <a
-href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
-android:backupAgent}</a> attribute.</li>
- <li>Register your application with a backup service. Google offers <a
-href="http://code.google.com/android/backup/index.html">Android Backup Service</a> as a backup
-service for most Android-powered devices, which requires that you register your application in
-order for it to work. Any other backup services available might also require you to register
-in order to store your data on their servers.</li>
- <li>Define a backup agent by either:</p>
- <ol type="a">
- <li><a href="#BackupAgent">Extending BackupAgent</a>
- <p>The {@link android.app.backup.BackupAgent} class provides the central interface with
-which your application communicates with the Backup Manager. If you extend this class
-directly, you must override {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()} to handle the backup and restore operations for your data.</p>
- <p><em>Or</em></p>
- <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
- <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient
-wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code
-you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more
-"helper" objects, which automatically backup and restore certain types of data, so that you do not
-need to implement {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}.</p>
- <p>Android currently provides backup helpers that will backup and restore complete files
-from {@link android.content.SharedPreferences} and <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p>
- </li>
- </ol>
- </li>
-</ol>
-
-
-
-<h2 id="BackupManifest">Declaring the Backup Agent in Your Manifest</h2>
-
-<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare
-it in your manifest with the <a
-href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
-android:backupAgent}</a> attribute in the <a
-href="{@docRoot}guide/topics/manifest/application-element.html">{@code
-<application>}</a> tag.</p>
-
-<p>For example:</p>
-
-<pre>
-<manifest ... >
- ...
- <application android:label="MyApplication"
- <b>android:backupAgent="MyBackupAgent"</b>>
- <activity ... >
- ...
- </activity>
- </application>
-</manifest>
-</pre>
-
-<p>Another attribute you might want to use is <a
-href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
-android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you
-want to restore the application data regardless of the current application version compared to the
-version that produced the backup data. (The default value is "{@code false}".) See <a
-href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p>
-
-<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are
-available only on devices running API Level 8 (Android 2.2) or greater, so you should also
-set your <a
-href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
-attribute to "8".</p>
-
-
-
-
-<h2 id="BackupKey">Registering for Android Backup Service</h2>
-
-<p>Google provides a backup transport with <a
-href="http://code.google.com/android/backup/index.html">Android Backup Service</a> for most
-Android-powered devices running Android 2.2 or greater.</p>
-
-<p>In order for your application to perform backup using Android Backup Service, you must
-register your application with the service to receive a Backup Service Key, then
-declare the Backup Service Key in your Android manifest.</p>
-
-<p>To get your Backup Service Key, <a
-href="http://code.google.com/android/backup/signup.html">register for Android Backup Service</a>.
-When you register, you will be provided a Backup Service Key and the appropriate {@code
-<meta-data>} XML code for your Android manifest file, which you must include as a child of the
-{@code <application>} element. For example:</p>
-
-<pre>
-<application android:label="MyApplication"
- android:backupAgent="MyBackupAgent">
- ...
- <meta-data android:name="com.google.android.backup.api_key"
- android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" />
-</application>
-</pre>
-
-<p>The <code>android:name</code> must be <code>"com.google.android.backup.api_key"</code> and
-the <code>android:value</code> must be the Backup Service Key received from the Android Backup
-Service registration.</p>
-
-<p>If you have multiple applications, you must register each one, using the respective package
-name.</p>
-
-<p class="note"><strong>Note:</strong> The backup transport provided by Android Backup Service is
-not guaranteed to be available
-on all Android-powered devices that support backup. Some devices might support backup
-using a different transport, some devices might not support backup at all, and there is no way for
-your application to know what transport is used on the device. However, if you implement backup for
-your application, you should always include a Backup Service Key for Android Backup Service so
-your application can perform backup when the device uses the Android Backup Service transport. If
-the device does not use Android Backup Service, then the {@code <meta-data>} element with the
-Backup Service Key is ignored.</p>
-
-
-
-
-<h2 id="BackupAgent">Extending BackupAgent</h2>
-
-<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
-directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take
-advantage of the built-in helper classes that automatically backup and restore your files. However,
-you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
-<ul>
- <li>Version your data format. For instance, if you anticipate the need to revise the
-format in which you write your application data, you can build a backup agent to cross-check your
-application version during a restore operation and perform any necessary compatibility work if the
-version on the device is different than that of the backup data. For more information, see <a
-href="#RestoreVersion">Checking the Restore Data Version</a>.</li>
- <li>Instead of backing up an entire file, you can specify the portions of data the should be
-backed up and how each portion is then restored to the device. (This can also help you manage
-different versions, because you read and write your data as unique entities, rather than
-complete files.)</li>
- <li>Back up data in a database. If you have an SQLite database that you want to restore when
-the user re-installs your application, you need to build a custom {@link
-android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then
-create your table and insert the data during a restore operation.</li>
-</ul>
-
-<p>If you don't need to perform any of the tasks above and want to back up complete files from
-{@link android.content.SharedPreferences} or <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
-should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
-
-
-
-<h3 id="RequiredMethods">Required Methods</h3>
-
-<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you
-must implement the following callback methods:</p>
-
-<dl>
- <dt>{@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()}</dt>
- <dd>The Backup Manager calls this method after you <a href="#RequestingBackup">request a
-backup</a>. In this method, you read your application data from the device and pass the data you
-want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing
-backup</a>.</dd>
-
- <dt>{@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}</dt>
- <dd>The Backup Manager calls this method during a restore operation (you can <a
-href="#RequestingRestore">request a restore</a>, but the system automatically performs restore when
-the user re-installs your application). When it calls this method, the Backup Manager delivers your
-backup data, which you then restore to the device, as described below in <a
-href="#PerformingRestore">Performing restore</a>.</dd>
-</dl>
-
-
-
-<h3 id="PerformingBackup">Performing backup</h3>
-
-
-<p>When it's time to back up your application data, the Backup Manager calls your {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method. This is where you must provide your application data to the Backup Manager so
-it can be saved to cloud storage.</p>
-
-<p>Only the Backup Manager can call your backup agent's {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method. Each time that your application data changes and you want to perform a backup,
-you must request a backup operation by calling {@link
-android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting
-Backup</a> for more information). A backup request does not result in an immediate call to your
-{@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs
-backup for all applications that have requested a backup since the last backup was performed.</p>
-
-<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an
-immediate backup operation from the Backup Manager with the <a
-href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a>.</p>
-
-<p>When the Backup Manager calls your {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method, it passes three parameters:</p>
-
-<dl>
- <dt>{@code oldState}</dt>
- <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup
-state provided by your application. This is not the backup data from cloud storage, but a
-local representation of the data that was backed up the last time {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} was called (as defined by {@code newState}, below, or from {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}—more about this in the next section). Because {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} does not allow you to read existing backup data in
-the cloud storage, you can use this local representation to determine whether your data has changed
-since the last backup.</dd>
- <dt>{@code data}</dt>
- <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup
-data to the Backup Manager.</dd>
- <dt>{@code newState}</dt>
- <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
-you must write a representation of the data that you delivered to {@code data} (a representation
-can be as simple as the last-modified timestamp for your file). This object is
-returned as {@code oldState} the next time the Backup Manager calls your {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState}
-will point to an empty file next time Backup Manager calls {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()}.</dd>
-</dl>
-
-<p>Using these parameters, you should implement your {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method to do the following:</p>
-
-<ol>
- <li>Check whether your data has changed since the last backup by comparing {@code oldState} to
-your current data. How you read data in {@code oldState} depends on how you originally wrote it to
-{@code newState} (see step 3). The easiest way to record the state of a file is with its
-last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code
-oldState}:
- <pre>
-// Get the oldState input stream
-FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
-DataInputStream in = new DataInputStream(instream);
-
-try {
- // Get the last modified timestamp from the state file and data file
- long stateModified = in.readLong();
- long fileModified = mDataFile.lastModified();
-
- if (stateModified != fileModified) {
- // The file has been modified, so do a backup
- // Or the time on the device changed, so be safe and do a backup
- } else {
- // Don't back up because the file hasn't changed
- return;
- }
-} catch (IOException e) {
- // Unable to read state file... be safe and do a backup
-}
-</pre>
- <p>If nothing has changed and you don't need to back up, skip to step 3.</p>
- </li>
- <li>If your data has changed, compared to {@code oldState}, write the current data to
-{@code data} to back it up to the cloud storage.
- <p>You must write each chunk of data as an "entity" in the {@link
-android.app.backup.BackupDataOutput}. An entity is a flattened binary data
-record that is identified by a unique key string. Thus, the data set that you back up is
-conceptually a set of key-value pairs.</p>
- <p>To add an entity to your backup data set, you must:</p>
- <ol>
- <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
-writeEntityHeader()}, passing a unique string key for the data you're about to write and the data
-size.</li>
- <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
-writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
-from the buffer (which should match the size passed to {@link
-android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li>
- </ol>
- <p>For example, the following code flattens some data into a byte stream and writes it into a
-single entity:</p>
- <pre>
-// Create buffer stream and data output stream for our data
-ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
-DataOutputStream outWriter = new DataOutputStream(bufStream);
-// Write structured data
-outWriter.writeUTF(mPlayerName);
-outWriter.writeInt(mPlayerScore);
-// Send the data to the Backup Manager via the BackupDataOutput
-byte[] buffer = bufStream.toByteArray();
-int len = buffer.length;
-data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
-data.writeEntityData(buffer, len);
-</pre>
- <p>Perform this for each piece of data that you want to back up. How you divide your data into
-entities is up to you (and you might use just one entity).</p>
- </li>
- <li>Whether or not you perform a backup (in step 2), write a representation of the current data to
-the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object
-locally as a representation of the data that is currently backed up. It passes this back to you as
-{@code oldState} the next time it calls {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
-do not write the current data state to this file, then
-{@code oldState} will be empty during the next callback.
- <p>The following example saves a representation of the current data into {@code newState} using
-the file's last-modified timestamp:</p>
- <pre>
-FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
-DataOutputStream out = new DataOutputStream(outstream);
-
-long modified = mDataFile.lastModified();
-out.writeLong(modified);
-</pre>
- </li>
-</ol>
-
-<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure
-that you use synchronized statements while accessing the file so that your backup agent does not
-read the file while an Activity in your application is also writing the file.</p>
-
-
-
-
-<h3 id="PerformingRestore">Performing restore</h3>
-
-<p>When it's time to restore your application data, the Backup Manager calls your backup
-agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so
-you can restore it onto the device.</p>
-
-<p>Only the Backup Manager can call {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}, which happens automatically when the system installs your application and
-finds existing backup data. However, you can request a restore operation for
-your application by calling {@link
-android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a
-href="#RequestingRestore">Requesting restore</a> for more information).</p>
-
-<p class="note"><strong>Note:</strong> While developing your application, you can also request a
-restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
-tool</a>.</p>
-
-<p>When the Backup Manager calls your {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()} method, it passes three parameters:</p>
-
-<dl>
- <dt>{@code data}</dt>
- <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup
-data.</dd>
- <dt>{@code appVersionCode}</dt>
- <dd>An integer representing the value of your application's <a
-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
-manifest attribute, as it was when this data was backed up. You can use this to cross-check the
-current application version and determine if the data format is compatible. For more
-information about using this to handle different versions of restore data, see the section
-below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd>
- <dt>{@code newState}</dt>
- <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
-you must write the final backup state that was provided with {@code data}. This object is
-returned as {@code oldState} the next time {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} is called. Recall that you must also write the same {@code newState} object in the
-{@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} callback—also doing it here ensures that the {@code oldState} object given to
-{@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} is valid even the first time {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} is called after the device is restored.</dd>
-</dl>
-
-<p>In your implementation of {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the
-{@code data} to iterate
-through all entities in the data set. For each entity found, do the following:</p>
-
-<ol>
- <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li>
- <li>Compare the entity key to a list of known key values that you should have declared as static
-final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of
-your known key strings, enter into a statement to extract the entity data and save it to the device:
- <ol>
- <li>Get the entity data size with {@link
-android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li>
- <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int)
-readEntityData()} and pass it the byte array, which is where the data will go, and specify the
-start offset and the size to read.</li>
- <li>Your byte array is now full and you can read the data and write it to the device
-however you like.</li>
- </ol>
- </li>
- <li>After you read and write your data back to the device, write the state of your data to the
-{@code newState} parameter the same as you do during {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()}.
-</ol>
-
-<p>For example, here's how you can restore the data backed up by the example in the previous
-section:</p>
-
-<pre>
-@Override
-public void onRestore(BackupDataInput data, int appVersionCode,
- ParcelFileDescriptor newState) throws IOException {
- // There should be only one entity, but the safest
- // way to consume it is using a while loop
- while (data.readNextHeader()) {
- String key = data.getKey();
- int dataSize = data.getDataSize();
-
- // If the key is ours (for saving top score). Note this key was used when
- // we wrote the backup entity header
- if (TOPSCORE_BACKUP_KEY.equals(key)) {
- // Create an input stream for the BackupDataInput
- byte[] dataBuf = new byte[dataSize];
- data.readEntityData(dataBuf, 0, dataSize);
- ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
- DataInputStream in = new DataInputStream(baStream);
-
- // Read the player name and score from the backup data
- mPlayerName = in.readUTF();
- mPlayerScore = in.readInt();
-
- // Record the score on the device (to a file or something)
- recordScore(mPlayerName, mPlayerScore);
- } else {
- // We don't know this entity key. Skip it. (Shouldn't happen.)
- data.skipEntityData();
- }
- }
-
- // Finally, write to the state blob (newState) that describes the restored data
- FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
- DataOutputStream out = new DataOutputStream(outstream);
- out.writeUTF(mPlayerName);
- out.writeInt(mPlayerScore);
-}
-</pre>
-
-<p>In this example, the {@code appVersionCode} parameter passed to {@link
-android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use
-it if you've chosen to perform backup when the user's version of the application has actually moved
-backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see
-the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p>
-
-<div class="special">
-<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
-href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
-ExampleAgent}</a> class in the <a
-href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
-application.</p>
-</div>
-
-
-
-
-
-
-<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2>
-
-<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want
-to back up complete files (from either {@link android.content.SharedPreferences} or <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>).
-Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less
-code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement
-{@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}.</p>
-
-<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must
-use one or more backup helpers. A backup helper is a specialized
-component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and
-restore operations for a particular type of data. The Android framework currently provides two
-different helpers:</p>
-<ul>
- <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link
-android.content.SharedPreferences} files.</li>
- <li>{@link android.app.backup.FileBackupHelper} to backup files from <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li>
-</ul>
-
-<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only
-one helper is needed for each data type. That is, if you have multiple {@link
-android.content.SharedPreferences} files, then you need only one {@link
-android.app.backup.SharedPreferencesBackupHelper}.</p>
-
-<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do
-the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p>
-<ol>
- <li>Instantiate in instance of the desired helper class. In the class constructor, you must
-specify the appropriate file(s) you want to backup.</li>
- <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()}
-to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li>
-</ol>
-
-<p>The following sections describe how to create a backup agent using each of the available
-helpers.</p>
-
-
-
-<h3 id="SharedPreferences">Backing up SharedPreferences</h3>
-
-<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must
-include the name of one or more {@link android.content.SharedPreferences} files.</p>
-
-<p>For example, to back up a {@link android.content.SharedPreferences} file named
-"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
-like this:</p>
-
-<pre>
-public class MyPrefsBackupAgent extends BackupAgentHelper {
- // The name of the SharedPreferences file
- static final String PREFS = "user_preferences";
-
- // A key to uniquely identify the set of backup data
- static final String PREFS_BACKUP_KEY = "prefs";
-
- // Allocate a helper and add it to the backup agent
- @Override
- public void onCreate() {
- SharedPreferencesBackupHelper helper =
- new SharedPreferencesBackupHelper(this, PREFS);
- addHelper(PREFS_BACKUP_KEY, helper);
- }
-}
-</pre>
-
-<p>That's it! That's your entire backup agent. The {@link
-android.app.backup.SharedPreferencesBackupHelper} includes all the code
-needed to backup and restore a {@link android.content.SharedPreferences} file.</p>
-
-<p>When the Backup Manager calls {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform
-backup and restore for your specified files.</p>
-
-<p class="note"><strong>Note:</strong> {@link android.content.SharedPreferences} are threadsafe, so
-you can safely read and write the shared preferences file from your backup agent and
-other activities.</p>
-
-
-
-<h3 id="Files">Backing up other files</h3>
-
-<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of
-one or more files that are saved to your application's <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>
-(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same
-location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes
-files).</p>
-
-<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link
-android.app.backup.BackupAgentHelper} looks like this:</p>
-
-<pre>
-public class MyFileBackupAgent extends BackupAgentHelper {
- // The name of the file
- static final String TOP_SCORES = "scores";
- static final String PLAYER_STATS = "stats";
-
- // A key to uniquely identify the set of backup data
- static final String FILES_BACKUP_KEY = "myfiles";
-
- // Allocate a helper and add it to the backup agent
- @Override
- public void onCreate() {
- FileBackupHelper helper = new FileBackupHelper(this,
- TOP_SCORES, PLAYER_STATS);
- addHelper(FILES_BACKUP_KEY, helper);
- }
-}
-</pre>
-
-<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and
-restore files that are saved to your application's <a
-href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p>
-
-<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To
-ensure that your backup agent does not read or write your files at the same time as your activities,
-you must use synchronized statements each time you perform a read or write. For example,
-in any Activity where you read and write the file, you need an object to use as the intrinsic
-lock for the synchronized statements:</p>
-
-<pre>
-// Object for intrinsic lock
-static final Object sDataLock = new Object();
-</pre>
-
-<p>Then create a synchronized statement with this lock each time you read or write the files. For
-example, here's a synchronized statement for writing the latest score in a game to a file:</p>
-
-<pre>
-try {
- synchronized (MyActivity.sDataLock) {
- File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES);
- RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
- raFile.writeInt(score);
- }
-} catch (IOException e) {
- Log.e(TAG, "Unable to write to file");
-}
-</pre>
-
-<p>You should synchronize your read statements with the same lock.</p>
-
-<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()} to synchronize the backup and restore operations with the same
-intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following
-methods:</p>
-
-<pre>
-@Override
-public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
- ParcelFileDescriptor newState) throws IOException {
- // Hold the lock while the FileBackupHelper performs backup
- synchronized (MyActivity.sDataLock) {
- super.onBackup(oldState, data, newState);
- }
-}
-
-@Override
-public void onRestore(BackupDataInput data, int appVersionCode,
- ParcelFileDescriptor newState) throws IOException {
- // Hold the lock while the FileBackupHelper restores the file
- synchronized (MyActivity.sDataLock) {
- super.onRestore(data, appVersionCode, newState);
- }
-}
-</pre>
-
-<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the
-{@link android.app.backup.BackupAgent#onCreate()} method and override {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} and {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()} to synchronize read and write operations.</p>
-
-<div class="special">
-<p>For an example implementation of {@link
-android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the
-{@code FileHelperExampleAgent} class in the <a
-href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
-application.</p>
-</div>
-
-
-
-
-
-
-<h2 id="RestoreVersion">Checking the Restore Data Version</h2>
-
-<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version
-of your application, as defined by your manifest file's <a
-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
-attribute. Before the Backup Manager calls your backup agent to restore your data, it
-looks at the <a
-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
-android:versionCode}</a> of the installed application and compares it to the value
-recorded in the restore data set. If the version recorded in the restore data set is
-<em>newer</em> than the application version on the device, then the user has downgraded their
-application. In this case, the Backup Manager will abort the restore operation for your application
-and not call your {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
-method, because the restore set is considered meaningless to an older version.</p>
-
-<p>You can override this behavior with the <a
-href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
-android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code
-false}" to indicate whether you want to restore the application regardless of the restore set
-version. The default value is "{@code false}". If you define this to be "{@code true}" then the
-Backup Manager will ignore the <a
-href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
-and call your {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
-method in all cases. In doing so, you can manually check for the version difference in your {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
-method and take any steps necessary to make the data compatible if the versions conflict.</p>
-
-<p>To help you handle different versions during a restore operation, the {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
-method passes you the version code included with the restore data set as the {@code appVersionCode}
-parameter. You can then query the current application's version code with the {@link
-android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p>
-
-<pre>
-PackageInfo info;
-try {
- String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}();
- info = {@link android.content.ContextWrapper#getPackageManager
-getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int)
-getPackageInfo}(name,0);
-} catch (NameNotFoundException nnfe) {
- info = null;
-}
-
-int version;
-if (info != null) {
- version = info.versionCode;
-}
-</pre>
-
-<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo}
-to the {@code appVersionCode} passed into {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
-</p>
-
-<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting
-<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
-android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your
-application that supports backup does not properly account for variations in your data format during
-{@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()},
-then the data on the device could be saved in a format incompatible with the version currently
-installed on the device.</p>
-
-
-
-<h2 id="RequestingBackup">Requesting Backup</h2>
-
-<p>You can request a backup operation at any time by calling {@link
-android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd
-like to backup your data using your backup agent. The Backup Manager then calls your backup
-agent's {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()} method at an opportune time in the future. Typically, you should
-request a backup each time your data changes (such as when the user changes an application
-preference that you'd like to back up). If you call {@link
-android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup
-Manager requests a backup from your agent, your agent still receives just one call to {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
-onBackup()}.</p>
-
-<p class="note"><strong>Note:</strong> While developing your application, you can request a
-backup and initiate an immediate backup operation with the <a
-href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
-tool</a>.</p>
-
-
-<h2 id="RequestingRestore">Requesting Restore</h2>
-
-<p>During the normal life of your application, you shouldn't need to request a restore operation.
-They system automatically checks for backup data and performs a restore when your application is
-installed. However, you can manually request a restore operation by calling {@link
-android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In
-which case, the Backup Manager calls your {@link
-android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
-implementation, passing the data from the current set of backup data.</p>
-
-<p class="note"><strong>Note:</strong> While developing your application, you can request a
-restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
-tool</a>.</p>
-
-
-<h2 id="Testing">Testing Your Backup Agent</h2>
-
-<p>Once you've implemented your backup agent, you can test the backup and restore functionality
-with the following procedure, using <a
-href="{@docRoot}tools/help/bmgr.html">{@code bmgr}</a>.</p>
-
-<ol>
- <li>Install your application on a suitable Android system image
- <ul>
- <li>If using the emulator, create and use an AVD with Android 2.2 (API Level 8).</li>
- <li>If using a device, the device must be running Android 2.2 or greater and have Google
-Play built in.</li>
- </ul>
- </li>
- <li>Ensure that backup is enabled
- <ul>
- <li>If using the emulator, you can enable backup with the following command from your SDK
-{@code tools/} path:
-<pre class="no-pretty-print">adb shell bmgr enable true</pre>
- </li>
- <li>If using a device, open the system <b>Settings</b>, select
- <b>Backup & reset</b>, then enable
- <b>Back up my data</b> and <b>Automatic restore</b>.</li>
- </ul>
- </li>
- <li>Open your application and initialize some data
- <p>If you've properly implemented backup in your application, then it should request a
-backup each time the data changes. For example, each time the user changes some data, your app
-should call {@link android.app.backup.BackupManager#dataChanged()}, which adds a backup request to
-the Backup Manager queue. For testing purposes, you can also make a request with the following
-{@code bmgr} command:</p>
-<pre class="no-pretty-print">adb shell bmgr backup <em>your.package.name</em></pre>
- </li>
- <li>Initiate a backup operation:
-<pre class="no-pretty-print">adb shell bmgr run</pre>
- <p>This forces the Backup Manager to perform all backup requests that are in its
-queue.</p>
- <li>Uninstall your application:
-<pre class="no-pretty-print">adb uninstall <em>your.package.name</em></pre>
- </li>
- <li>Re-install your application.</li>
-</ol>
-
-<p>If your backup agent is successful, all the data you initialized in step 4 is restored.</p>
-
-
+<p class="note"><strong>Note:</strong> These data backup features are not designed for synchronizing app data with other clients or
+saving data that you'd like to access during the normal application lifecycle.
+You cannot read or write backup data on demand. For synchronizing app data, see
+<a href="{@docRoot}training/sync-adapters/index.html">Transferring
+Data Using Sync Adapters</a> or <a href="https://developers.google.com/drive/android/">Google Drive Android
+API</a>.
\ No newline at end of file
diff --git a/docs/html/guide/topics/data/images/backup-framework.png b/docs/html/guide/topics/data/images/backup-framework.png
new file mode 100644
index 0000000..2ba2e612
--- /dev/null
+++ b/docs/html/guide/topics/data/images/backup-framework.png
Binary files differ
diff --git a/docs/html/guide/topics/data/index.jd b/docs/html/guide/topics/data/index.jd
index 3872825..2365f18 100644
--- a/docs/html/guide/topics/data/index.jd
+++ b/docs/html/guide/topics/data/index.jd
@@ -5,21 +5,3 @@
@jd:body
-<div class="landing-docs">
-
-
- <div class="col-12">
- <h3>Training</h3>
-
- <a href="{@docRoot}training/backup/index.html">
- <h4>Backing up App Data to the Cloud</h4>
- <p>
- This class covers techniques for backing up data to the cloud so that
- users can restore their data when recovering from a data loss (such as a
- factory reset) or installing your application on a new device.
- </p>
- </a>
-
- </div>
-
-</div>
diff --git a/docs/html/guide/topics/data/keyvaluebackup.jd b/docs/html/guide/topics/data/keyvaluebackup.jd
new file mode 100644
index 0000000..c7c5e2f
--- /dev/null
+++ b/docs/html/guide/topics/data/keyvaluebackup.jd
@@ -0,0 +1,884 @@
+page.title=Key/Value Backup
+page.tags=backup, marshmallow, androidm
+page.keywords=backup, kvbackup
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#Comparison">Comparison to Auto Backup</a></li>
+ <li><a href="#ImplementingBackup">Implementing Key/Value Backup</a></li>
+
+ <li><a href="#BackupManifest">Declaring the backup agent in your manifest</a></li>
+ <li><a href="#BackupKey">Registering for Android Backup Service</a></li>
+ <li><a href="#BackupAgent">Extending BackupAgent</a>
+ <ol>
+ <li><a href="#RequiredMethods">Required methods</a></li>
+ <li><a href="#PerformingBackup">Performing backup</a></li>
+ <li><a href="#PerformingRestore">Performing restore</a></li>
+ </ol>
+ </li>
+ <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
+ <ol>
+ <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li>
+ <li><a href="#Files">Backing up private files</a></li>
+ </ol>
+ </li>
+ <li><a href="#RestoreVersion">Checking the restore data version</a></li>
+ <li><a href="#RequestingBackup">Requesting backup</a></li>
+ <li><a href="#RequestingRestore">Requesting restore</a></li>
+ <li><a href="#Migrating">Migrating to Auto Backup</a></li>
+ </ol>
+
+ <h2>Key classes</h2>
+ <ol>
+ <li>{@link android.app.backup.BackupManager}</li>
+ <li>{@link android.app.backup.BackupAgent}</li>
+ <li>{@link android.app.backup.BackupAgentHelper}</li>
+ </ol>
+
+</div>
+</div>
+
+
+<p>Since Android 2.2 (API 8), Android has offered the <em>Key/Value Backup</em>
+feature as a way for developers to backup app data to the cloud. The Key/Value
+Backup feature (formerly known as the Backup API and the Android Backup Service)
+preserves app data by uploading it to
+<a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
+The amount of data is limited to 5MB per user of your app and there is
+no charge for storing backup data.
+
+<p class="note"><strong>Note:</strong> If your app implements Key/Value Backup
+and targets API 23 or higher, you should set
+<a href="{@docRoot}reference/android/R.attr.html#fullBackupOnly">android:fullBackupOnly</a>.
+This attribute indicates whether or not to use Auto Backup on devices where it is available.
+
+<h2 id="Comparison">Comparison to Auto Backup</h2>
+<p>Like Auto Backup, Key/Value Backups are restored automatically whenever the app
+is installed. The following table describes some of the key differences between Key/Value Backup and Auto Backup:
+
+<table>
+ <tr>
+ <th>Key/Value Backup</th>
+ <th>Auto Backup</th>
+ </tr>
+ <tr>
+ <td>Available in API 8, Android 2.2</td>
+ <td>Available in API 23, Android 6.0</td>
+ </tr>
+ <tr>
+ <td>Apps must implement a {@link android.app.backup.BackupAgent}. The backup agent defines what data to backup and how to
+restore data.</td>
+ <td>By default, Auto Backup includes almost all of the app's files. You can
+use XML to include and exclude files. Under the hood, Auto Backup relies on a
+backup agent that is built into the framework.</td>
+ </tr>
+ <tr>
+ <td>Apps must issue a request when there is data
+that is ready to be backed up. Requests
+from multiple apps are batched and executed every few hours.</td>
+ <td>Backups happen automatically roughly once a day.</td>
+ </tr>
+ <tr>
+ <td>Backup data can be transmitted via wifi or cellular data.</td>
+ <td>Backup data is tranmitted only via wifi. If the device is never connected to a
+wifi network, then Auto Backup never occurs.</td>
+ </tr>
+ <tr>
+ <td>Apps are not shut down during backup.</td>
+ <td>The system shuts down the app during backup.</td>
+ </tr>
+ <tr>
+ <td>Backup data is stored in <a href="{@docRoot}google/backup/index.html">Android Backup Service</a> limited to 5MB per app.</td>
+ <td>Backup data is stored in the user's Google Drive limited to 25MB per app.</td>
+ </tr>
+ <tr>
+ <td>Related API methods are not filed based:<ul>
+ <li>{@link android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()}
+ <li>{@link android.app.backup.BackupAgent#onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()}</ul></td>
+ <td>Related API methods are filed based:<ul>
+<li>{@link android.app.backup.BackupAgent#onFullBackup(FullBackupDataOutput) onFullBackup()}
+<li>{@link android.app.backup.BackupAgent#onRestoreFile(ParcelFileDescriptor,long,File,int,long,long) onRestoreFile()}</ul></td>
+ </tr>
+</table>
+
+<h2 id="ImplementingBackup">Implementing Key/Value Backup</h2>
+<p>To backup your application data, you need to implement a backup agent. Your backup
+agent is called by the Backup Manager both during backup and restore.</p>
+
+<p>To implement a backup agent, you must:</p>
+
+<ol>
+ <li>Declare your backup agent in your manifest file with the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
+android:backupAgent}</a> attribute.</li>
+ <li>Register your application with <a href="{@docRoot}google/backup/index.html">Android
+ Backup Service</a></li>
+ <li>Define a backup agent by either:</p>
+ <ol type="a">
+ <li><a href="#BackupAgent">Extending BackupAgent</a>
+ <p>The {@link android.app.backup.BackupAgent} class provides the central interface with
+which your application communicates with the Backup Manager. If you extend this class
+directly, you must override {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} to handle the backup and restore operations for your data.</p>
+ <p><em>Or</em></p>
+ <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
+ <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient
+wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code
+you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more
+"helper" objects, which automatically backup and restore certain types of data, so that you do not
+need to implement {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}.</p>
+ <p>Android currently provides backup helpers that will backup and restore complete files
+from {@link android.content.SharedPreferences} and <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p>
+ </li>
+ </ol>
+ </li>
+</ol>
+
+<h2 id="BackupManifest">Declaring the backup agent in your manifest</h2>
+
+<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare
+it in your manifest with the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
+android:backupAgent}</a> attribute in the <a
+href="{@docRoot}guide/topics/manifest/application-element.html">{@code
+<application>}</a> tag.</p>
+
+<p>For example:</p>
+
+<pre>
+<manifest ... >
+ ...
+ <application android:label="MyApplication"
+ <b>android:backupAgent="MyBackupAgent"</b>>
+ <activity ... >
+ ...
+ </activity>
+ </application>
+</manifest>
+</pre>
+
+<p>Another attribute you might want to use is <a
+href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
+android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you
+want to restore the application data regardless of the current application version compared to the
+version that produced the backup data. (The default value is "{@code false}".) See <a
+href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p>
+
+<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are
+available only on devices running API Level 8 (Android 2.2) or greater, so you should also
+set your <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
+attribute to "8".</p>
+
+
+
+
+<h2 id="BackupKey">Registering for Android Backup Service</h2>
+
+<p>Google provides a backup transport with <a
+href="{@docRoot}google/backup/index.html">Android Backup Service</a> for most
+Android-powered devices running Android 2.2 or greater.</p>
+
+<p>In order for your application to perform backup using Android Backup Service, you must
+register your application with the service to receive a Backup Service Key, then
+declare the Backup Service Key in your Android manifest.</p>
+
+<p>To get your Backup Service Key, <a
+href="{@docRoot}google/backup/signup.html">register for Android Backup Service</a>.
+When you register, you will be provided a Backup Service Key and the appropriate {@code
+<meta-data>} XML code for your Android manifest file, which you must include as a child of the
+{@code <application>} element. For example:</p>
+
+<pre>
+<application android:label="MyApplication"
+ android:backupAgent="MyBackupAgent">
+ ...
+ <meta-data android:name="com.google.android.backup.api_key"
+ android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" />
+</application>
+</pre>
+
+<p>The <code>android:name</code> must be <code>"com.google.android.backup.api_key"</code> and
+the <code>android:value</code> must be the Backup Service Key received from the Android Backup
+Service registration.</p>
+
+<p>If you have multiple applications, you must register each one, using the respective package
+name.</p>
+
+<p class="note"><strong>Note:</strong> The backup transport provided by Android Backup Service is
+not guaranteed to be available
+on all Android-powered devices that support backup. Some devices might support backup
+using a different transport, some devices might not support backup at all, and there is no way for
+your application to know what transport is used on the device. However, if you implement backup for
+your application, you should always include a Backup Service Key for Android Backup Service so
+your application can perform backup when the device uses the Android Backup Service transport. If
+the device does not use Android Backup Service, then the {@code <meta-data>} element with the
+Backup Service Key is ignored.</p>
+
+
+
+
+<h2 id="BackupAgent">Extending BackupAgent</h2>
+
+<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
+directly, but should instead <a href="#BackupAgentHelper">extend BackupAgentHelper</a> to take
+advantage of the built-in helper classes that automatically backup and restore your files. However,
+you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
+<ul>
+ <li>Version your data format. For instance, if you anticipate the need to revise the
+format in which you write your application data, you can build a backup agent to cross-check your
+application version during a restore operation and perform any necessary compatibility work if the
+version on the device is different than that of the backup data. For more information, see <a
+href="#RestoreVersion">Checking the Restore Data Version</a>.</li>
+ <li>Instead of backing up an entire file, you can specify the portions of data the should be
+backed up and how each portion is then restored to the device. (This can also help you manage
+different versions, because you read and write your data as unique entities, rather than
+complete files.)</li>
+ <li>Back up data in a database. If you have an SQLite database that you want to restore when
+the user re-installs your application, you need to build a custom {@link
+android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then
+create your table and insert the data during a restore operation.</li>
+</ul>
+
+<p>If you don't need to perform any of the tasks above and want to back up complete files from
+{@link android.content.SharedPreferences} or <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
+should skip to <a href="#BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
+
+
+
+<h3 id="RequiredMethods">Required methods</h3>
+
+<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you
+must implement the following callback methods:</p>
+
+<dl>
+ <dt>{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}</dt>
+ <dd>The Backup Manager calls this method after you <a href="#RequestingBackup">request a
+backup</a>. In this method, you read your application data from the device and pass the data you
+want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing
+backup</a>.</dd>
+
+ <dt>{@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}</dt>
+ <dd>The Backup Manager calls this method during a restore operation (you can <a
+href="#RequestingRestore">request a restore</a>, but the system automatically performs restore when
+the user re-installs your application). When it calls this method, the Backup Manager delivers your
+backup data, which you then restore to the device, as described below in <a
+href="#PerformingRestore">Performing restore</a>.</dd>
+</dl>
+
+
+
+<h3 id="PerformingBackup">Performing backup</h3>
+
+
+<p>When it's time to back up your application data, the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. This is where you must provide your application data to the Backup Manager so
+it can be saved to cloud storage.</p>
+
+<p>Only the Backup Manager can call your backup agent's {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. Each time that your application data changes and you want to perform a backup,
+you must request a backup operation by calling {@link
+android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting
+Backup</a> for more information). A backup request does not result in an immediate call to your
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs
+backup for all applications that have requested a backup since the last backup was performed.</p>
+
+<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an
+immediate backup operation from the Backup Manager with the <a
+href="{@docRoot}tools/help/bmgr.html">{@code bmgr} tool</a>.</p>
+
+<p>When the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method, it passes three parameters:</p>
+
+<dl>
+ <dt>{@code oldState}</dt>
+ <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup
+state provided by your application. This is not the backup data from cloud storage, but a
+local representation of the data that was backed up the last time {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} was called (as defined by {@code newState}, below, or from {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}—more about this in the next section). Because {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} does not allow you to read existing backup data in
+the cloud storage, you can use this local representation to determine whether your data has changed
+since the last backup.</dd>
+ <dt>{@code data}</dt>
+ <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup
+data to the Backup Manager.</dd>
+ <dt>{@code newState}</dt>
+ <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
+you must write a representation of the data that you delivered to {@code data} (a representation
+can be as simple as the last-modified timestamp for your file). This object is
+returned as {@code oldState} the next time the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState}
+will point to an empty file next time Backup Manager calls {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}.</dd>
+</dl>
+
+<p>Using these parameters, you should implement your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method to do the following:</p>
+
+<ol>
+ <li>Check whether your data has changed since the last backup by comparing {@code oldState} to
+your current data. How you read data in {@code oldState} depends on how you originally wrote it to
+{@code newState} (see step 3). The easiest way to record the state of a file is with its
+last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code
+oldState}:
+ <pre>
+// Get the oldState input stream
+FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
+DataInputStream in = new DataInputStream(instream);
+
+try {
+ // Get the last modified timestamp from the state file and data file
+ long stateModified = in.readLong();
+ long fileModified = mDataFile.lastModified();
+
+ if (stateModified != fileModified) {
+ // The file has been modified, so do a backup
+ // Or the time on the device changed, so be safe and do a backup
+ } else {
+ // Don't back up because the file hasn't changed
+ return;
+ }
+} catch (IOException e) {
+ // Unable to read state file... be safe and do a backup
+}
+</pre>
+ <p>If nothing has changed and you don't need to back up, skip to step 3.</p>
+ </li>
+ <li>If your data has changed, compared to {@code oldState}, write the current data to
+{@code data} to back it up to the cloud storage.
+ <p>You must write each chunk of data as an "entity" in the {@link
+android.app.backup.BackupDataOutput}. An entity is a flattened binary data
+record that is identified by a unique key string. Thus, the data set that you back up is
+conceptually a set of key-value pairs.</p>
+ <p>To add an entity to your backup data set, you must:</p>
+ <ol>
+ <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
+writeEntityHeader()}, passing a unique string key for the data you're about to write and the data
+size.</li>
+ <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
+writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
+from the buffer (which should match the size passed to {@link
+android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li>
+ </ol>
+ <p>For example, the following code flattens some data into a byte stream and writes it into a
+single entity:</p>
+ <pre>
+// Create buffer stream and data output stream for our data
+ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
+DataOutputStream outWriter = new DataOutputStream(bufStream);
+// Write structured data
+outWriter.writeUTF(mPlayerName);
+outWriter.writeInt(mPlayerScore);
+// Send the data to the Backup Manager via the BackupDataOutput
+byte[] buffer = bufStream.toByteArray();
+int len = buffer.length;
+data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
+data.writeEntityData(buffer, len);
+</pre>
+ <p>Perform this for each piece of data that you want to back up. How you divide your data into
+entities is up to you (and you might use just one entity).</p>
+ </li>
+ <li>Whether or not you perform a backup (in step 2), write a representation of the current data to
+the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object
+locally as a representation of the data that is currently backed up. It passes this back to you as
+{@code oldState} the next time it calls {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
+do not write the current data state to this file, then
+{@code oldState} will be empty during the next callback.
+ <p>The following example saves a representation of the current data into {@code newState} using
+the file's last-modified timestamp:</p>
+ <pre>
+FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
+DataOutputStream out = new DataOutputStream(outstream);
+
+long modified = mDataFile.lastModified();
+out.writeLong(modified);
+</pre>
+ </li>
+</ol>
+
+<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure
+that you use synchronized statements while accessing the file so that your backup agent does not
+read the file while an Activity in your application is also writing the file.</p>
+
+
+
+
+<h3 id="PerformingRestore">Performing restore</h3>
+
+<p>When it's time to restore your application data, the Backup Manager calls your backup
+agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so
+you can restore it onto the device.</p>
+
+<p>Only the Backup Manager can call {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}, which happens automatically when the system installs your application and
+finds existing backup data. However, you can request a restore operation for
+your application by calling {@link
+android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a
+href="#RequestingRestore">Requesting restore</a> for more information).</p>
+
+<p class="note"><strong>Note:</strong> While developing your application, you can also request a
+restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
+tool</a>.</p>
+
+<p>When the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} method, it passes three parameters:</p>
+
+<dl>
+ <dt>{@code data}</dt>
+ <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup
+data.</dd>
+ <dt>{@code appVersionCode}</dt>
+ <dd>An integer representing the value of your application's <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
+manifest attribute, as it was when this data was backed up. You can use this to cross-check the
+current application version and determine if the data format is compatible. For more
+information about using this to handle different versions of restore data, see the section
+below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd>
+ <dt>{@code newState}</dt>
+ <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
+you must write the final backup state that was provided with {@code data}. This object is
+returned as {@code oldState} the next time {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} is called. Recall that you must also write the same {@code newState} object in the
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} callback—also doing it here ensures that the {@code oldState} object given to
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} is valid even the first time {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} is called after the device is restored.</dd>
+</dl>
+
+<p>In your implementation of {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the
+{@code data} to iterate
+through all entities in the data set. For each entity found, do the following:</p>
+
+<ol>
+ <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li>
+ <li>Compare the entity key to a list of known key values that you should have declared as static
+final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of
+your known key strings, enter into a statement to extract the entity data and save it to the device:
+ <ol>
+ <li>Get the entity data size with {@link
+android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li>
+ <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int)
+readEntityData()} and pass it the byte array, which is where the data will go, and specify the
+start offset and the size to read.</li>
+ <li>Your byte array is now full and you can read the data and write it to the device
+however you like.</li>
+ </ol>
+ </li>
+ <li>After you read and write your data back to the device, write the state of your data to the
+{@code newState} parameter the same as you do during {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}.
+</ol>
+
+<p>For example, here's how you can restore the data backed up by the example in the previous
+section:</p>
+
+<pre>
+@Override
+public void onRestore(BackupDataInput data, int appVersionCode,
+ ParcelFileDescriptor newState) throws IOException {
+ // There should be only one entity, but the safest
+ // way to consume it is using a while loop
+ while (data.readNextHeader()) {
+ String key = data.getKey();
+ int dataSize = data.getDataSize();
+
+ // If the key is ours (for saving top score). Note this key was used when
+ // we wrote the backup entity header
+ if (TOPSCORE_BACKUP_KEY.equals(key)) {
+ // Create an input stream for the BackupDataInput
+ byte[] dataBuf = new byte[dataSize];
+ data.readEntityData(dataBuf, 0, dataSize);
+ ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
+ DataInputStream in = new DataInputStream(baStream);
+
+ // Read the player name and score from the backup data
+ mPlayerName = in.readUTF();
+ mPlayerScore = in.readInt();
+
+ // Record the score on the device (to a file or something)
+ recordScore(mPlayerName, mPlayerScore);
+ } else {
+ // We don't know this entity key. Skip it. (Shouldn't happen.)
+ data.skipEntityData();
+ }
+ }
+
+ // Finally, write to the state blob (newState) that describes the restored data
+ FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
+ DataOutputStream out = new DataOutputStream(outstream);
+ out.writeUTF(mPlayerName);
+ out.writeInt(mPlayerScore);
+}
+</pre>
+
+<p>In this example, the {@code appVersionCode} parameter passed to {@link
+android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use
+it if you've chosen to perform backup when the user's version of the application has actually moved
+backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see
+the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p>
+
+<div class="special">
+<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
+href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
+ExampleAgent}</a> class in the <a
+href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
+application.</p>
+</div>
+
+
+
+
+
+
+<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2>
+
+<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want
+to back up complete files (from either {@link android.content.SharedPreferences} or <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>).
+Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less
+code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}.</p>
+
+<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must
+use one or more backup helpers. A backup helper is a specialized
+component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and
+restore operations for a particular type of data. The Android framework currently provides two
+different helpers:</p>
+<ul>
+ <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link
+android.content.SharedPreferences} files.</li>
+ <li>{@link android.app.backup.FileBackupHelper} to backup files from <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li>
+</ul>
+
+<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only
+one helper is needed for each data type. That is, if you have multiple {@link
+android.content.SharedPreferences} files, then you need only one {@link
+android.app.backup.SharedPreferencesBackupHelper}.</p>
+
+<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do
+the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p>
+<ol>
+ <li>Instantiate in instance of the desired helper class. In the class constructor, you must
+specify the appropriate file(s) you want to backup.</li>
+ <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()}
+to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li>
+</ol>
+
+<p>The following sections describe how to create a backup agent using each of the available
+helpers.</p>
+
+
+
+<h3 id="SharedPreferences">Backing up SharedPreferences</h3>
+
+<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must
+include the name of one or more {@link android.content.SharedPreferences} files.</p>
+
+<p>For example, to back up a {@link android.content.SharedPreferences} file named
+"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
+like this:</p>
+
+<pre>
+public class MyPrefsBackupAgent extends BackupAgentHelper {
+ // The name of the SharedPreferences file
+ static final String PREFS = "user_preferences";
+
+ // A key to uniquely identify the set of backup data
+ static final String PREFS_BACKUP_KEY = "prefs";
+
+ // Allocate a helper and add it to the backup agent
+ @Override
+ public void onCreate() {
+ SharedPreferencesBackupHelper helper =
+ new SharedPreferencesBackupHelper(this, PREFS);
+ addHelper(PREFS_BACKUP_KEY, helper);
+ }
+}
+</pre>
+
+<p>That's it! That's your entire backup agent. The {@link
+android.app.backup.SharedPreferencesBackupHelper} includes all the code
+needed to backup and restore a {@link android.content.SharedPreferences} file.</p>
+
+<p>When the Backup Manager calls {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform
+backup and restore for your specified files.</p>
+
+<p class="note"><strong>Note:</strong> The methods of {@link android.content.SharedPreferences}
+are threadsafe, so
+you can safely read and write the shared preferences file from your backup agent and
+other activities.</p>
+
+
+
+<h3 id="Files">Backing up other files</h3>
+
+<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of
+one or more files that are saved to your application's <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>
+(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same
+location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes
+files).</p>
+
+<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link
+android.app.backup.BackupAgentHelper} looks like this:</p>
+
+<pre>
+public class MyFileBackupAgent extends BackupAgentHelper {
+ // The name of the file
+ static final String TOP_SCORES = "scores";
+ static final String PLAYER_STATS = "stats";
+
+ // A key to uniquely identify the set of backup data
+ static final String FILES_BACKUP_KEY = "myfiles";
+
+ // Allocate a helper and add it to the backup agent
+ @Override
+ public void onCreate() {
+ FileBackupHelper helper = new FileBackupHelper(this,
+ TOP_SCORES, PLAYER_STATS);
+ addHelper(FILES_BACKUP_KEY, helper);
+ }
+}
+</pre>
+
+<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and
+restore files that are saved to your application's <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p>
+
+<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To
+ensure that your backup agent does not read or write your files at the same time as your activities,
+you must use synchronized statements each time you perform a read or write. For example,
+in any Activity where you read and write the file, you need an object to use as the intrinsic
+lock for the synchronized statements:</p>
+
+<pre>
+// Object for intrinsic lock
+static final Object sDataLock = new Object();
+</pre>
+
+<p>Then create a synchronized statement with this lock each time you read or write the files. For
+example, here's a synchronized statement for writing the latest score in a game to a file:</p>
+
+<pre>
+try {
+ synchronized (MyActivity.sDataLock) {
+ File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES);
+ RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
+ raFile.writeInt(score);
+ }
+} catch (IOException e) {
+ Log.e(TAG, "Unable to write to file");
+}
+</pre>
+
+<p>You should synchronize your read statements with the same lock.</p>
+
+<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} to synchronize the backup and restore operations with the same
+intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following
+methods:</p>
+
+<pre>
+@Override
+public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) throws IOException {
+ // Hold the lock while the FileBackupHelper performs backup
+ synchronized (MyActivity.sDataLock) {
+ super.onBackup(oldState, data, newState);
+ }
+}
+
+@Override
+public void onRestore(BackupDataInput data, int appVersionCode,
+ ParcelFileDescriptor newState) throws IOException {
+ // Hold the lock while the FileBackupHelper restores the file
+ synchronized (MyActivity.sDataLock) {
+ super.onRestore(data, appVersionCode, newState);
+ }
+}
+</pre>
+
+<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the
+{@link android.app.backup.BackupAgent#onCreate()} method and override {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} to synchronize read and write operations.</p>
+
+<div class="special">
+<p>For an example implementation of {@link
+android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the
+{@code FileHelperExampleAgent} class in the <a
+href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
+application.</p>
+</div>
+
+
+
+
+
+
+<h2 id="RestoreVersion">Checking the restore data version</h2>
+
+<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version
+of your application, as defined by your manifest file's <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
+attribute. Before the Backup Manager calls your backup agent to restore your data, it
+looks at the <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
+android:versionCode}</a> of the installed application and compares it to the value
+recorded in the restore data set. If the version recorded in the restore data set is
+<em>newer</em> than the application version on the device, then the user has downgraded their
+application. In this case, the Backup Manager will abort the restore operation for your application
+and not call your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method, because the restore set is considered meaningless to an older version.</p>
+
+<p>You can override this behavior with the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
+android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code
+false}" to indicate whether you want to restore the application regardless of the restore set
+version. The default value is "{@code false}". If you define this to be "{@code true}" then the
+Backup Manager will ignore the <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
+and call your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method in all cases. In doing so, you can manually check for the version difference in your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method and take any steps necessary to make the data compatible if the versions conflict.</p>
+
+<p>To help you handle different versions during a restore operation, the {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method passes you the version code included with the restore data set as the {@code appVersionCode}
+parameter. You can then query the current application's version code with the {@link
+android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p>
+
+<pre>
+PackageInfo info;
+try {
+ String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}();
+ info = {@link android.content.ContextWrapper#getPackageManager
+getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int)
+getPackageInfo}(name,0);
+} catch (NameNotFoundException nnfe) {
+ info = null;
+}
+
+int version;
+if (info != null) {
+ version = info.versionCode;
+}
+</pre>
+
+<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo}
+to the {@code appVersionCode} passed into {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
+</p>
+
+<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting
+<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
+android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your
+application that supports backup does not properly account for variations in your data format during
+{@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()},
+then the data on the device could be saved in a format incompatible with the version currently
+installed on the device.</p>
+
+
+
+<h2 id="RequestingBackup">Requesting backup</h2>
+
+<p>You can request a backup operation at any time by calling {@link
+android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd
+like to backup your data using your backup agent. The Backup Manager then calls your backup
+agent's {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method at an opportune time in the future. Typically, you should
+request a backup each time your data changes (such as when the user changes an application
+preference that you'd like to back up). If you call {@link
+android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup
+Manager requests a backup from your agent, your agent still receives just one call to {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}.</p>
+
+<p class="note"><strong>Note:</strong> While developing your application, you can request a
+backup and initiate an immediate backup operation with the <a
+href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
+tool</a>.</p>
+
+
+<h2 id="RequestingRestore">Requesting restore</h2>
+
+<p>During the normal life of your application, you shouldn't need to request a restore operation.
+They system automatically checks for backup data and performs a restore when your application is
+installed. However, you can manually request a restore operation by calling {@link
+android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In
+which case, the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+implementation, passing the data from the current set of backup data.</p>
+
+<p class="note"><strong>Note:</strong> While developing your application, you can request a
+restore operation with the <a href="{@docRoot}tools/help/bmgr.html">{@code bmgr}
+tool</a>.</p>
+
+
+<h2 id="Migrating">Migrating to Auto Backup</h2>
+<p>You can transition your app to full-data backups by setting <a href="{@docRoot}reference/android/R.attr.html#fullBackupOnly">android:fullBackupOnly</a> to <code>true</code> in the <code><application></code> element in the manifest file. When
+running on a device with Android 5.1 (API level 22) or lower, your app ignores
+this value in the manifest, and continues performing Key/Value Backups. When
+running on a device with Android 6.0 (API level 23) or higher, your app performs
+Auto Backup instead of Key/Value Backup.
\ No newline at end of file
diff --git a/docs/html/guide/topics/data/testingbackup.jd b/docs/html/guide/topics/data/testingbackup.jd
new file mode 100644
index 0000000..6ff5837
--- /dev/null
+++ b/docs/html/guide/topics/data/testingbackup.jd
@@ -0,0 +1,181 @@
+page.title=Testing Backup and Restore
+page.tags=backup, marshmallow, androidm
+page.keywords=backup, restore, testing
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#HowBackupWorks">How backup works</a></li>
+ <li><a href="#Prerequisites">Prerequisites</a></li>
+ <li><a href="#Preparing">Preparing your device or emulator</a></li>
+ <li><a href="#TestingBackup">Testing backup</a></li>
+ <li><a href="#TestingRestore">Testing restore</a></li>
+ <li><a href="#Troubleshooting">Troubleshooting</a></li>
+ </ol>
+
+</div>
+</div>
+
+<p>This page shows you how to manually trigger Auto Backup, Key/Value Backup, and restore operations to
+ensure your app saves and restores data properly.
+
+<h2 id="HowBackupWorkso">How backup works</h2>
+<p>The section describes various pieces in the Android backup framework and how they
+interact with apps that support Auto Backup and Key/Value Backup. During the app
+development phase, most of the inner working of the framework were abstracted away, so you didn't need to know this information. However, during the
+testing phase, an understanding of these concepts is important.
+
+<p>The following diagram illustrates how data flows during backup and restore:
+
+<img src="images/backup-framework.png" alt="backup-framework">
+
+<p>The <em>Backup Manager Service</em> is an Android system
+service which orchestrates and initiates backup and restore operations. The service
+is accessible through the {@link android.app.backup.BackupManager}
+API. During a backup operation, the service queries your app for backup data,
+then hands it to the <em>backup transport</em>, which then archives the data.
+During a restore operation, the backup manager service retrieves the backup data
+from the backup transport and restores the data to the device.
+
+<p><em>Backup Transports</em> are Android components that are responsible
+for storing and retrieving backups. An Android device can have zero or more
+backup transports, but only one of those transports can be marked active. The
+available backup transports may differ from device to device (due to
+customizations by device manufacturers and service providers), but most Google
+Play enabled devices ship with the following transports:
+</p><ul>
+<li><strong>Google GMS Transport</strong>(default) - the active backup
+transport on most devices, part of <a href="https://www.android.com/gms/">Google Mobile Services</a>. This documentation assumes that users are using the
+Google GMS transport. This transport stores Auto Backup data in a private folder in the
+user's Google Drive account. Key/Value Backup data is stored in the <a href="{@docRoot}google/backup/index.html">Android Backup Service</a>.
+<li><strong>Local Transport</strong> - stores backup data locally on the device.
+This transport is typically used for development/debugging purposes and is not
+useful in the real world.</li></ul>
+
+<p>If a device does not have any backup transports, then the data cannot be
+backed up. Your app is not adversely affected.
+
+<p class="caution"><strong>Caution:</strong> Because the backup transport
+can differ from device to device, Android cannot guarantee the security
+of your data while using backup. Be cautious about using backup to store
+sensitive data, such as usernames and passwords.
+
+<h2 id="Prerequisites">Prerequisites</h2>
+<p>You need to know a bit about the following tools:
+
+<ul>
+ <li><a href="{@docRoot}studio/command-line/adb.html">adb</a>
+- to run commands on the device or emulator
+ <li><a href="{@docRoot}studio/command-line/bmgr.html">bmgr</a> - to
+perform various backup and restore operations
+ <li><a href="{@docRoot}studio/command-line/logcat.html">logcat</a>
+- to see the output of backup and restore operations.</li></ul>
+
+<h2 id="Preparing">Preparing your device or
+emulator</h2>
+<p>Prepare your device or emulator for backup testing by working through the
+following checklist:
+<ul>
+ <li>For Auto Backup, check that you are using a device or emulator running
+Android 6.0 (API level 23) or higher.</li>
+ <li>For Key/Value Backup, check that you are using a device or emulator running
+Android 2.2 (API level 8) or higher.</li>
+ <li>Check that backup and restore is enabled on the device or emulator. There
+are two ways to check: <ul>
+ <li>On the device, go to <strong>Settings -> Backup & Restore</strong>.
+ <li>From adb shell, run <code>bmgr enable</code></li></ul>
+ <p>On physical devices, backup and restore is typically enabled during the
+initial setup wizard. Emulators do not run the setup wizard, so don't forget to
+enable backup and specify a backup account in device settings.
+ <li>Make sure the GMS Backup Transport is available and active by running the
+command from adb shell:
+ <pre class="prettyprint">$ bmgr list transports</pre>
+ <p>Then, check the console for the following output:
+ <pre class="prettyprint">android/com.android.internal.backup.LocalTransport
+* com.google.android.gms/.backup.BackupTransportService</pre>
+ <p>Physical devices without Google Play and emulators without Google APIs
+might not include the GMS Backup Transport. This article assumes you are using
+the GMS Backup Transport. You can test backup and restore with other backup
+transports, but the procedure and output can differ.
+</ul>
+
+<h2 id="TestingBackup">Testing backup</h2>
+<p>To initiate a backup of your app, run the following command:
+
+<pre class="prettyprint">$ bmgr backupnow <PACKAGE></pre>
+
+<p>The <code>backupnow</code> command runs either a Key/Value Backup or Auto Backup depending on
+the package's manifest declarations. Check logcat to see the output of the
+backup procedure. For example:
+
+<pre class="prettyprint">D/BackupManagerService: fullTransportBackup()
+I/GmsBackupTransport: Attempt to do full backup on <PACKAGE>
+
+---- or ----
+
+V/BackupManagerService: Scheduling immediate backup pass
+D/PerformBackupTask: starting key/value Backup of BackupRequest{pkg=<PACKAGE>}
+</pre>
+
+<p>If the <code>backupnow</code> command is not available on your device, you need to run one
+of the following commands:
+<ul>
+ <li>For Auto Backups, run: <code>bmgr fullbackup <PACKAGE></code>
+ <li>For Key/Value Backups, schedule and run your backup with the following
+commands:
+ <pre class="prettyprint">$ bmgr backup <PACKAGE>
+$ bmgr run</pre>
+ <p><code>bmgr backup</code> adds your app to the Backup Manager's queue. <code>bmgr run</code> initiates the
+backup operation, which forces the Backup Manager to perform all backup requests
+that are in its queue.
+ </li></ul>
+
+<h2 id="TestingRestore">Testing restore</h2>
+<p>To manually initiate a restore, run the following command:
+
+<pre class="prettyprint">$ bmgr restore <PACKAGE></pre>
+
+<p>Warning: This action stops your app and wipes its data before performing the
+restore operation.
+
+<p>Then, check logcat to see the output of the restore procedure. For example:
+
+<pre class="prettyprint">V/BackupManagerService: beginRestoreSession: pkg=<PACKAGE> transport=null
+V/RestoreSession: restorePackage pkg=<PACKAGE> token=368abb4465c5c683
+...
+I/BackupManagerService: Restore complete.
+</pre>
+
+<p>You also can test automatic restore for your app by uninstalling and
+reinstalling your app either with <code>adb</code> or through the Google
+Play Store app.
+
+<h2 id="Troubleshooting">Troubleshooting</h2>
+<p><strong>Exceeded Quota</strong>
+
+<p>If you see the the following messages in logcat:
+
+<pre class="prettyprint">I/PFTBT: Transport rejected backup of <PACKAGE>, skipping
+
+--- or ---
+
+I/PFTBT: Transport quota exceeded for package: <PACKAGE>
+</pre>
+
+<p>Your app has exceeded the quota and has been banned from backing up
+data on this device. To lift the ban, either factory reset your device or change
+the backup account.
+
+<p><strong>Full Backup Not Possible</strong>
+
+<p>If you see the the following message in logcat:
+
+<pre class="prettyprint">I/BackupManagerService: Full backup not currently possible -- key/value backup not yet run?
+</pre>
+
+<p>The fullbackup operation failed because no Key/Value Backup operation has yet
+occurred on the device. Trigger a Key/Value Backup with the command <code>bmgr
+run </code>and then try again.
\ No newline at end of file
diff --git a/docs/html/guide/topics/resources/drawable-resource.jd b/docs/html/guide/topics/resources/drawable-resource.jd
index aae0cba..4587ae4 100644
--- a/docs/html/guide/topics/resources/drawable-resource.jd
+++ b/docs/html/guide/topics/resources/drawable-resource.jd
@@ -1270,7 +1270,7 @@
progressively reveal the image:</p>
<pre>
ImageView imageview = (ImageView) findViewById(R.id.image);
-ClipDrawable drawable = (ClipDrawable) imageview.getDrawable();
+ClipDrawable drawable = (ClipDrawable) imageview.getBackground();
drawable.setLevel(drawable.getLevel() + 1000);
</pre>
diff --git a/docs/html/guide/topics/ui/accessibility/services.jd b/docs/html/guide/topics/ui/accessibility/services.jd
index c6db855..dbc69ef 100644
--- a/docs/html/guide/topics/ui/accessibility/services.jd
+++ b/docs/html/guide/topics/ui/accessibility/services.jd
@@ -79,22 +79,15 @@
as shown in the following sample:</p>
<pre>
-<manifest>
- ...
- <uses-permission ... />
- ...
<application>
- ...
<service android:name=".MyAccessibilityService"
- android:label="@string/accessibility_service_label"
- android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
+ android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+ android:label="@string/accessibility_service_label">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
</service>
- <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
</application>
-</manifest>
</pre>
<p>These declarations are required for all accessibility services deployed on Android 1.6 (API Level
diff --git a/docs/html/guide/topics/ui/drag-drop.jd b/docs/html/guide/topics/ui/drag-drop.jd
index 8e4297f..9280818 100644
--- a/docs/html/guide/topics/ui/drag-drop.jd
+++ b/docs/html/guide/topics/ui/drag-drop.jd
@@ -157,19 +157,22 @@
</p>
<p>
Your application tells the system to start a drag by calling the
- {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
+ {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ startDragAndDrop()}
method. This tells the system to start sending drag events. The method also sends the data that
you are dragging.
</p>
<p>
You can call
- {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
+ {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ startDragAndDrop()}
for any attached View in the current layout. The system only uses the View object to get access
to global settings in your layout.
</p>
<p>
Once your application calls
- {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()},
+ {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ startDragAndDrop()},
the rest of the process uses events that the system sends to the View objects in your current
layout.
</p>
@@ -183,11 +186,13 @@
</dt>
<dd>
In response to the user's gesture to begin a drag, your application calls
- {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
- to tell the system to start a drag. The arguments
- {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
- provide the data to be dragged, metadata for this data, and a callback for drawing the
- drag shadow.
+ {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ startDragAndDrop()}
+ to tell the system to start a drag. The
+ {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ startDragAndDrop()}
+ arguments provide the data to be dragged, metadata for this data, and a callback for drawing
+ the drag shadow.
<p>
The system first responds by calling back to your application to get a drag shadow. It
then displays the drag shadow on the device.
@@ -199,12 +204,13 @@
including a possible drop event, a drag event listener must return <code>true</code>.
This registers the listener with the system. Only registered listeners continue to
receive drag events. At this point, listeners can also change the appearance of their
- View object to show that the listener can accept a drop event.
+ View object to show that the listener can accept the dragged data.
</p>
<p>
If the drag event listener returns <code>false</code>, then it will not receive drag
- events for the current operation until the system sends a drag event with action type
- {@link android.view.DragEvent#ACTION_DRAG_ENDED}. By sending <code>false</code>, the
+ events for the current operation, including the drag event with action type
+ {@link android.view.DragEvent#ACTION_DRAG_ENDED} that will conclude the
+ operation. By sending <code>false</code>, the
listener tells the system that it is not interested in the drag operation and
does not want to accept the dragged data.
</p>
@@ -230,7 +236,8 @@
object's listener a drag event with action type
{@link android.view.DragEvent#ACTION_DROP}. The drag event contains the data that was
passed to the system in the call to
- {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}
+ {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ startDragAndDrop()}
that started the operation. The listener is expected to return boolean <code>true</code> to
the system if code for accepting the drop succeeds.
<p>
@@ -297,7 +304,8 @@
<p>
The {@link android.view.DragEvent} object also contains the data that your application provided
to the system in the call to
- {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+ {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ startDragAndDrop()}.
Some of the data is valid only for certain action types. The data that is valid for each action
type is summarized in <a href="#table2">table 2</a>. It is also described in detail with
the event for which it is valid in the section
@@ -316,8 +324,9 @@
<td>
A View object's drag event listener receives this event action type just after the
application calls
-{@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()} and
- gets a drag shadow.
+ {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ startDragAndDrop()}
+ and gets a drag shadow.
<p>
If the listener wants to continue receiving drag events for this operation, it must
return boolean <code>true</code> to the system.
@@ -345,8 +354,7 @@
<td>{@link android.view.DragEvent#ACTION_DRAG_EXITED}</td>
<td>
A View object's drag event listener receives this event action type after it receives a
- {@link android.view.DragEvent#ACTION_DRAG_ENTERED} and at least one
- {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event, and after the user has moved
+ {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event, and after the user has moved
the drag shadow outside the bounding box of the View or into a descendant view that can
accept the data.
</td>
@@ -355,7 +363,8 @@
<td>{@link android.view.DragEvent#ACTION_DROP}</td>
<td>
A View object's drag event listener receives this event action type when the user
- releases the drag shadow over the View object. This action type is only sent to a View
+ releases the drag shadow over the View object and not over its descendant view that can
+ accept the drag data. This action type is only sent to a View
object's listener if the listener returned boolean <code>true</code> in response to the
{@link android.view.DragEvent#ACTION_DRAG_STARTED} drag event. This action type is not
sent if the user releases the drag shadow on a View whose listener is not registered,
@@ -408,8 +417,8 @@
<td>{@link android.view.DragEvent#ACTION_DRAG_ENTERED}</td>
<td style="text-align: center;">X</td>
<td style="text-align: center;">X</td>
- <td style="text-align: center;">X</td>
- <td style="text-align: center;">X</td>
+ <td style="text-align: center;"> </td>
+ <td style="text-align: center;"> </td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"> </td>
</tr>
@@ -442,7 +451,7 @@
</tr>
<tr>
<td>{@link android.view.DragEvent#ACTION_DRAG_ENDED}</td>
- <td style="text-align: center;">X</td>
+ <td style="text-align: center;"> </td>
<td style="text-align: center;">X</td>
<td style="text-align: center;"> </td>
<td style="text-align: center;"> </td>
@@ -472,9 +481,11 @@
The image is called a drag shadow. You create it with methods you declare for a
{@link android.view.View.DragShadowBuilder} object, and then pass it to the system when you
start a drag using
- {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}.
+ {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ startDragAndDrop()}.
As part of its response to
- {@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()},
+ {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ startDragAndDrop()},
the system invokes the callback methods you've defined in
{@link android.view.View.DragShadowBuilder} to obtain a drag shadow.
</p>
@@ -516,7 +527,8 @@
</dt>
<dd>
The system calls this method immediately after you call
-{@link android.view.View#startDrag(ClipData,View.DragShadowBuilder,Object,int) startDrag()}. Use it
+ {@link android.view.View#startDragAndDrop(ClipData,View.DragShadowBuilder,Object,int)
+ startDragAndDrop()}. Use it
to send to the system the dimensions and touch point of the drag shadow. The method has two
arguments:
<dl>
@@ -616,10 +628,10 @@
// Starts the drag
- v.startDrag(dragData, // the data to be dragged
- myShadow, // the drag shadow builder
- null, // no need to use local data
- 0 // flags (not currently used, set to 0)
+ v.startDragAndDrop(dragData, // the data to be dragged
+ myShadow, // the drag shadow builder
+ null, // no need to use local data
+ 0 // flags (not currently used, set to 0)
);
}
@@ -722,8 +734,7 @@
<p>
Note that for an {@link android.view.DragEvent#ACTION_DRAG_STARTED} event, these
the following {@link android.view.DragEvent} methods are not valid:
- {@link android.view.DragEvent#getClipData()}, {@link android.view.DragEvent#getX()},
- {@link android.view.DragEvent#getY()}, and {@link android.view.DragEvent#getResult()}.
+ {@link android.view.DragEvent#getClipData()} and {@link android.view.DragEvent#getResult()}.
</p>
<h3 id="HandleDuring">Handling events during the drag</h3>
<p>
@@ -751,7 +762,9 @@
{@link android.view.DragEvent#ACTION_DRAG_LOCATION}: Once the listener receives an
{@link android.view.DragEvent#ACTION_DRAG_ENTERED} event, and before it receives an
A{@link android.view.DragEvent#ACTION_DRAG_EXITED} event, it receives a new
- {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event every time the touch point moves.
+ {@link android.view.DragEvent#ACTION_DRAG_LOCATION} event immediately after the
+ {@link android.view.DragEvent#ACTION_DRAG_ENTERED} event, and then every time the touch
+ point moves.
The {@link android.view.DragEvent#getX()} and {@link android.view.DragEvent#getY()} methods
return the X and Y coordinates of the touch point.
</li>
@@ -769,9 +782,9 @@
</p>
<ul>
<li>
- In response to {@link android.view.DragEvent#ACTION_DRAG_ENTERED} or
- {@link android.view.DragEvent#ACTION_DRAG_LOCATION}, the listener can change the appearance
- of the View to indicate that it is about to receive a drop.
+ In response to {@link android.view.DragEvent#ACTION_DRAG_ENTERED}, the listener can change
+ the appearance
+ of the View to indicate that it is ready to receive a drop.
</li>
<li>
An event with the action type {@link android.view.DragEvent#ACTION_DRAG_LOCATION} contains
@@ -784,14 +797,14 @@
<li>
In response to {@link android.view.DragEvent#ACTION_DRAG_EXITED}, the listener should reset
any appearance changes it applied in response to
- {@link android.view.DragEvent#ACTION_DRAG_ENTERED} or
- {@link android.view.DragEvent#ACTION_DRAG_LOCATION}. This indicates to the user that
+ {@link android.view.DragEvent#ACTION_DRAG_ENTERED}. This indicates to the user that
the View is no longer an imminent drop target.
</li>
</ul>
<h3 id="HandleDrop">Responding to a drop</h3>
<p>
- When the user releases the drag shadow on a View in the application, and that View previously
+ When the user releases the drag shadow on a View in the application, but not on its descendant
+ view that can accept the data, and that View previously
reported that it could accept the content being dragged, the system dispatches a drag event
to that View with the action type {@link android.view.DragEvent#ACTION_DROP}. The listener
should do the following:
@@ -800,8 +813,8 @@
<li>
Call {@link android.view.DragEvent#getClipData()} to get the
{@link android.content.ClipData} object that was originally supplied in the call
- to
-{@link android.view.View#startDrag(ClipData, View.DragShadowBuilder, Object, int) startDrag()}
+ to {@link android.view.View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)
+ startDragAndDrop()}
and store it. If the drag and drop operation does not represent data movement,
this may not be necessary.
</li>
@@ -856,9 +869,6 @@
including any case in which the system did not send out a
{@link android.view.DragEvent#ACTION_DROP} event.
</li>
- <li>
- The listener should return boolean <code>true</code> to the system.
- </li>
</ol>
<p>
</p>
diff --git a/docs/html/images/cards/distribute/stories/animoca.jpg b/docs/html/images/cards/distribute/stories/animoca.jpg
new file mode 100644
index 0000000..1886bce
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/animoca.jpg
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/drupe.jpg b/docs/html/images/cards/distribute/stories/drupe.jpg
new file mode 100644
index 0000000..5295695
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/drupe.jpg
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/economist-espresso.png b/docs/html/images/cards/distribute/stories/economist-espresso.png
new file mode 100644
index 0000000..923bf57
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/economist-espresso.png
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/expressen-sport.png b/docs/html/images/cards/distribute/stories/expressen-sport.png
new file mode 100644
index 0000000..842ed3d
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/expressen-sport.png
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/glamour.png b/docs/html/images/cards/distribute/stories/glamour.png
new file mode 100644
index 0000000..770b03f
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/glamour.png
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/happylabs-logo.png b/docs/html/images/cards/distribute/stories/happylabs-logo.png
new file mode 100644
index 0000000..ea20e71
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/happylabs-logo.png
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/lifesum.png b/docs/html/images/cards/distribute/stories/lifesum.png
new file mode 100644
index 0000000..3975ff2
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/lifesum.png
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/noom.jpg b/docs/html/images/cards/distribute/stories/noom.jpg
new file mode 100644
index 0000000..dde18a2
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/noom.jpg
Binary files differ
diff --git a/docs/html/images/cards/distribute/stories/playlab.jpg b/docs/html/images/cards/distribute/stories/playlab.jpg
new file mode 100644
index 0000000..3b641e6
--- /dev/null
+++ b/docs/html/images/cards/distribute/stories/playlab.jpg
Binary files differ
diff --git a/docs/html/images/distribute/stories/animoca-flow.jpg b/docs/html/images/distribute/stories/animoca-flow.jpg
new file mode 100644
index 0000000..d2aa2f6
--- /dev/null
+++ b/docs/html/images/distribute/stories/animoca-flow.jpg
Binary files differ
diff --git a/docs/html/images/distribute/stories/animoca-graph.jpg b/docs/html/images/distribute/stories/animoca-graph.jpg
new file mode 100644
index 0000000..c2a42f4
--- /dev/null
+++ b/docs/html/images/distribute/stories/animoca-graph.jpg
Binary files differ
diff --git a/docs/html/images/distribute/stories/animoca-logo.png b/docs/html/images/distribute/stories/animoca-logo.png
new file mode 100644
index 0000000..4b5b6b5
--- /dev/null
+++ b/docs/html/images/distribute/stories/animoca-logo.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/drupe-icon.png b/docs/html/images/distribute/stories/drupe-icon.png
new file mode 100644
index 0000000..1b75cca
--- /dev/null
+++ b/docs/html/images/distribute/stories/drupe-icon.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/drupe-screenshot.png b/docs/html/images/distribute/stories/drupe-screenshot.png
new file mode 100644
index 0000000..6fd4445
--- /dev/null
+++ b/docs/html/images/distribute/stories/drupe-screenshot.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/economist-espresso-icon.png b/docs/html/images/distribute/stories/economist-espresso-icon.png
new file mode 100644
index 0000000..923bf57
--- /dev/null
+++ b/docs/html/images/distribute/stories/economist-espresso-icon.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/expressen-icon.png b/docs/html/images/distribute/stories/expressen-icon.png
new file mode 100644
index 0000000..4547ce7
--- /dev/null
+++ b/docs/html/images/distribute/stories/expressen-icon.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/glamour-icon.png b/docs/html/images/distribute/stories/glamour-icon.png
new file mode 100644
index 0000000..770b03f
--- /dev/null
+++ b/docs/html/images/distribute/stories/glamour-icon.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/happylabs-happy_pet_icon.png b/docs/html/images/distribute/stories/happylabs-happy_pet_icon.png
new file mode 100644
index 0000000..9b24c4a
--- /dev/null
+++ b/docs/html/images/distribute/stories/happylabs-happy_pet_icon.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/happylabs-logo.png b/docs/html/images/distribute/stories/happylabs-logo.png
new file mode 100644
index 0000000..ea20e71
--- /dev/null
+++ b/docs/html/images/distribute/stories/happylabs-logo.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/happylabs-variant.png b/docs/html/images/distribute/stories/happylabs-variant.png
new file mode 100644
index 0000000..3ce5342
--- /dev/null
+++ b/docs/html/images/distribute/stories/happylabs-variant.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/lifesum-icon.png b/docs/html/images/distribute/stories/lifesum-icon.png
new file mode 100644
index 0000000..3975ff2
--- /dev/null
+++ b/docs/html/images/distribute/stories/lifesum-icon.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/noom-icon.png b/docs/html/images/distribute/stories/noom-icon.png
new file mode 100644
index 0000000..a853218
--- /dev/null
+++ b/docs/html/images/distribute/stories/noom-icon.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/noom-screenshot.png b/docs/html/images/distribute/stories/noom-screenshot.png
new file mode 100644
index 0000000..0293eea
--- /dev/null
+++ b/docs/html/images/distribute/stories/noom-screenshot.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/playlab-icon.png b/docs/html/images/distribute/stories/playlab-icon.png
new file mode 100644
index 0000000..af80183
--- /dev/null
+++ b/docs/html/images/distribute/stories/playlab-icon.png
Binary files differ
diff --git a/docs/html/images/distribute/stories/playlab-screenshot.png b/docs/html/images/distribute/stories/playlab-screenshot.png
new file mode 100644
index 0000000..42ffb6a
--- /dev/null
+++ b/docs/html/images/distribute/stories/playlab-screenshot.png
Binary files differ
diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
index f76cf36..1a97db4 100644
--- a/docs/html/jd_extras_en.js
+++ b/docs/html/jd_extras_en.js
@@ -2981,7 +2981,6 @@
"type": "distribute",
"category": "google"
},
-
{
"lang": "en",
"group": "",
@@ -5376,6 +5375,47 @@
"https://storage.googleapis.com/androiddevelopers/shareables/stories/Senri_LeosFortune_gpgs.pdf"
]
},
+ "distribute/stories/games/docs": {
+ "title": "",
+ "resources": [
+ "distribute/stories/games/animoca-star-girl.html",
+ "distribute/stories/games/happy-labs-experiment.html",
+ "distribute/stories/games/playlab-puzzles.html",
+ "distribute/stories/games/upbeat-games.html",
+ "distribute/stories/games/tapps.html",
+ "distribute/stories/games/noodlecake-super-stickman.html",
+ "distribute/stories/games/glu-tap-baseball.html",
+ "distribute/stories/games/doctor-who-legacy.html",
+ "distribute/stories/games/glu-dh.html",
+ "distribute/stories/games/dots.html",
+ "distribute/stories/games/kongregate-adv-cap.html",
+ "distribute/stories/games/kongregate-global-assault.html",
+ "distribute/stories/games/leos-fortune.html",
+ "distribute/stories/games/tiny-co.html",
+ "distribute/stories/games/g4a-indian-rummy.html",
+ "distribute/stories/games/rvappstudios-zombie.html",
+ "distribute/stories/games/glu-eternity-warriors.html",
+ "distribute/stories/games/hotheadgames-firefight.html",
+ "distribute/stories/games/concrete-bowling.html",
+ "distribute/stories/games/gameloft-asphalt8.html"
+ ]
+ },
+ "distribute/stories/apps/docs": {
+ "title": "",
+ "resources": [
+ "distribute/stories/apps/condenast-shopping.html",
+ "distribute/stories/apps/economist-espresso.html",
+ "distribute/stories/apps/expressen-sports.html",
+ "distribute/stories/apps/drupe-communications.html",
+ "distribute/stories/apps/noom-health.html",
+ "distribute/stories/apps/aftenposten.html",
+ "distribute/stories/apps/el-mundo.html",
+ "distribute/stories/apps/segundamano.html",
+ "distribute/stories/apps/remember-the-milk.html",
+ "distribute/stories/apps/intuit-mint.html",
+ "distribute/stories/apps/sayhi.html",
+ ]
+ },
"training/testing/overview": {
"title": "",
"resources": [
diff --git a/docs/html/jd_extras_zh-cn.js b/docs/html/jd_extras_zh-cn.js
index cb1ccb7..866a87e 100644
--- a/docs/html/jd_extras_zh-cn.js
+++ b/docs/html/jd_extras_zh-cn.js
@@ -244,40 +244,40 @@
"overview/zhcn/1": {
"title": "",
"resources": [
- "intl/zh-cn/distribute/essentials/quality/core.html",
- "intl/zh-cn/distribute/essentials/quality/tablets.html",
- "intl/zh-cn/distribute/tools/launch-checklist.html",
- "intl/zh-cn/tools/publishing/publishing_overview.html",
- "intl/zh-cn/distribute/tools/localization-checklist.html"
+ "distribute/essentials/quality/core.html",
+ "distribute/essentials/quality/tablets.html",
+ "distribute/tools/launch-checklist.html",
+ "tools/publishing/publishing_overview.html",
+ "distribute/tools/localization-checklist.html"
]
},
"overview/zhcn/2": {
"title": "",
"resources": [
- "intl/zh-cn/google/play/billing/index.html",
- "intl/zh-cn/google/play/billing/api.html",
- "intl/zh-cn/google/play/billing/billing_admin.html",
- "intl/zh-cn/google/play/billing/billing_testing.html",
- "intl/zh-cn/google/play/billing/billing_best_practices.html"
+ "google/play/billing/index.html",
+ "google/play/billing/api.html",
+ "google/play/billing/billing_admin.html",
+ "google/play/billing/billing_testing.html",
+ "google/play/billing/billing_best_practices.html"
]
},
"overview/zhcn/3": {
"title": "",
"resources": [
"https://play.google.com/intl/en_us/badges/",
- "intl/zh-cn/distribute/tools/promote/device-art.html",
- "intl/zh-cn/distribute/tools/promote/linking.html",
- "intl/zh-cn/distribute/tools/promote/brand.html",
- "intl/zh-cn/tools/help/proguard.html"
+ "distribute/tools/promote/device-art.html",
+ "distribute/tools/promote/linking.html",
+ "distribute/tools/promote/brand.html",
+ "tools/help/proguard.html"
]
},
"overview/zhcn/4": {
"title": "",
"resources": [
- "intl/zh-cn/design/style/writing.html",
- "intl/zh-cn/training/basics/fragments/fragment-ui.html",
- "intl/zh-cn/training/multiscreen/index.html",
- "intl/zh-cn/training/monitoring-device-state/index.html"
+ "design/style/writing.html",
+ "training/basics/fragments/fragment-ui.html",
+ "training/multiscreen/index.html",
+ "training/monitoring-device-state/index.html"
]
},
"overview/carousel/zhcn": {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html
index 9786c92..fcff8ea 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_additions.html
@@ -332,7 +332,7 @@
<!-- Method zBy -->
<nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
(<code>float</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html
index 7055d15..4e923e6 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_all.html
@@ -425,7 +425,7 @@
<!-- Method zBy -->
<nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
(<code>float</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html
index c40c9f5..4002f63 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_changes.html
@@ -114,7 +114,7 @@
<A HREF="android.support.v4.view.ViewParentCompat.html" class="hiddenlink" target="rightframe">ViewParentCompat</A><br>
<!-- Class ViewPropertyAnimatorCompat -->
<A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html" class="hiddenlink" target="rightframe">ViewPropertyAnimatorCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html
index 68d2c20..c6ec566 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/alldiffs_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html
index ae6415e..42084ee 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.Builder.html
@@ -129,7 +129,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html
index 4e476b3..deab0af 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.CustomAction.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
index bd3e5dd..16b5462 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
@@ -144,7 +144,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html
index 1574050..d48ce71 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewCompat.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html
index f03c403..bed9612 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPager.html
@@ -140,7 +140,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html
index 6cdd299..08d2ab2 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewParentCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
index 5706997..1bfa2b3 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
@@ -129,7 +129,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
index e746f08..09b19c2 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
@@ -151,7 +151,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html
index ccce9c5..7b2f8bb 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatActivity.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html
index f53a519..fd75b74 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatCallback.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html
index 88490d4..5df87b9 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDelegate.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html
index 42d29a8..6d992ad 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.app.AppCompatDialog.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html
index 0364519..edfb8bd 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/android.support.v7.util.SortedList.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html
index c6736cd..72ddc5a 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/changes-summary.html
@@ -233,7 +233,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html
index ccd5b66..4537739 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_additions.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html
index 728e37d..50a77aa 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_all.html
@@ -88,7 +88,7 @@
<A HREF="android.support.v4.view.ViewPager.html" class="hiddenlink" target="rightframe">ViewPager</A><br>
<A HREF="android.support.v4.view.ViewParentCompat.html" class="hiddenlink" target="rightframe">ViewParentCompat</A><br>
<A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html" class="hiddenlink" target="rightframe">ViewPropertyAnimatorCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html
index 64e7f44..04fc9bc 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_changes.html
@@ -88,7 +88,7 @@
<A HREF="android.support.v4.view.ViewPager.html" class="hiddenlink" target="rightframe">ViewPager</A><br>
<A HREF="android.support.v4.view.ViewParentCompat.html" class="hiddenlink" target="rightframe">ViewParentCompat</A><br>
<A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html" class="hiddenlink" target="rightframe">ViewPropertyAnimatorCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html
index 792fc4e..8881d7d 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/classes_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html
index 3237ba3..603d376 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_additions.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html
index 637582e..a29ef64 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_all.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html
index 728fa2d..182ad3c 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_changes.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html
index 1b95544..9f9bb438 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/constructors_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html
index 48de992..6b0d997 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_additions.html
@@ -69,7 +69,7 @@
</nobr><br>
<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM" class="hiddenlink" target="rightframe">STATE_SKIPPING_TO_QUEUE_ITEM</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html
index 02f6dc0..726deb6 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_all.html
@@ -69,7 +69,7 @@
</nobr><br>
<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM" class="hiddenlink" target="rightframe">STATE_SKIPPING_TO_QUEUE_ITEM</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html
index 4ebfa31..e4376a5 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_changes.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html
index 09b0726..db6d007 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/fields_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html
index 8bfbd1d..e978be0 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_help.html
@@ -120,7 +120,7 @@
There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass.
In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes.
</BLOCKQUOTE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html
index 229819b..6a96e39 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_statistics.html
@@ -265,7 +265,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html
index 36f9836..6a2e76e 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/jdiff_topleftframe.html
@@ -49,7 +49,7 @@
<TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
</TR>
</TABLE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html
index f7c8488..b7b94ac 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_additions.html
@@ -264,7 +264,7 @@
(<code>float</code>)</A></nobr><br>
<nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
(<code>float</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html
index 63a2848..04d38841 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_all.html
@@ -266,7 +266,7 @@
(<code>float</code>)</A></nobr><br>
<nobr><A HREF="android.support.v4.view.ViewPropertyAnimatorCompat.html#android.support.v4.view.ViewPropertyAnimatorCompat.zBy_added(float)" class="hiddenlink" target="rightframe"><b>zBy</b>
(<code>float</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html
index 3e43f87..3bfd471 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_changes.html
@@ -53,7 +53,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.view.ViewPager.html#android.support.v4.view.ViewPager.setOnPageChangeListener_changed(android.support.v4.view.ViewPager.OnPageChangeListener)" class="hiddenlink" target="rightframe">setOnPageChangeListener
(<code>OnPageChangeListener</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html
index b5aea4f..e85e6fc 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/methods_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html
index 7d92a82..183d500 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_additions.html
@@ -61,7 +61,7 @@
<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><b>android.support.v7.appcompat</b></A><br>
<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><b>android.support.v7.recyclerview</b></A><br>
<A HREF="changes-summary.html#android.support.v7.widget.helper" class="hiddenlink" target="rightframe"><b>android.support.v7.widget.helper</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html
index 2735fe9..0fb83cf 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_all.html
@@ -66,7 +66,7 @@
<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><b>android.support.v7.recyclerview</b></A><br>
<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
<A HREF="changes-summary.html#android.support.v7.widget.helper" class="hiddenlink" target="rightframe"><b>android.support.v7.widget.helper</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html
index 3e40878..917e060 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_changes.html
@@ -55,7 +55,7 @@
<A HREF="pkg_android.support.v4.view.accessibility.html" class="hiddenlink" target="rightframe">android.support.v4.view.accessibility</A><br>
<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html
index d0ffabc..d5a825d 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/packages_index_removals.html
@@ -49,7 +49,7 @@
</div>
<br>
<div id="indexTableEntries">
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html
index 4dfd7de..992f05d 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.media.session.html
@@ -119,7 +119,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html
index f52efcb..86dc841 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.accessibility.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html
index f05d812..ad51e62 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v4.view.html
@@ -126,7 +126,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html
index 44bf61d..508323f 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.app.html
@@ -126,7 +126,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html
index d08d9af..8f74fb7 100644
--- a/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html
+++ b/docs/html/sdk/support_api_diff/22.2.0/changes/pkg_android.support.v7.util.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html
index 3374ffd..a1055f1 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_additions.html
@@ -660,7 +660,7 @@
<!-- Method useStaticShadow -->
<nobr><A HREF="android.support.v17.leanback.widget.ShadowOverlayContainer.html#android.support.v17.leanback.widget.ShadowOverlayContainer.useStaticShadow_added()" class="hiddenlink" target="rightframe"><b>useStaticShadow</b>
()</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html
index bb24c29..48f43d2 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_all.html
@@ -913,7 +913,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html
index 8340749..d5b60c9 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_changes.html
@@ -389,7 +389,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html
index 0d670c0..f2a8797 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/alldiffs_index_removals.html
@@ -83,7 +83,7 @@
<!-- Field Platform_V12_AppCompat_Light -->
<nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Platform_V12_AppCompat_Light" class="hiddenlink" target="rightframe"><strike>Platform_V12_AppCompat_Light</strike></A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
index 78392f4..c45efa2 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html
index 6d68976..a23105a 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.Behavior.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html
index 21b55c0..91a6d77 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.FloatingActionButton.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html
index 028df73..24fdf70 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.Snackbar.html
@@ -130,7 +130,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html
index 2acf995..74a296d 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.Tab.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html
index 22a5ff5..3a8d151 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.design.widget.TabLayout.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html
index 16e5798..7ae6ce1 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsFragment.html
@@ -136,7 +136,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
index 7825292..d1733ac 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
@@ -136,7 +136,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html
index ba8e6af..799db3d 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.DetailsOverviewRowPresenter.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html
index 25f1b48..f8c0cbf 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.ViewHolder.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html
index a88f694..b98c33e 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ItemBridgeAdapter.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html
index 5d71011..f9ad877 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ListRowPresenter.html
@@ -111,7 +111,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html
index eb8a563..f13b147 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.OnChildSelectedListener.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html
index a94d9f5..55f3575 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.ViewHolder.html
@@ -116,7 +116,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html
index fde5e4b..417bf86 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.Presenter.html
@@ -116,7 +116,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html
index 06a0a79..827b2cf 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.PresenterSelector.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html
index 6da5f9b..24b7683 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.RowPresenter.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
index ac3ac3a..9814065 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
@@ -172,7 +172,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
index ab9ce07..c18075e 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
@@ -111,7 +111,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html
index 8519610..d96b874 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompat.Action.html
@@ -131,7 +131,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html
index 498374e..09ae7fc 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.Action.html
@@ -151,7 +151,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html
index 309d7b6..9824574 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v4.app.NotificationCompatBase.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html
index 229289c..541f134 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.attr.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html
index a253e59..584073e 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.dimen.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html
index 4f87127..45a1dc7 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.drawable.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html
index e856c8b..cecd912 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.id.html
@@ -192,7 +192,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html
index 70585a7..4b90739 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.integer.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html
index 8130707..c0a1304 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.layout.html
@@ -157,7 +157,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html
index 6a01b20..39be2b2 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.string.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html
index 886f2ce..ffc3690 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.style.html
@@ -186,7 +186,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html
index cd9cd60..713526b 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.appcompat.R.styleable.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html
index b38c632..181a0fc 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/android.support.v7.util.SortedList.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html b/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html
index e05b67d..b500246 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/changes-summary.html
@@ -177,7 +177,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html
index 52b4ab7..f2fe6ec 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_additions.html
@@ -103,7 +103,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="pkg_android.support.v17.leanback.widget.html#OnChildViewHolderSelectedListener" class="hiddenlink" target="rightframe"><b>OnChildViewHolderSelectedListener</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html
index 1edab7a..16ebdfa 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_all.html
@@ -339,7 +339,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html
index f46bc67..8072f0f 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_changes.html
@@ -259,7 +259,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html
index 09c0d19..757f5bb 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/classes_index_removals.html
@@ -63,7 +63,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="pkg_android.support.v17.leanback.widget.html#GridLayoutManager" class="hiddenlink" target="rightframe"><strike>GridLayoutManager</strike></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html
index e694216..3bced29 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_additions.html
@@ -53,7 +53,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.app.NotificationCompatBase.html#android.support.v4.app.NotificationCompatBase.ctor_added()" class="hiddenlink" target="rightframe"><b>NotificationCompatBase</b>
()</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html
index 27d7557..7769d75 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_all.html
@@ -53,7 +53,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.app.NotificationCompatBase.html#android.support.v4.app.NotificationCompatBase.ctor_added()" class="hiddenlink" target="rightframe"><b>NotificationCompatBase</b>
()</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html
index a5ca2ef..122cdce 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_changes.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html
index 74a09ba..dadd1cd 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/constructors_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html
index 2ae5237..5d6411a 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_additions.html
@@ -263,7 +263,7 @@
</nobr><br>
<nobr><A HREF="android.support.v7.appcompat.R.id.html#android.support.v7.appcompat.R.id.time" class="hiddenlink" target="rightframe">time</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html
index 4a9194d..85420c3 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_all.html
@@ -291,7 +291,7 @@
</nobr><br>
<nobr><A HREF="android.support.v7.appcompat.R.id.html#android.support.v7.appcompat.R.id.time" class="hiddenlink" target="rightframe">time</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html
index 0e2ccff..301881a 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_changes.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html
index 6245b05..b1bf691 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/fields_index_removals.html
@@ -55,7 +55,7 @@
</nobr><br>
<nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Platform_V12_AppCompat_Light" class="hiddenlink" target="rightframe"><strike>Platform_V12_AppCompat_Light</strike></A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html
index 25acfbe..f9c1f08 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_help.html
@@ -120,7 +120,7 @@
There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass.
In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes.
</BLOCKQUOTE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html
index 0f4805f..322ad44 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_statistics.html
@@ -368,7 +368,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html
index 36f9836..6a2e76e 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/jdiff_topleftframe.html
@@ -49,7 +49,7 @@
<TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
</TR>
</TABLE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html
index 33a155f..5a237de 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_additions.html
@@ -224,7 +224,7 @@
</A></nobr><br>
<nobr><A HREF="android.support.v17.leanback.widget.ShadowOverlayContainer.html#android.support.v17.leanback.widget.ShadowOverlayContainer.useStaticShadow_added()" class="hiddenlink" target="rightframe"><b>useStaticShadow</b>
()</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html
index b9cf858..014ef9a 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_all.html
@@ -256,7 +256,7 @@
</A></nobr><br>
<nobr><A HREF="android.support.v17.leanback.widget.ShadowOverlayContainer.html#android.support.v17.leanback.widget.ShadowOverlayContainer.useStaticShadow_added()" class="hiddenlink" target="rightframe"><b>useStaticShadow</b>
()</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html
index 4e2d329..6b02e2a 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_changes.html
@@ -89,7 +89,7 @@
<nobr><A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html#android.support.v17.leanback.widget.VerticalGridPresenter.isUsingZOrder_changed(android.content.Context)" class="hiddenlink" target="rightframe">type
(<code>Context</code>) in android.support.v17.leanback.widget.VerticalGridPresenter
</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html
index b5aea4f..e85e6fc 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/methods_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html
index 6311752..d08c85c 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_additions.html
@@ -51,7 +51,7 @@
<div id="indexTableEntries">
<A NAME="A"></A>
<A HREF="changes-summary.html#android.support.v17.leanback.system" class="hiddenlink" target="rightframe"><b>android.support.v17.leanback.system</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html
index 3f5ee13..712eac9 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_all.html
@@ -58,7 +58,7 @@
<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
<A HREF="pkg_android.support.v7.appcompat.html" class="hiddenlink" target="rightframe">android.support.v7.appcompat</A><br>
<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html
index a4637a7..e53ee87 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_changes.html
@@ -57,7 +57,7 @@
<A HREF="pkg_android.support.v7.app.html" class="hiddenlink" target="rightframe">android.support.v7.app</A><br>
<A HREF="pkg_android.support.v7.appcompat.html" class="hiddenlink" target="rightframe">android.support.v7.appcompat</A><br>
<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html
index d0ffabc..d5a825d 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/packages_index_removals.html
@@ -49,7 +49,7 @@
</div>
<br>
<div id="indexTableEntries">
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html
index 345f33b..25070ce 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.design.widget.html
@@ -140,7 +140,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html
index 873bc6b..48f868b 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.app.html
@@ -112,7 +112,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html
index 7197d3a..ac3d8435 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v17.leanback.widget.html
@@ -324,7 +324,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html
index 1d15399..3122461 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v4.app.html
@@ -119,7 +119,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html
index 47c0894..5f69310 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.app.html
@@ -119,7 +119,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html
index 4c562aec..00bcf19 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.appcompat.html
@@ -161,7 +161,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html
index bac0313..e0f4bcd 100644
--- a/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html
+++ b/docs/html/sdk/support_api_diff/22.2.1/changes/pkg_android.support.v7.util.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html
index 5495f89..1717f7d 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_additions.html
@@ -1104,7 +1104,7 @@
<!-- Field Widget_AppCompat_SeekBar -->
<nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html
index 575ee95..d4c30e3 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_all.html
@@ -1511,7 +1511,7 @@
<!-- Field Widget_AppCompat_SeekBar -->
<nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html
index d7ebd36..6562fa8 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_changes.html
@@ -548,7 +548,7 @@
<A HREF="android.support.v17.leanback.app.VerticalGridSupportFragment.html" class="hiddenlink" target="rightframe">VerticalGridSupportFragment</A><br>
<!-- Class ViewCompat -->
<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html
index 0d7da0f..9b21b1d 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/alldiffs_index_removals.html
@@ -270,7 +270,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v17.leanback.app.GuidedStepFragment.html#android.support.v17.leanback.app.GuidedStepFragment.setEntryTransitionEnabled_removed(boolean)" class="hiddenlink" target="rightframe"><strike>setEntryTransitionEnabled</strike>
(<code>boolean</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html
index 0466d5d..6ba5f831 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsCallback.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
index e3aefb5..c53722b 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html
index 9312755..db59258 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsIntent.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html
index 2a0fd18..fd5a12b 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsService.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html
index 6b70224..6910bab 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSession.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html
index 2bdb42e..0282d49 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.customtabs.CustomTabsSessionToken.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html
index bb89bbd..cea16c0 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.SavedState.html
@@ -123,7 +123,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html
index b538999a..672951d 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.Behavior.html
@@ -131,7 +131,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html
index 6d19d36..0218c30 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.LayoutParams.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
index c089db3..424a618 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
@@ -124,7 +124,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
index 49d92737..8e708c0 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
@@ -143,7 +143,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html
index f92babd..496a460 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.CoordinatorLayout.SavedState.html
@@ -123,7 +123,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
index 07fdda1..eba4247 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html
index 90553fa..520fdcf 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.FloatingActionButton.html
@@ -116,7 +116,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html
index 8a9ae80..61428ca 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.NavigationView.SavedState.html
@@ -123,7 +123,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html
index d741863..f33e47a 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.Snackbar.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html
index 30d0dd6..609e864 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.design.widget.TextInputLayout.html
@@ -129,7 +129,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
index b6f2e48..967542f 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html
index 30f22a8..6b6151b 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v14.preference.EditTextPreferenceDialogFragment.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html
index f4d77bf..14f6fdfa 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseFragment.html
@@ -150,7 +150,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
index a48ea3b..7adcbe8 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
@@ -150,7 +150,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html
index d38127c..2240f4e 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsFragment.html
@@ -143,7 +143,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
index a02b8f3..23ca151 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
@@ -143,7 +143,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
index 725281a..4c78b30 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
@@ -215,7 +215,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html
index 71e230b..ecb35bef 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlayFragment.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html
index a794f14..1809374 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.PlaybackOverlaySupportFragment.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html
index 827f46b..2c444ae 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchFragment.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html
index f1e2826..7ff0204 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.SearchSupportFragment.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html
index 01bb4de..5516bda 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridFragment.html
@@ -137,7 +137,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html
index a818a79..0f09ec0 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.app.VerticalGridSupportFragment.html
@@ -154,7 +154,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html
index 1cf004d..e457402 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.FragmentAnimationProvider.html
@@ -165,7 +165,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
index e0b94bc..9794929 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
@@ -165,7 +165,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
index 96d30a4..3408bd9 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html
index 84b93bf..857b7d8 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedAction.html
@@ -143,7 +143,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
index 38e83b4..497e985 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
index 104f325..cd45d6d 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
@@ -165,7 +165,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html
index 1535ca0..a5aa07e 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ImageCardView.html
@@ -151,7 +151,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html
index f536d92..11b95c40 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ListRowPresenter.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html
index 3f10b29..0f254d7 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.RowPresenter.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html
index 2965c15..6e4b41c 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.SearchBar.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
index 761fd92..553bbb1 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.ShadowOverlayContainer.html
@@ -127,7 +127,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
index e999838..f1d6fb6 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v17.leanback.widget.VerticalGridPresenter.html
@@ -129,7 +129,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html
index c68356c..dd88aca 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.app.FragmentActivity.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html
index 9bdd4f7..bb339da 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.content.res.ResourcesCompat.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html
index 5b5f1e3..278f42d 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.media.session.MediaSessionCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html
index 2e39745..03dda58 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.view.ViewCompat.html
@@ -179,7 +179,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html
index 8d4cbaa..cdb3d13 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.NestedScrollView.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html
index 7f47eae..9ef847e 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.ScrollerCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html
index 3641625..87b1da2 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v4.widget.TextViewCompat.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html
index dc6fce2..ef31519 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.attr.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html
index 973cf83..c26367a 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.bool.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html
index ca5fec2..bd324cb 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.dimen.html
@@ -186,7 +186,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html
index 3cfba65..c9264d6 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.drawable.html
@@ -157,7 +157,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html
index a25139d..e7f9f95 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.id.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html
index 0b485ea..c04d4f7 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.layout.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html
index b5b32c7..9dc84ab 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.string.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html
index a7b4e2d..58f9025 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.style.html
@@ -158,7 +158,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html
index 3f6d157..49adae8 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.appcompat.R.styleable.html
@@ -150,7 +150,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html
index 03171fb..22ee483 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.Palette.Builder.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html
index ec3cb15..77232ba 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.graphics.drawable.DrawerArrowDrawable.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
index aec06c0..5cac372 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
@@ -154,7 +154,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html
index 381eb20..437c56d 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouteDescriptor.html
@@ -147,7 +147,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html
index 239341d..51afa4f 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.media.MediaRouter.RouteInfo.html
@@ -166,7 +166,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html
index 05b65ff..ac63d53 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/android.support.v7.preference.EditTextPreferenceDialogFragmentCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html
index 728ade1..d9658ba 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/changes-summary.html
@@ -232,7 +232,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html
index c0022c9..1a97c98 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_additions.html
@@ -197,7 +197,7 @@
<A HREF="pkg_android.support.v17.leanback.widget.html#ShadowOverlayHelper" class="hiddenlink" target="rightframe"><b>ShadowOverlayHelper</b></A><br>
<A HREF="pkg_android.support.v17.leanback.widget.html#ShadowOverlayHelper.Builder" class="hiddenlink" target="rightframe"><b>ShadowOverlayHelper.Builder</b></A><br>
<A HREF="pkg_android.support.v17.leanback.widget.html#ShadowOverlayHelper.Options" class="hiddenlink" target="rightframe"><b>ShadowOverlayHelper.Options</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html
index 05f83b8..c8f86f4 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_all.html
@@ -471,7 +471,7 @@
<A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
<A HREF="android.support.v17.leanback.app.VerticalGridSupportFragment.html" class="hiddenlink" target="rightframe">VerticalGridSupportFragment</A><br>
<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html
index b1ee972..f280906 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_changes.html
@@ -415,7 +415,7 @@
<A HREF="android.support.v17.leanback.widget.VerticalGridPresenter.html" class="hiddenlink" target="rightframe">VerticalGridPresenter</A><br>
<A HREF="android.support.v17.leanback.app.VerticalGridSupportFragment.html" class="hiddenlink" target="rightframe">VerticalGridSupportFragment</A><br>
<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html
index e6da73f..c466298 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/classes_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html
index 3bf8178..45f72f1 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_additions.html
@@ -97,7 +97,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.design.widget.NavigationView.SavedState.html#android.support.design.widget.NavigationView.SavedState.ctor_added(android.os.Parcel, java.lang.ClassLoader)" class="hiddenlink" target="rightframe"><b>NavigationView.SavedState</b>
(<code>Parcel, ClassLoader</code>)</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html
index 546eae8..8dda68f 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_all.html
@@ -106,7 +106,7 @@
(<code>Parcel</code>)</A></nobr> constructor<br>
<nobr><A HREF="android.support.design.widget.NavigationView.SavedState.html#android.support.design.widget.NavigationView.SavedState.ctor_added(android.os.Parcel, java.lang.ClassLoader)" class="hiddenlink" target="rightframe"><b>NavigationView.SavedState</b>
(<code>Parcel, ClassLoader</code>)</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html
index 52c8b49..d6584d1 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_changes.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html
index 337274d..49ee23c 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/constructors_index_removals.html
@@ -71,7 +71,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.design.widget.NavigationView.SavedState.html#android.support.design.widget.NavigationView.SavedState.ctor_removed(android.os.Parcel)" class="hiddenlink" target="rightframe"><strike>NavigationView.SavedState</strike>
(<code>Parcel</code>)</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html
index d1ef3ac..0c43320 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_additions.html
@@ -329,7 +329,7 @@
</nobr><br>
<nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html
index 697f16a..71d9b71 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_all.html
@@ -339,7 +339,7 @@
</nobr><br>
<nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_SeekBar" class="hiddenlink" target="rightframe">Widget_AppCompat_SeekBar</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html
index 0e2ccff..301881a 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_changes.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html
index 93bcdc3..f520de6 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/fields_index_removals.html
@@ -67,7 +67,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.RtlOverlay_Widget_AppCompat_ActionButton_Overflow" class="hiddenlink" target="rightframe"><strike>RtlOverlay_Widget_AppCompat_ActionButton_Overflow</strike></A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html
index b03b763..0ba76e7 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_help.html
@@ -120,7 +120,7 @@
There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass.
In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes.
</BLOCKQUOTE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html
index bdda25f..ac4d43e 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_statistics.html
@@ -568,7 +568,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html
index 36f9836..6a2e76e 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/jdiff_topleftframe.html
@@ -49,7 +49,7 @@
<TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
</TR>
</TABLE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html
index 9b4eab3..fee36df 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_additions.html
@@ -516,7 +516,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.customtabs.CustomTabsService.html#android.support.customtabs.CustomTabsService.updateVisuals_added(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle)" class="hiddenlink" target="rightframe"><b>updateVisuals</b>
(<code>CustomTabsSessionToken, Bundle</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html
index d63656c..7a2fe5c 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_all.html
@@ -616,7 +616,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.customtabs.CustomTabsService.html#android.support.customtabs.CustomTabsService.updateVisuals_added(android.support.customtabs.CustomTabsSessionToken, android.os.Bundle)" class="hiddenlink" target="rightframe"><b>updateVisuals</b>
(<code>CustomTabsSessionToken, Bundle</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html
index 8271b35..254a721 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_changes.html
@@ -77,7 +77,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v7.media.MediaRouteDescriptor.Builder.html#android.support.v7.media.MediaRouteDescriptor.Builder.setConnecting_changed(boolean)" class="hiddenlink" target="rightframe">setConnecting
(<code>boolean</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html
index 7250505..0b6f2b4 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/methods_index_removals.html
@@ -158,7 +158,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v17.leanback.app.GuidedStepFragment.html#android.support.v17.leanback.app.GuidedStepFragment.setEntryTransitionEnabled_removed(boolean)" class="hiddenlink" target="rightframe"><strike>setEntryTransitionEnabled</strike>
(<code>boolean</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html
index 1776064..e7ed63e 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_additions.html
@@ -49,7 +49,7 @@
</div>
<br>
<div id="indexTableEntries">
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html
index 2bf0974..4236847 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_all.html
@@ -67,7 +67,7 @@
<A HREF="pkg_android.support.v7.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v7.graphics.drawable</A><br>
<A HREF="pkg_android.support.v7.media.html" class="hiddenlink" target="rightframe">android.support.v7.media</A><br>
<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html
index 519e9aa..8d51ea2 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_changes.html
@@ -67,7 +67,7 @@
<A HREF="pkg_android.support.v7.graphics.drawable.html" class="hiddenlink" target="rightframe">android.support.v7.graphics.drawable</A><br>
<A HREF="pkg_android.support.v7.media.html" class="hiddenlink" target="rightframe">android.support.v7.media</A><br>
<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html
index 9fd0f7e..ae935f4 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/packages_index_removals.html
@@ -49,7 +49,7 @@
</div>
<br>
<div id="indexTableEntries">
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html
index d85f3f8..ea62004 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.customtabs.html
@@ -140,7 +140,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html
index 449afa6..45625b9 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.design.widget.html
@@ -211,7 +211,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html
index 53b92a9..13b9732 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.percent.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html
index 3ef0a0f..7364b7c 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v14.preference.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html
index 49ee52f..21763fb 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.app.html
@@ -211,7 +211,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html
index 73d5050..ff00794 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v17.leanback.widget.html
@@ -239,7 +239,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html
index b1645a6..ccdb5fe 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.app.html
@@ -120,7 +120,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html
index efc62c9..b1b6ffc 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html
index fd9c9f8..f6a1367 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.content.res.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html
index afd23b1..1182648 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.media.session.html
@@ -120,7 +120,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html
index 7d74c82..b4fe9b2 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.view.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html
index 4ca7874..e32ebc81 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v4.widget.html
@@ -134,7 +134,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html
index 553bdf2..b516a35 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.appcompat.html
@@ -161,7 +161,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html
index e9d5cd9..69c91d5 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.drawable.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html
index ba9a092..13d6ef9 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.graphics.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html
index 7892bf9..4c2094c 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.media.html
@@ -134,7 +134,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html
index ced3a90..ed590bb 100644
--- a/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html
+++ b/docs/html/sdk/support_api_diff/23.1.0/changes/pkg_android.support.v7.preference.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html
index 09ec1eb..3b43f27 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_additions.html
@@ -1955,7 +1955,7 @@
<!-- Method XYZToLAB -->
<nobr><A HREF="android.support.v4.graphics.ColorUtils.html#android.support.v4.graphics.ColorUtils.XYZToLAB_added(double, double, double, double[])" class="hiddenlink" target="rightframe"><b>XYZToLAB</b>
(<code>double, double, double, double[]</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html
index 770d615..6264757 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_all.html
@@ -2914,7 +2914,7 @@
<!-- Method XYZToLAB -->
<nobr><A HREF="android.support.v4.graphics.ColorUtils.html#android.support.v4.graphics.ColorUtils.XYZToLAB_added(double, double, double, double[])" class="hiddenlink" target="rightframe"><b>XYZToLAB</b>
(<code>double, double, double, double[]</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html
index 134580d..6113a9e 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_changes.html
@@ -939,7 +939,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="android.support.v4.view.WindowCompat.html" class="hiddenlink" target="rightframe">WindowCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html
index a60b244..2df39dc 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/alldiffs_index_removals.html
@@ -956,7 +956,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.view.WindowCompat.html#android.support.v4.view.WindowCompat.ctor_removed()" class="hiddenlink" target="rightframe"><strike>WindowCompat</strike>
()</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
index 46a0548..3e97afd 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html
index 7987724..d7745e6 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsIntent.html
@@ -151,7 +151,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html
index 1296d4c..9b48018 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.customtabs.CustomTabsSession.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
index d539481..80c8e11 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
@@ -136,7 +136,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
index e47f317..e1ae295 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
@@ -164,7 +164,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
index 04efe89..ee87ca60 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
@@ -121,7 +121,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html
index 985adba..33d67e2 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.FloatingActionButton.html
@@ -144,7 +144,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html
index 7021ba2..0e24356 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.HeaderScrollingViewBehavior.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html
index 9224ddb..3d0eb9f 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TabLayout.html
@@ -111,7 +111,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html
index b0f5d63..d72b373 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.TextInputLayout.html
@@ -129,7 +129,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html
index 1b4625f..9faa826 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.design.widget.ViewOffsetBehavior.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
index c13de02..13c0b4e 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.percent.PercentLayoutHelper.PercentLayoutInfo.html
@@ -130,7 +130,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html
index 3a910d0..7ead465 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v14.preference.PreferenceFragment.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html
index 003f04b..9bd2bd7 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowFragment.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html
index 6a30cc3..cf9900c 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BaseRowSupportFragment.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html
index 74cb151..d7d0e76 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseFragment.html
@@ -129,7 +129,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
index a46a8ed..d7bb8c9 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.BrowseSupportFragment.html
@@ -129,7 +129,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html
index 34875c3..852b28a6 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsFragment.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
index 4cd41ed..444a537 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.DetailsSupportFragment.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
index 0962be7..1cfc19e 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepFragment.html
@@ -330,7 +330,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html
index b464afa..c5f0d5a 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.GuidedStepSupportFragment.html
@@ -330,7 +330,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html
index 0df02c4..800f32b 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderClickedListener.html
@@ -112,7 +112,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html
index cc2eeda..70ec556 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersFragment.OnHeaderViewSelectedListener.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html
index 0c59abd..ee37373 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderClickedListener.html
@@ -112,7 +112,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html
index ee27726..99e380d 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.HeadersSupportFragment.OnHeaderViewSelectedListener.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html
index 612c05a..7c78322 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsFragment.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html
index 7cbdf0c..a112b19 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.app.RowsSupportFragment.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html
index 674231e..ef74a40 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.ViewHolder.html
@@ -129,7 +129,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html
index 74e170c..05a2205 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.DetailsOverviewLogoPresenter.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
index 0a20eb4..f67942e 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidanceStylist.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
index b77684b..4d1d86b 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.Builder.html
@@ -281,7 +281,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html
index 20165c7..2ce2773 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedAction.html
@@ -307,7 +307,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
index 0849383..b9b78cb 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.ViewHolder.html
@@ -195,7 +195,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
index a8dff6f..fbe6bb4 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.GuidedActionsStylist.html
@@ -306,7 +306,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html
index f110a16..dde52dd 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ImageCardView.html
@@ -111,7 +111,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html
index 2207a6d..9aadb33 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v17.leanback.widget.ListRowPresenter.ViewHolder.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
index 2479a86..4545dc6 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html
index 15ddb44..8d4b281 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.AppOpsManagerCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html
index 63ecf79e..65cb6ce 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.BundleCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html
index d6c9e88..adb8e8a 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.Fragment.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html
index 72bd4de..843cf68 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentActivity.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html
index fcb311f..ca9cab8 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.FragmentHostCallback.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html
index e4fb7fa..7267e50 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NavUtils.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html
index be48aac..06346b2 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.NotificationManagerCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html
index a6a2a2d..006eeee 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.RemoteInput.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html
index c038e52..613affe 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ServiceCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html
index 8e9c945..90c0630 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.ShareCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html
index 8a8a3c7..12d44de 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.app.TaskStackBuilder.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html
index 6abd31a..37ab80d 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContentResolverCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html
index c0abad2..92f9469 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ContextCompat.html
@@ -111,7 +111,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html
index 707b2de..37a8b42 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.IntentCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html
index fb0f8eb..a3d8f89 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.LocalBroadcastManager.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html
index 135c65a..3dd3598 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.ParallelExecutorCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html
index 2a46cc87..5159fec 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.EditorCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html
index 99e7e84..3c4513a 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.SharedPreferencesCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html
index 201f6e2..1fa3936 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.pm.ActivityInfoCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html
index 497d73b..77e6d43 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.content.res.ResourcesCompat.html
@@ -137,7 +137,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html
index 0feb04b..90a5d72 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.database.DatabaseUtilsCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html
index 3b50f8e..912d5ee 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.BitmapCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html
index 68c2dce..1dfcdc5 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.ColorUtils.html
@@ -186,7 +186,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
index 735909e..041cbfd 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
@@ -152,7 +152,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html
index f0e4cbf..2323bf0 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html
index 3c5e74d..8a49a32 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.hardware.fingerprint.FingerprintManagerCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html
index 585fbe1..45e77fa 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.ConnectivityManagerCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html
index d8d8d74..89403e7 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.net.TrafficStatsCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html
index 0ea4b47..fcde361 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.AsyncTaskCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html
index 4d625b1..914f3f0 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.EnvironmentCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html
index 0192ed6..8933edd 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.ParcelableCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html
index 3f490ba..8778c2e4 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.os.TraceCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html
index 2b97440..c4ea966 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.ICUCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html
index 45557e1..351a162 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextDirectionHeuristicsCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html
index 16d0835..d3ab7ce 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.text.TextUtilsCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html
index 5c0463d..e66c261 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GestureDetectorCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html
index 9ee14c5..95c665e 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.GravityCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html
index 4a7f385..38a1cd8 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.InputDeviceCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html
index 49526ab..58692a9 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.KeyEventCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html
index 7329ff7..b62e876 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.LayoutInflaterCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html
index 86a7b57..444980d 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MarginLayoutParamsCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html
index 22ead5ec..17b8b7d 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html
index a321ac3..415dae2 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MenuItemCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html
index cb8895d..c1f81ba 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.MotionEventCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html
index 23f8718..8733e6b 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ScaleGestureDetectorCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html
index 31a2b66..078bb96 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.VelocityTrackerCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html
index bbfebc1..0647acb 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
index 3deb282..0721e0c 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html
index 973f25d..7c3f280 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewGroupCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html
index 0ff6977..186cdce 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewParentCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
index dcb75fc..7611f00 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.ViewPropertyAnimatorCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html
index a9711fa..bf16942a 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.WindowCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
index e2045d7..b9b15c8 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
index d74f936..5180523 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html
index 6701f77..715f73f 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.view.animation.PathInterpolatorCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html
index c2e7c83..f859501 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.DrawerLayout.html
@@ -148,7 +148,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html
index 6993bec..a476dfb 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.EdgeEffectCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html
index fc5ed8d..243f6d2 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ListPopupWindowCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html
index 1d55628..c3cca70 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupMenuCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html
index 215118c..0523e9f 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.PopupWindowCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html
index ea76c92..f13086d 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.ScrollerCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html
index ce5abd3..e3de11d 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.SearchViewCompat.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html
index e2078f4..e3a0f9a 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v4.widget.TextViewCompat.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html
index 6fd286c..2dbee43 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.app.AppCompatDelegate.html
@@ -172,7 +172,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html
index c399a8a..2a2364a 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.attr.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html
index ec1ee38..a2e1dc3 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.drawable.html
@@ -347,7 +347,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html
index 478d333..32befe4 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.style.html
@@ -178,7 +178,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html
index 498ec51..6433bc2 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.appcompat.R.styleable.html
@@ -1705,7 +1705,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html
index 83f441b..2758189 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.Builder.html
@@ -140,7 +140,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html
index be157a7..d7752f5 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.graphics.Palette.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
index 7db6666..9181648 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.Builder.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html
index 315ba3d..0cb71cf 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouteDescriptor.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html
index 66be68d..5d68006 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.media.MediaRouter.Callback.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html
index 68aa733..980ff0d 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceFragmentCompat.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html
index 12de78c..de14ee0 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceScreen.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html
index b27e66c..0597c2a 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.preference.PreferenceViewHolder.html
@@ -129,7 +129,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html
index b38c6dc..a56e112 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.recyclerview.R.dimen.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html
index 6a2a9b3..9111877 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.OrientationHelper.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html
index 95e642e..a641975 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.ItemAnimator.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html
index 30b0a78..173d636 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.LayoutManager.html
@@ -193,7 +193,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html
index 2b3ac61..86d91dc 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.State.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html
index 5cdc7a0..a53430b 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.RecyclerView.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html
index 1237408..b241e6e 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/android.support.v7.widget.helper.ItemTouchHelper.Callback.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html
index d41ec1f..431b2ae 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/changes-summary.html
@@ -352,7 +352,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html
index a2e1d44..eb0457c 100644
--- a/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23.2.0/changes/classes_index_additions.html
@@ -143,7 +143,7 @@
<p><div style="line-height:1.5em;color:black">
<A HREF="pkg_android.support.v17.leanback.widget.html#ViewHolderTask" class="hiddenlink" target="rightframe"><b><i>ViewHolderTask</i></b></A><br>
<A HREF="pkg_android.support.design.widget.html#VisibilityAwareImageButton" class="hiddenlink" target="rightframe"><b>VisibilityAwareImageButton</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html
index 78c94e1..c526b45 100644
--- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_additions.html
@@ -1128,7 +1128,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html
index f39d82e..61459ad 100644
--- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html
+++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_all.html
@@ -1457,7 +1457,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html
index debbb14..0a63a58 100644
--- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_changes.html
@@ -485,7 +485,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html
index a6cdb59..9f13a01 100644
--- a/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23/changes/alldiffs_index_removals.html
@@ -332,7 +332,7 @@
<!-- Field View_backgroundTintMode -->
<nobr><A HREF="android.support.v7.appcompat.R.styleable.html#android.support.v7.appcompat.R.styleable.View_backgroundTintMode" class="hiddenlink" target="rightframe"><strike>View_backgroundTintMode</strike></A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html
index a6bbf2d..352dcfd 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.Behavior.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html
index 71e3167..cd2a11f 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.AppBarLayout.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html
index 7244be9..d80f7ee 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.CollapsingToolbarLayout.html
@@ -150,7 +150,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html
index a38990a..5dd3104 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.NavigationView.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html
index 9a53448..2247297 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.Snackbar.html
@@ -116,7 +116,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html
index b7a01f5..a0ea052 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.Tab.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html
index df626ac..bd3c8e6 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TabLayout.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html
index 471e267..a9a7b49 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.design.widget.TextInputLayout.html
@@ -165,7 +165,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html
index 9eb5b24..b61fb5a 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v13.app.FragmentCompat.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html
index 3c6165f..f189083 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.ViewHolder.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html
index b6d8863..cb2156a 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html
@@ -179,7 +179,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html
index 092a6c3..5d5a9fc 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.animation.AnimatorCompatHelper.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html
index 76e8ce9..c318b70 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.ActivityCompat.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html
index 53a8bd5..2f56f59 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.Fragment.html
@@ -190,7 +190,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html
index 8d2321f..0338069 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.app.FragmentActivity.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html
index 19be27c..5dfbe6c 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.AsyncTaskLoader.html
@@ -133,7 +133,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html
index 6ed5b3e..64d09ac 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.ContextCompat.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html
index d4c3bb0..f97def1 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.content.Loader.html
@@ -136,7 +136,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html
index 87fefee..ca42f3d 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.DrawableCompat.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html
index 7c72cf4..793bd8b 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.graphics.drawable.RoundedBitmapDrawable.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html
index c429c39..6ae7186 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.Builder.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html
index 4053435..dde12a5 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.MediaDescriptionCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html
index 4d10769..12743cd 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaControllerCompat.TransportControls.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html
index a0bbbf6..4acf244 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.MediaSessionCompat.Callback.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html
index 29e5f0b..0f568c4 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.media.session.PlaybackStateCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html
index 5f9f31e..e357c50 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.text.ICUCompat.html
@@ -130,7 +130,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html
index 548502c..caaf19a 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.ViewCompat.html
@@ -122,7 +122,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
index ce98f64..c60e7e1 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
@@ -255,7 +255,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
index f3ef666..6f2e809 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
@@ -361,7 +361,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html
index 3297157..c18ae6c 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.DrawerLayout.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html
index 4026cd2..be8512f 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.ExploreByTouchHelper.html
@@ -123,7 +123,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html
index 8a9b9c6..284dab4 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.PopupWindowCompat.html
@@ -129,7 +129,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html
index 91a99cb..1fb912f 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v4.widget.SwipeRefreshLayout.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html
index 42ef289..9f768b9 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.app.AppCompatDelegate.html
@@ -137,7 +137,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html
index cc28516..98d2c2c 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.attr.html
@@ -221,7 +221,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html
index 5f1a3f6..852d595 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.color.html
@@ -193,7 +193,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html
index c4fba92..893ea25 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.dimen.html
@@ -158,7 +158,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html
index 0bf5ce1..482e9ff 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.drawable.html
@@ -144,7 +144,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html
index 2b34b3a..818a5b0 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.id.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html
index 9d24903..a0a33fb 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.layout.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html
index 8b16f1c..d084de0 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.style.html
@@ -207,7 +207,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html
index 5365376..c021cbe 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.appcompat.R.styleable.html
@@ -333,7 +333,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html
index 3893441..e707730 100644
--- a/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html
+++ b/docs/html/sdk/support_api_diff/23/changes/android.support.v7.graphics.Palette.Builder.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/changes-summary.html b/docs/html/sdk/support_api_diff/23/changes/changes-summary.html
index 3deee46e..75c1eb3 100644
--- a/docs/html/sdk/support_api_diff/23/changes/changes-summary.html
+++ b/docs/html/sdk/support_api_diff/23/changes/changes-summary.html
@@ -310,7 +310,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html
index 094fff5..bc69616 100644
--- a/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_additions.html
@@ -160,7 +160,7 @@
<A HREF="pkg_android.support.v4.content.html#SharedPreferencesCompat" class="hiddenlink" target="rightframe"><b>SharedPreferencesCompat</b></A><br>
<A HREF="pkg_android.support.v4.content.html#SharedPreferencesCompat.EditorCompat" class="hiddenlink" target="rightframe"><b>SharedPreferencesCompat.EditorCompat</b></A><br>
<A HREF="pkg_android.support.design.widget.html#Snackbar.Callback" class="hiddenlink" target="rightframe"><b>Snackbar.Callback</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html
index cb1ed5f..33a23bf 100644
--- a/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html
+++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_all.html
@@ -419,7 +419,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html
index b674f27..9588a73 100644
--- a/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_changes.html
@@ -328,7 +328,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="android.support.v4.view.ViewCompat.html" class="hiddenlink" target="rightframe">ViewCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html
index e6da73f..c466298 100644
--- a/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23/changes/classes_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html
index d1e5215..ae8c0d3 100644
--- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_additions.html
@@ -53,7 +53,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.ctor_added(android.content.Context, android.util.AttributeSet, int)" class="hiddenlink" target="rightframe"><b>TextInputLayout</b>
(<code>Context, AttributeSet, int</code>)</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html
index 4618d88..401df57 100644
--- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html
+++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_all.html
@@ -53,7 +53,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.design.widget.TextInputLayout.html#android.support.design.widget.TextInputLayout.ctor_added(android.content.Context, android.util.AttributeSet, int)" class="hiddenlink" target="rightframe"><b>TextInputLayout</b>
(<code>Context, AttributeSet, int</code>)</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html
index a5ca2ef..122cdce 100644
--- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_changes.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html
index 74a09ba..dadd1cd 100644
--- a/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23/changes/constructors_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html
index 2f6ac9c..f9137b8 100644
--- a/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_additions.html
@@ -444,7 +444,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html
index a7f5e18..909dbcc 100644
--- a/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html
+++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_all.html
@@ -538,7 +538,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v7.appcompat.R.style.html#android.support.v7.appcompat.R.style.Widget_AppCompat_Button_Colored" class="hiddenlink" target="rightframe">Widget_AppCompat_Button_Colored</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html
index 0e2ccff..301881a 100644
--- a/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_changes.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html
index 5027374..174a576 100644
--- a/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23/changes/fields_index_removals.html
@@ -241,7 +241,7 @@
</nobr><br>
<nobr><A HREF="android.support.v7.appcompat.R.styleable.html#android.support.v7.appcompat.R.styleable.View_backgroundTintMode" class="hiddenlink" target="rightframe"><strike>View_backgroundTintMode</strike></A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html
index acb8508..125d4e8 100644
--- a/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html
+++ b/docs/html/sdk/support_api_diff/23/changes/jdiff_help.html
@@ -120,7 +120,7 @@
There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass.
In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes.
</BLOCKQUOTE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html
index 4480788..1e865b7 100644
--- a/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html
+++ b/docs/html/sdk/support_api_diff/23/changes/jdiff_statistics.html
@@ -467,7 +467,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html
index 36f9836..6a2e76e 100644
--- a/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html
+++ b/docs/html/sdk/support_api_diff/23/changes/jdiff_topleftframe.html
@@ -49,7 +49,7 @@
<TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
</TR>
</TABLE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html
index 3cec9a3..c3e4176 100644
--- a/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_additions.html
@@ -529,7 +529,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.app.FragmentActivity.html#android.support.v4.app.FragmentActivity.validateRequestPermissionsRequestCode_added(int)" class="hiddenlink" target="rightframe"><b>validateRequestPermissionsRequestCode</b>
(<code>int</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html
index 072b2ff..7b2f1d4 100644
--- a/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html
+++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_all.html
@@ -550,7 +550,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.app.FragmentActivity.html#android.support.v4.app.FragmentActivity.validateRequestPermissionsRequestCode_added(int)" class="hiddenlink" target="rightframe"><b>validateRequestPermissionsRequestCode</b>
(<code>int</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html
index d190580..90a0a23 100644
--- a/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_changes.html
@@ -83,7 +83,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.html#android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter.setBackgroundColor_changed(int)" class="hiddenlink" target="rightframe">setBackgroundColor
(<code>int</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html
index 25175750..ce89d27 100644
--- a/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23/changes/methods_index_removals.html
@@ -71,7 +71,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.app.Fragment.html#android.support.v4.app.Fragment.onAttach_removed(android.app.Activity)" class="hiddenlink" target="rightframe"><strike>onAttach</strike>
(<code>Activity</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html
index 446ee58..fc6d24d 100644
--- a/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html
+++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_additions.html
@@ -59,7 +59,7 @@
<A HREF="changes-summary.html#android.support.v7.graphics.drawable" class="hiddenlink" target="rightframe"><b>android.support.v7.graphics.drawable</b></A><br>
<A HREF="changes-summary.html#android.support.v7.preference" class="hiddenlink" target="rightframe"><b>android.support.v7.preference</b></A><br>
<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><b>android.support.v8.renderscript</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html
index d1dbbe1..c770167 100644
--- a/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html
+++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_all.html
@@ -77,7 +77,7 @@
<A HREF="changes-summary.html#android.support.v7.preference" class="hiddenlink" target="rightframe"><b>android.support.v7.preference</b></A><br>
<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><b>android.support.v8.renderscript</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html
index 730633e..2140313 100644
--- a/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html
+++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_changes.html
@@ -68,7 +68,7 @@
<A HREF="pkg_android.support.v7.appcompat.html" class="hiddenlink" target="rightframe">android.support.v7.appcompat</A><br>
<A HREF="pkg_android.support.v7.graphics.html" class="hiddenlink" target="rightframe">android.support.v7.graphics</A><br>
<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html
index d0ffabc..d5a825d 100644
--- a/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html
+++ b/docs/html/sdk/support_api_diff/23/changes/packages_index_removals.html
@@ -49,7 +49,7 @@
</div>
<br>
<div id="indexTableEntries">
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html
index a8630f7..6ebc3a7 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.design.widget.html
@@ -169,7 +169,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html
index c56e8a4..877fd6c 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v13.app.html
@@ -120,7 +120,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html
index 3d7f780..ea3848e 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v17.leanback.widget.html
@@ -112,7 +112,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html
index 36965dd..4a51cf8 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.animation.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html
index 692e7ef..9fbee40 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.app.html
@@ -176,7 +176,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html
index 44e9f81..9e654a6 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.content.html
@@ -169,7 +169,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html
index 6139c8e..de77561 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.graphics.drawable.html
@@ -112,7 +112,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html
index e6fe510..761e746 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.html
@@ -112,7 +112,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html
index 9b0e472..18893f4 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.media.session.html
@@ -119,7 +119,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html
index 9a76a7b..2ed8d04 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.os.html
@@ -119,7 +119,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html
index b2a178a..c995ed8 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.text.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html
index dcdbc56..ec69556 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.accessibility.html
@@ -127,7 +127,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html
index 2a955d3..2361c0f 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.view.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html
index 482bf1f..c6b5e0c 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v4.widget.html
@@ -141,7 +141,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html
index 1dd5425..a99b641 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.app.html
@@ -120,7 +120,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html
index e014278..eb5ed08 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.appcompat.html
@@ -154,7 +154,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html
index cb6c97b..9f88138 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.graphics.html
@@ -120,7 +120,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html
index cc0065d..e4da229 100644
--- a/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html
+++ b/docs/html/sdk/support_api_diff/23/changes/pkg_android.support.v7.util.html
@@ -119,7 +119,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html
index cb62aa8..f73d864 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_additions.html
@@ -933,7 +933,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
(<code>WindowInsetsCompat</code>)</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html
index 719f9af..fb553f8 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_all.html
@@ -1313,7 +1313,7 @@
<!-- Constructor WindowInsetsCompat -->
<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
(<code>WindowInsetsCompat</code>)</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html
index 854a487..4718b46 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_changes.html
@@ -652,7 +652,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html
index e6d9e07..179472a32 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/alldiffs_index_removals.html
@@ -110,7 +110,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
index d6a9415..41ac368 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.Builder.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html
index dd0b511..c4f0bfb 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsIntent.html
@@ -130,7 +130,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html
index 16cac31..1ccaab3 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.customtabs.CustomTabsSession.html
@@ -126,7 +126,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
index 7e1e59a..ad3dfd8 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.AppBarLayout.ScrollingViewBehavior.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html
index e98c6f3..22984b8 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.BottomSheetBehavior.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
index ebfdce1..a20a1ed 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CollapsingToolbarLayout.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
index 8cf6146..edc96ed 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.Behavior.html
@@ -147,7 +147,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html
index a36eab0..445da88 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.LayoutParams.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html
index 4a7247a..3ba5c1e 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.CoordinatorLayout.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
index 633db38..07099d6 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.FloatingActionButton.Behavior.html
@@ -144,7 +144,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html
index 01d4b6d..a09656a 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TabLayout.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html
index ecd6fd4..9ad13eb 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.design.widget.TextInputLayout.html
@@ -171,7 +171,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html
index 9b31c9e..6b23c17 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v14.preference.PreferenceFragment.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html
index 9df6536..9f1f00c 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.ViewHolder.html
@@ -136,7 +136,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html
index 16b03ad..a0b0aa9 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.AbstractMediaItemPresenter.html
@@ -151,7 +151,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html
index 3e3ded0..3dad1a2 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.leanback.widget.ObjectAdapter.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html
index 6e544651..690328a 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v17.preference.LeanbackSettingsFragment.html
@@ -94,7 +94,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
index 0600e44..a353745 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.accessibilityservice.AccessibilityServiceInfoCompat.html
@@ -126,7 +126,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html
index 74ae6f6..95b4fc6 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityCompat.html
@@ -129,7 +129,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html
index ce96b49..e675b7f 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ActivityOptionsCompat.html
@@ -165,7 +165,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html
index 13b2ce1..dfc1a60 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.FragmentController.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html
index 6a404eb..211a88f 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.ServiceCompat.html
@@ -130,7 +130,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html
index 1495fb4..7394059 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.app.SharedElementCallback.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html
index 1d6b9b1..b6157a2 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.content.ContextCompat.html
@@ -111,7 +111,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
index 3408caa..92f1ba4 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.graphics.drawable.DrawableCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html
index acc16c1..52da3d4 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserCompat.MediaItem.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html
index 7a9c73311..7ea97f3 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaBrowserServiceCompat.BrowserRoot.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html
index fbbaa19..fa1d610 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaDescriptionCompat.html
@@ -157,7 +157,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html
index e52493b..7e0f137 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.MediaMetadataCompat.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html
index 3e2c68b..65467b8 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaButtonReceiver.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html
index 5ce173f..e3b0184 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.QueueItem.html
@@ -133,7 +133,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html
index ee71244..90bd5eb 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.MediaSessionCompat.html
@@ -126,7 +126,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
index 2c54c1d..07e2449 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.media.session.PlaybackStateCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html
index eb59ddb..372415a 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.os.BuildCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html
index b5f4371..d62437e 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.KeyEventCompat.html
@@ -141,7 +141,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html
index 9f85dab..8f58037 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.MotionEventCompat.html
@@ -161,7 +161,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html
index 1b4ea0f..0974230 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewCompat.html
@@ -181,7 +181,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
index dcb2023..3eec7fa0a 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.ViewConfigurationCompat.html
@@ -111,7 +111,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html
index e0f77c9..c5c1d22 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.WindowInsetsCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
index 6ff46b8..1f9801f 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityEventCompat.html
@@ -158,7 +158,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html
index 5d63b93a..923ec80 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.AccessibilityStateChangeListenerCompat.html
@@ -110,7 +110,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
index 004d89e..defa406 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityManagerCompat.html
@@ -143,7 +143,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
index 695028b..d6f719e 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat.html
@@ -157,7 +157,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html
index 17109ec..d087e4a 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html
index 30df540..84fc73b 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html
index 1d5a250..41abf7e 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.RangeInfoCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
index 727576d..005616a 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.html
@@ -144,7 +144,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html
index 101070c..bd6b7f8 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityNodeProviderCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html
index a3b8d96..40f3ca2 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.view.accessibility.AccessibilityWindowInfoCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html
index cba004e..3d9f2ea 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnCloseListenerCompat.html
@@ -95,7 +95,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html
index c15d1b9..df0f3e1 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.OnQueryTextListenerCompat.html
@@ -95,7 +95,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html
index cbb3925..4af1e46 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SearchViewCompat.html
@@ -121,7 +121,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html
index 77dbdf6..5848782 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.SwipeRefreshLayout.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html
index a803634..87b9e69 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v4.widget.TextViewCompat.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html
index 2a864f0..bc8abd6 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.ActionBarDrawerToggle.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html
index adfcabb..7b131e6 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.app.AppCompatDelegate.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html
index e26c32b..02f43fd 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.content.res.AppCompatResources.html
@@ -108,7 +108,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html
index f588384..1999a48 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.graphics.Palette.html
@@ -115,7 +115,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html
index d2350979..95be79c 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.util.SortedList.Callback.html
@@ -138,7 +138,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html
index cf5c0f6..2fdfb0e 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearLayoutManager.html
@@ -109,7 +109,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html
index 3e13735..5cf79ee 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.LinearSmoothScroller.html
@@ -112,7 +112,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html
index d5e36f0..5411a1f 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.RecyclerView.html
@@ -116,7 +116,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html
index 640ef38..9d0ab87 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/android.support.v7.widget.StaggeredGridLayoutManager.html
@@ -124,7 +124,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html b/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html
index 12dfb4e..4456c22 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/changes-summary.html
@@ -315,7 +315,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html
index f3eb2ed..acb8115 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_additions.html
@@ -291,7 +291,7 @@
<A HREF="pkg_android.support.v7.widget.html#Toolbar.LayoutParams" class="hiddenlink" target="rightframe"><b>Toolbar.LayoutParams</b></A><br>
<A HREF="pkg_android.support.v7.widget.html#Toolbar.OnMenuItemClickListener" class="hiddenlink" target="rightframe"><b><i>Toolbar.OnMenuItemClickListener</i></b></A><br>
<A HREF="pkg_android.support.v7.widget.html#Toolbar.SavedState" class="hiddenlink" target="rightframe"><b>Toolbar.SavedState</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html
index 410ac8a..3e77bf2 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_all.html
@@ -514,7 +514,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html
index 1baef5c..58fe615 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_changes.html
@@ -380,7 +380,7 @@
<a href="#topheader"><font size="-2">TOP</font></a>
<p><div style="line-height:1.5em;color:black">
<A HREF="android.support.v4.view.WindowInsetsCompat.html" class="hiddenlink" target="rightframe">WindowInsetsCompat</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html
index e6da73f..c466298 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/classes_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html
index b0c0587..312effc 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_additions.html
@@ -53,7 +53,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
(<code>WindowInsetsCompat</code>)</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html
index 91568db..24310b7 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_all.html
@@ -71,7 +71,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.view.WindowInsetsCompat.html#android.support.v4.view.WindowInsetsCompat.ctor_added(android.support.v4.view.WindowInsetsCompat)" class="hiddenlink" target="rightframe"><b>WindowInsetsCompat</b>
(<code>WindowInsetsCompat</code>)</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html
index b4142ed..62a75f8c 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_changes.html
@@ -61,7 +61,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.content.ContextCompat.html#android.support.v4.content.ContextCompat.ctor_changed()" class="hiddenlink" target="rightframe">ContextCompat
()</A></nobr> constructor<br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html
index f1a9952..2fbd2e1 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/constructors_index_removals.html
@@ -47,7 +47,7 @@
<div id="indexTableCaption" style="background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;">
Listed as: <span style="color:#069"><strong>Added</strong></span>, <span style="color:#069"><strike>Removed</strike></span>, <span style="color:#069">Changed</span></font>
</div>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html
index 8923dbe..cdb8ee8 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_additions.html
@@ -253,7 +253,7 @@
</nobr><br>
<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html
index 19cebb7..14b3e97 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_all.html
@@ -285,7 +285,7 @@
</nobr><br>
<nobr><A HREF="android.support.v4.view.accessibility.AccessibilityEventCompat.html#android.support.v4.view.accessibility.AccessibilityEventCompat.TYPE_WINDOWS_CHANGED" class="hiddenlink" target="rightframe">TYPE_WINDOWS_CHANGED</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html
index b5ab769..c72b2de 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_changes.html
@@ -57,7 +57,7 @@
</nobr><br>
<nobr><A HREF="android.support.v4.view.ViewCompat.html#android.support.v4.view.ViewCompat.OVER_SCROLL_NEVER" class="hiddenlink" target="rightframe">OVER_SCROLL_NEVER</A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html
index 09ffac4..61820d1 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/fields_index_removals.html
@@ -53,7 +53,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v7.widget.StaggeredGridLayoutManager.html#android.support.v7.widget.StaggeredGridLayoutManager.TAG" class="hiddenlink" target="rightframe"><strike>TAG</strike></A>
</nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html
index ca0931f..966dda8 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_help.html
@@ -120,7 +120,7 @@
There are some complex changes which can occur between versions, for example, when two or more methods with the same name change simultaneously, or when a method or field is moved into or from a superclass.
In these cases, the change will be seen as a removal and an addition, rather than as a change. Unexpected removals or additions are often part of one of these type of changes.
</BLOCKQUOTE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html
index 698dbec..7010da6 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_statistics.html
@@ -583,7 +583,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html
index 36f9836..6a2e76e 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/jdiff_topleftframe.html
@@ -49,7 +49,7 @@
<TD NOWRAP><FONT CLASS="indexText" size="-2"><A HREF="fields_index_all.html" TARGET="bottomleftframe">By Field</A></FONT><br></TD>
</TR>
</TABLE>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html
index 508018e..419a607 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_additions.html
@@ -434,7 +434,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
(<code>long</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html
index a52d5c9..d33bfc0 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_all.html
@@ -565,7 +565,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v4.media.session.PlaybackStateCompat.html#android.support.v4.media.session.PlaybackStateCompat.toKeyCode_added(long)" class="hiddenlink" target="rightframe"><b>toKeyCode</b>
(<code>long</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html
index 5faae42..ef008cb 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_changes.html
@@ -208,7 +208,7 @@
(<code>int, Bitmap, String</code>)</A></nobr><br>
<nobr><A HREF="android.support.v4.view.KeyEventCompat.html#android.support.v4.view.KeyEventCompat.startTracking_changed(android.view.KeyEvent)" class="hiddenlink" target="rightframe">startTracking
(<code>KeyEvent</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html
index 062ac8f..1c0c6be 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/methods_index_removals.html
@@ -79,7 +79,7 @@
<p><div style="line-height:1.5em;color:black">
<nobr><A HREF="android.support.v7.widget.LinearLayoutManager.html#android.support.v7.widget.LinearLayoutManager.prepareForDrop_removed(android.view.View, android.view.View, int, int)" class="hiddenlink" target="rightframe"><strike>prepareForDrop</strike>
(<code>View, View, int, int</code>)</A></nobr><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html
index 2eff0f7..bb88d9f 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_additions.html
@@ -52,7 +52,7 @@
<A NAME="A"></A>
<A HREF="changes-summary.html#android.support.transition" class="hiddenlink" target="rightframe"><b>android.support.transition</b></A><br>
<A HREF="changes-summary.html#android.support.v4.text.util" class="hiddenlink" target="rightframe"><b>android.support.v4.text.util</b></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html
index 58e51ed..78805db 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_all.html
@@ -77,7 +77,7 @@
<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html
index 1d9e428..f5f6425 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_changes.html
@@ -72,7 +72,7 @@
<A HREF="pkg_android.support.v7.preference.html" class="hiddenlink" target="rightframe">android.support.v7.preference</A><br>
<A HREF="pkg_android.support.v7.util.html" class="hiddenlink" target="rightframe">android.support.v7.util</A><br>
<A HREF="pkg_android.support.v7.widget.html" class="hiddenlink" target="rightframe">android.support.v7.widget</A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html
index d52d40d..ce5ca58 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/packages_index_removals.html
@@ -53,7 +53,7 @@
<A HREF="changes-summary.html#android.support.v7.appcompat" class="hiddenlink" target="rightframe"><strike>android.support.v7.appcompat</strike></A><br>
<A HREF="changes-summary.html#android.support.v7.recyclerview" class="hiddenlink" target="rightframe"><strike>android.support.v7.recyclerview</strike></A><br>
<A HREF="changes-summary.html#android.support.v8.renderscript" class="hiddenlink" target="rightframe"><strike>android.support.v8.renderscript</strike></A><br>
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html
index 5959d63..45a31ff 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.customtabs.html
@@ -119,7 +119,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html
index 510b9bd..a311b48 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.design.widget.html
@@ -161,7 +161,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html
index 84efadc6..f24be00 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v14.preference.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html
index 4ce1f32..c07a487 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.leanback.widget.html
@@ -119,7 +119,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html
index ad0aadd..c61d79d 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v17.preference.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html
index e904a76..2c0f684 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.accessibilityservice.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html
index f8e4cb1..58ed06f9 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.app.html
@@ -148,7 +148,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html
index 31aa1da..65dd616 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.content.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html
index b1efab3..f8b31a5 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.graphics.drawable.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html
index 612a1a0..5300c86 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.html
@@ -126,7 +126,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html
index 3e46335..459d0c3 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.media.session.html
@@ -126,7 +126,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html
index b250855..6d7f399 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.os.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html
index d34506e..6f0e777 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.util.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html
index a6362fb..d5d126c 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.accessibility.html
@@ -190,7 +190,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html
index 10b1334..d720d41 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.view.html
@@ -133,7 +133,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html
index 5ed0f65..2efef45 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v4.widget.html
@@ -162,7 +162,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html
index 8eb58aa..f36cba5 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.app.html
@@ -162,7 +162,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html
index 90787f7..2e4b703 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.content.res.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html
index bd9cf24..439c8d3 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.graphics.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html
index b80e005..b2b781b 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.preference.html
@@ -105,7 +105,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html
index 365022f..c35fb8c 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.util.html
@@ -148,7 +148,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html
index e07d5b8..72e5497 100644
--- a/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html
+++ b/docs/html/sdk/support_api_diff/24.2.0/changes/pkg_android.support.v7.widget.html
@@ -449,7 +449,7 @@
</div> <!-- end footer -->
</div><!-- end doc-content -->
</div> <!-- end body-content -->
-<script src="http://www.google-analytics.com/ga.js" type="text/javascript">
+<script src="https://www.google-analytics.com/ga.js" type="text/javascript">
</script>
<script type="text/javascript">
try {
diff --git a/docs/html/topic/performance/_book.yaml b/docs/html/topic/performance/_book.yaml
index e053a2c..4021e85 100644
--- a/docs/html/topic/performance/_book.yaml
+++ b/docs/html/topic/performance/_book.yaml
@@ -1,34 +1,61 @@
toc:
-- title: Reducing Network Battery Drain
- path: /topic/performance/power/network/index.html
+- title: Optimizing for Battery Life
+ path: /topic/performance/power/index.html
path_attributes:
- name: description
- value: Access the network while going easy on battery life.
+ value: Learn to make your app more battery-friendly.
section:
- - title: Collecting Network Traffic Data
- path: /topic/performance/power/network/gather-data.html
- - title: Analyzing Network Traffic Data
- path: /topic/performance/power/network/analyze-data.html
- - title: Optimizing User-Initiated Network Use
- path: /topic/performance/power/network/action-user-traffic.html
- - title: Optimizing Server-Initiated Network Use
- path: /topic/performance/power/network/action-server-traffic.html
- - title: Optimizing General Network Use
- path: /topic/performance/power/network/action-any-traffic.html
-- title: Implementing Doze
- path: /training/monitoring-device-state/doze-standby.html
+ - title: Network Use and Battery Consumption
+ path: /topic/performance/power/network/index.html
+ section:
+ - title: Collecting Network Traffic Data
+ path: /topic/performance/power/network/gather-data.html
+ - title: Analyzing Data Traffic
+ path: /topic/performance/power/network/analyze-data.html
+ - title: Optimizing User-Initiated Network Use
+ path: /topic/performance/power/network/action-user-traffic.html
+ - title: Optimizing App-Initiated Network Use
+ path: topic/performance/power/network/action-app-traffic.html
+ - title: Optimizing Server-Initiated Network Use
+ path: /topic/performance/power/network/action-server-traffic.html
+ - title: Optimizing General Network Use
+ path: /topic/performance/power/network/action-any-traffic.html
+ - title: Doze and App Standby
+ path: /training/monitoring-device-state/doze-standby.html
+ path_attributes:
+ - name: description
+ value: Help ensure the device isn't depleting the battery when not in use.
+ - title: Battery Historian
+ path: /topic/performance/power/battery-historian.html
+- title: Rendering
+ path: /topic/performance/rendering/index.html
path_attributes:
- name: description
- value: Help ensure the device isn't depleting the battery when not in use.
+ value: Speed up your app's rendering
+ section:
+ - title: Reducing Overdraw
+ path: /topic/performance/rendering/overdraw.html
+ - title: Performance and View Hierarchies
+ path: /topic/performance/rendering/optimizing-view-hierarchies.html
+ - title: Analyzing with Profile GPU Rendering
+ path: /topic/performance/rendering/profile-gpu.html
+- title: Intelligent Job-Scheduling
+ path: /topic/performance/scheduling.html
+- title: Background Optimization
+ path: /topic/performance/background-optimization.html
+- title: Reducing APK Size
+ path: /topic/performance/reduce-apk-size.html
+- title: Reducing Image Download Sizes
+ path: /topic/performance/network-xfer.html
- title: Launch-Time Performance
path: /topic/performance/launch-time.html
- title: Better Performance through Threading
path: /topic/performance/threads.html
-- title: Optimizing View Hierarchies
- path: /topic/performance/optimizing-view-hierarchies.html
-- title: Background Optimization
- path: /topic/performance/background-optimization.html
-- title: Intelligent Job-Scheduling
- path: /topic/performance/scheduling.html
-- title: Reducing APK Size
- path: /topic/performance/reduce-apk-size.html
+- title: Manage Your App's Memory
+ path: /topic/performance/memory.html
+- title: Overview of Memory Managemement
+ path: /topic/performance/memory-overview.html
+ path_attributes:
+ - name: description
+ value: How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices.
+
diff --git a/docs/html/topic/performance/images/app-rankings.png b/docs/html/topic/performance/images/app-rankings.png
new file mode 100644
index 0000000..9dd60e5
--- /dev/null
+++ b/docs/html/topic/performance/images/app-rankings.png
Binary files differ
diff --git a/docs/html/topic/performance/images/bars.png b/docs/html/topic/performance/images/bars.png
new file mode 100644
index 0000000..3afea46
--- /dev/null
+++ b/docs/html/topic/performance/images/bars.png
Binary files differ
diff --git a/docs/html/topic/performance/images/beforeafterindexed.png b/docs/html/topic/performance/images/beforeafterindexed.png
new file mode 100644
index 0000000..dc7762e
--- /dev/null
+++ b/docs/html/topic/performance/images/beforeafterindexed.png
Binary files differ
diff --git a/docs/html/topic/performance/images/comparison.png b/docs/html/topic/performance/images/comparison.png
new file mode 100644
index 0000000..18f204c
--- /dev/null
+++ b/docs/html/topic/performance/images/comparison.png
Binary files differ
diff --git a/docs/html/topic/performance/images/decisions.png b/docs/html/topic/performance/images/decisions.png
new file mode 100644
index 0000000..d4f21f8
--- /dev/null
+++ b/docs/html/topic/performance/images/decisions.png
Binary files differ
diff --git a/docs/html/topic/performance/images/dropdown.png b/docs/html/topic/performance/images/dropdown.png
new file mode 100644
index 0000000..59ec6110
--- /dev/null
+++ b/docs/html/topic/performance/images/dropdown.png
Binary files differ
diff --git a/docs/html/topic/performance/images/generic-timeline.png b/docs/html/topic/performance/images/generic-timeline.png
new file mode 100644
index 0000000..04388b6
--- /dev/null
+++ b/docs/html/topic/performance/images/generic-timeline.png
Binary files differ
diff --git a/docs/html/topic/performance/images/moarparrots.png b/docs/html/topic/performance/images/moarparrots.png
new file mode 100644
index 0000000..ee10ec1
--- /dev/null
+++ b/docs/html/topic/performance/images/moarparrots.png
Binary files differ
diff --git a/docs/html/topic/performance/images/palette.png b/docs/html/topic/performance/images/palette.png
new file mode 100644
index 0000000..eb6be6b
--- /dev/null
+++ b/docs/html/topic/performance/images/palette.png
Binary files differ
diff --git a/docs/html/topic/performance/images/parrot.png b/docs/html/topic/performance/images/parrot.png
new file mode 100644
index 0000000..7a8b86a
--- /dev/null
+++ b/docs/html/topic/performance/images/parrot.png
Binary files differ
diff --git a/docs/html/topic/performance/images/pug-visualization.png b/docs/html/topic/performance/images/pug-visualization.png
new file mode 100644
index 0000000..8270d0e
--- /dev/null
+++ b/docs/html/topic/performance/images/pug-visualization.png
Binary files differ
diff --git a/docs/html/topic/performance/images/pugspecificdata.png b/docs/html/topic/performance/images/pugspecificdata.png
new file mode 100644
index 0000000..1c2be83
--- /dev/null
+++ b/docs/html/topic/performance/images/pugspecificdata.png
Binary files differ
diff --git a/docs/html/topic/performance/images/s-generic-closeup.png b/docs/html/topic/performance/images/s-generic-closeup.png
new file mode 100644
index 0000000..6685d51
--- /dev/null
+++ b/docs/html/topic/performance/images/s-generic-closeup.png
Binary files differ
diff --git a/docs/html/topic/performance/images/s-profiler-legend.png b/docs/html/topic/performance/images/s-profiler-legend.png
new file mode 100644
index 0000000..968fd38
--- /dev/null
+++ b/docs/html/topic/performance/images/s-profiler-legend.png
Binary files differ
diff --git a/docs/html/topic/performance/images/vq.gif b/docs/html/topic/performance/images/vq.gif
new file mode 100644
index 0000000..cbf6a35
--- /dev/null
+++ b/docs/html/topic/performance/images/vq.gif
Binary files differ
diff --git a/docs/html/topic/performance/index.jd b/docs/html/topic/performance/index.jd
index e08db15..2b6b197 100644
--- a/docs/html/topic/performance/index.jd
+++ b/docs/html/topic/performance/index.jd
@@ -1,4 +1,4 @@
-page.title=Performance
+page.title=Performance and Power
page.article=true
page.metaDescription=Improve your app's performance by learning how to optimize power consumption, launch times, and other important areas of performance.
diff --git a/docs/html/topic/performance/memory-overview.jd b/docs/html/topic/performance/memory-overview.jd
new file mode 100644
index 0000000..58067d2
--- /dev/null
+++ b/docs/html/topic/performance/memory-overview.jd
@@ -0,0 +1,288 @@
+page.title=Overview of Android Memory Management
+page.tags=ram,memory,paging,mmap
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol class="nolist">
+ <li><a href="#gc">Garbage collection</a></li>
+ <li><a href="#SharingRAM">Sharing Memory</a></li>
+ <li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li>
+ <li><a href="#RestrictingMemory">Restricting App Memory</a></li>
+ <li><a href="#SwitchingApps">Switching Apps</a></li>
+</ol>
+<h2>See Also</h2>
+<ul>
+ <li><a href="{@docRoot}training/articles/memory.html">Manage Your App's Memory</a>
+ </li>
+ <li><a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
+ </li>
+</ul>
+
+</div>
+</div>
+
+<p>
+ The Android Runtime (ART) and Dalvik virtual machine use
+ <a href="http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a>
+ and <a href="http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a>
+ (mmapping) to manage memory. This means that any memory an app
+ modifies—whether by allocating
+ new objects or touching mmapped pages—remains resident in RAM and
+ cannot be paged out. The only way to release memory from an app is to release
+ object references that the app holds, making the memory available to the
+ garbage collector.
+ That is with one exception: any files
+ mmapped in without modification, such as code,
+ can be paged out of RAM if the system wants to use that memory elsewhere.
+</p>
+
+<p>
+ This page explains how Android manages app processes and memory
+ allocation. For more information about how to manage memory more efficiently
+ in your app, see
+ <a href="{@docRoot}training/articles/memory.html">Manage Your App's Memory</a>.
+</p>
+
+<!-- Section 1 #################################################### -->
+
+<h2 id="gc">Garbage collection</h2>
+
+<p>
+ A managed memory environment, like the ART or Dalvik virtual machine,
+ keeps track of each memory allocation. Once it determines
+ that a piece of memory is no longer being used by the program,
+ it frees it back to the heap, without any intervention from the programmer.
+ The mechanism for reclaiming unused memory
+ within a managed memory environment
+ is known as <i>garbage collection</i>. Garbage collection has two goals:
+ find data objects in a program that cannot be accessed in the future; and
+ reclaim the resources used by those objects.
+</p>
+
+<p>
+ Android’s memory heap is a generational one, meaning that there are
+ different buckets of allocations that it tracks,
+ based on the expected life and size of an object being allocated.
+ For example, recently allocated objects belong in the <i>Young generation</i>.
+ When an object stays active long enough, it can be promoted
+ to an older generation, followed by a permanent generation.
+</p>
+
+<p>
+ Each heap generation has its own dedicated upper limit on the amount
+ of memory that objects there can occupy. Any time a generation starts
+ to fill up, the system executes a garbage collection
+ event in an attempt to free up memory. The duration of the garbage collection
+ depends on which generation of objects it's collecting
+ and how many active objects are in each generation.
+</p>
+
+<p>
+ Even though garbage collection can be quite fast, it can still
+ affect your app's performance. You don’t generally control
+ when a garbage collection event occurs from within your code.
+ The system has a running set of criteria for determining when to perform
+ garbage collection. When the criteria are satisfied,
+ the system stops executing the process and begins garbage collection. If
+ garbage collection occurs in the middle of an intensive processing loop
+ like an animation or during music playback, it can increase processing time.
+ This increase can potentially push code execution in your app past the
+ recommended 16ms threshold for efficient and smooth frame rendering.
+</p>
+
+<p>
+ Additionally, your code flow may perform kinds of work that
+ force garbage collection events to occur
+ more often or make them last longer-than-normal.
+ For example, if you allocate multiple objects in the
+ innermost part of a for-loop during each frame of an alpha
+ blending animation, you might pollute your memory heap with a
+ lot of objects.
+ In that circumstance, the garbage collector executes multiple garbage
+ collection events and can degrade the performance of your app.
+</p>
+
+<p>
+ For more general information about garbage collection, see
+ <a href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)"
+ class="external-link">Garbage collection</a>.
+</p>
+
+<!-- Section 2 #################################################### -->
+
+<h2 id="SharingRAM">Sharing Memory</h2>
+
+<p>
+ In order to fit everything it needs in RAM,
+ Android tries to share RAM pages across processes. It
+ can do so in the following ways:
+</p>
+
+<ul>
+ <li>
+ Each app process is forked from an existing process called Zygote.
+ The Zygote process starts when the system boots and loads common
+ framework code and resources
+ (such as activity themes). To start a new app process,
+ the system forks the Zygote process then
+ loads and runs the app's code in the new process.
+ This approach allows most of the RAM pages allocated for
+ framework code and resources to be shared across all app processes.
+ </li>
+
+ <li>
+ Most static data is mmapped into a process.
+ This technique allows data to be shared
+ between processes, and also allows it to be paged
+ out when needed. Example static data include:
+ Dalvik code (by placing it in a pre-linked <code>.odex</code>
+ file for direct mmapping), app resources
+ (by designing the resource table to be a structure
+ that can be mmapped and by aligning the zip
+ entries of the APK), and traditional project
+ elements like native code in <code>.so</code> files.
+ </li>
+
+ <li>
+ In many places, Android shares the same dynamic
+ RAM across processes using explicitly allocated
+ shared memory regions (either with ashmem or gralloc).
+ For example, window surfaces use shared
+ memory between the app and screen compositor, and
+ cursor buffers use shared memory between the
+ content provider and client.
+ </li>
+</ul>
+
+<p>
+ Due to the extensive use of shared memory, determining
+ how much memory your app is using requires
+ care. Techniques to properly determine your app's
+ memory use are discussed in
+ <a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>.
+</p>
+
+<!-- Section 3 #################################################### -->
+
+<h2 id="AllocatingRAM">Allocating and Reclaiming App Memory</h2>
+
+<p>
+ The Dalvik heap is constrained to a
+ single virtual memory range for each app process. This defines
+ the logical heap size, which can grow as it needs to
+ but only up to a limit that the system defines
+ for each app.
+</p>
+
+<p>
+ The logical size of the heap is not the same as
+ the amount of physical memory used by the heap.
+ When inspecting your app's heap, Android computes
+ a value called the Proportional Set Size (PSS),
+ which accounts for both dirty and clean pages
+ that are shared with other processes—but only in an
+ amount that's proportional to how many apps share
+ that RAM. This (PSS) total is what the system
+ considers to be your physical memory footprint.
+ For more information about PSS, see the
+ <a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
+ guide.
+</p>
+
+<p>
+ The Dalvik heap does not compact the logical
+ size of the heap, meaning that Android does not
+ defragment the heap to close up space. Android
+ can only shrink the logical heap size when there
+ is unused space at the end of the heap. However,
+ the system can still reduce physical memory used by the heap.
+ After garbage collection, Dalvik
+ walks the heap and finds unused pages, then returns
+ those pages to the kernel using madvise. So, paired
+ allocations and deallocations of large
+ chunks should result in reclaiming all (or nearly all)
+ the physical memory used. However,
+ reclaiming memory from small allocations can be much
+ less efficient because the page used
+ for a small allocation may still be shared with
+ something else that has not yet been freed.
+
+</p>
+
+<!-- Section 4 #################################################### -->
+
+<h2 id="RestrictingMemory">Restricting App Memory</h2>
+
+<p>
+ To maintain a functional multi-tasking environment,
+ Android sets a hard limit on the heap size
+ for each app. The exact heap size limit varies
+ between devices based on how much RAM the device
+ has available overall. If your app has reached the
+ heap capacity and tries to allocate more
+ memory, it can receive an {@link java.lang.OutOfMemoryError}.
+</p>
+
+<p>
+ In some cases, you might want to query the
+ system to determine exactly how much heap space you
+ have available on the current device—for example, to
+ determine how much data is safe to keep in a
+ cache. You can query the system for this figure by calling
+ {@link android.app.ActivityManager#getMemoryClass() }.
+ This method returns an integer indicating the number of
+ megabytes available for your app's heap.
+</p>
+
+<!-- Section 5 #################################################### -->
+
+<h2 id="SwitchingApps">Switching apps</h2>
+
+<p>
+ When users switch between apps,
+ Android keeps apps that
+ are not foreground—that is, not visible to the user or running a
+ foreground service like music playback—
+ in a least-recently used (LRU) cache.
+ For example, when a user first launches an app,
+ a process is created for it; but when the user
+ leaves the app, that process does <em>not</em> quit.
+ The system keeps the process cached. If
+ the user later returns to the app, the system reuses the process, thereby
+ making the app switching faster.
+</p>
+
+<p>
+ If your app has a cached process and it retains memory
+ that it currently does not need,
+ then your app—even while the user is not using it—
+ affects the system's
+ overall performance. As the system runs low on memory,
+ it kills processes in the LRU cache
+ beginning with the process least recently used. The system also
+ accounts for processes that hold onto the most memory
+ and can terminate them to free up RAM.
+</p>
+
+<p class="note">
+ <strong>Note:</strong> When the system begins killing processes in the
+ LRU cache, it primarily works bottom-up. The system also considers which
+ processes consume more memory and thus provide the system
+ more memory gain if killed.
+ The less memory you consume while in the LRU list overall,
+ the better your chances are
+ to remain in the list and be able to quickly resume.
+</p>
+
+<p>
+ For more information about how processes are cached while
+ not running in the foreground and how
+ Android decides which ones
+ can be killed, see the
+ <a href="{@docRoot}guide/components/processes-and-threads.html">Processes and Threads</a>
+ guide.
+</p>
diff --git a/docs/html/topic/performance/memory.jd b/docs/html/topic/performance/memory.jd
new file mode 100644
index 0000000..ef1c4ae
--- /dev/null
+++ b/docs/html/topic/performance/memory.jd
@@ -0,0 +1,593 @@
+page.title=Manage Your App's Memory
+page.tags=ram,low memory,OutOfMemoryError,onTrimMemory
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+ <li><a href="#monitor">Monitor Available Memory and Memory Usage</a>
+ <ul>
+ <li><a href="#AnalyzeRam">Tools for analyzing RAM usage</a></li>
+ <li><a href="#release">Release memory in response to events</a></li>
+ <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li>
+ </ul>
+ </li>
+ <li><a href="#code">Use More Efficient Code Constructs</a>
+ <ul>
+ <li><a href="#Services">Use services sparingly</a></li>
+ <li><a href="#DataContainers">Use optimized data containers</a></li>
+ <li><a href="#Abstractions">Be careful with code abstractions</a></li>
+ <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li>
+ <li><a href="#churn">Avoid memory churn</a></li>
+ </ul>
+ </li>
+ <li><a href="#remove">Remove Memory-Intensive Resources and Libraries</a>
+ <ul>
+ <li><a href="#reduce">Reduce overall APK size</a></li>
+ <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li>
+ <li><a href="#ExternalLibs">Be careful about using external libraries</a></li>
+ </ul>
+ </li>
+</ol>
+<h2>See Also</h2>
+<ul>
+ <li><a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a>
+ </li>
+ <li><a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
+ </li>
+ <li><a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a></li>
+</ul>
+
+</div>
+</div>
+
+<!-- INTRO #################################################### -->
+
+<p>
+ Random-access memory (RAM) is a valuable
+ resource in any software development environment, but
+ it's even more valuable on a mobile operating system
+ where physical memory is often constrained.
+ Although both the Android Runtime (ART) and Dalvik virtual machine perform
+ routine garbage collection, this does not mean you can ignore
+ when and where your app allocates and releases memory.
+ You still need to avoid
+ introducing memory leaks, usually caused by holding onto
+ object references in static member variables, and
+ release any {@link java.lang.ref.Reference} objects at the appropriate
+ time as defined by
+ lifecycle callbacks.
+</p>
+
+<p>
+ This page explains how you can
+ proactively reduce memory usage within your app.
+ For more information about general
+ practices to clean up your resources when programming in Java,
+ refer to other books or online
+ documentation about managing resource references.
+ If you’re looking for information about how to
+ analyze memory in a running app, read
+ <a href="#AnalyzeRam">Tools for analyzing RAM usage</a>.
+ For more detailed information about how the Android Runtime and Dalvik
+ virtual machine manage memory, see the
+ <a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a>.
+</p>
+
+<!-- Section 1 #################################################### -->
+
+<h2 id="monitor">Monitor Available Memory and Memory Usage</h2>
+
+<p>
+ The Android framework, Android Studio, and Android SDK
+ can help you analyze and adjust your app's memory usage.
+ The Android framework
+ exposes several APIs that allow your app to reduce its memory usage
+ dynamically during runtime. Android Studio and the Android SDK
+ contain several tools that allow you to investigate how your
+ app uses memory.
+</p>
+
+<!-- Section 1.1 #################################################### -->
+
+<h3 id="AnalyzeRam">Tools for analyzing RAM usage</h3>
+
+<p>
+ Before you can fix the memory usage problems in your app, you first need
+ to find them. Android Studio and the Android SDK include several tools
+ for analyzing memory usage in your app:
+</p>
+
+<ol>
+ <li>
+ The Device Monitor has a Dalvik Debug Monitor Server (DDMS) tool that allows
+ you to inspect memory allocation within your app process.
+ You can use this information to understand how your
+ app uses memory overall. For example, you can force a garbage collection
+ event and then view the types of objects that remain in memory. You can
+ use this information to identify operations or actions within your app
+ that allocate or leave excessive amounts of objects in memory.
+
+ <p>For more information about how to use the DDMS tool, see
+ <a href="/studio/profile/ddms.html">Using DDMS</a>.
+ </p>
+ </li>
+
+ <li>
+ The Memory Monitor in Android Studio shows you how your app allocates
+ memory over the course of a single session.
+ The tool shows a graph of available
+ and allocated Java memory over time, including garbage collection events.
+ You can also initiate garbage collection events and take a snapshot of
+ the Java heap while your app runs. The output from the Memory Monitor tool
+ can help you identify points when your app experiences excessive garbage
+ collection events, leading to app slowness.
+ <p>
+ For more information about how to use Memory Monitor tool, see
+ <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewHeap">Viewing Heap Updates</a>.
+ </p>
+ </li>
+
+ <li>
+ Garbage collection events also show up in the Traceview viewer. Traceview
+ allows you to view trace log files as both a timeline and as a profile
+ of what happened within a method. You can use this tool to determine
+ what code was executing when a garbage collection event occurred.
+ <p>
+ For more information about how to use the Traceview viewer, see
+ <a href="https://developer.android.com/studio/profile/traceview.html">Profiling with Traceview and dmtracedump</a>.
+ </p>
+ </li>
+
+ <li>
+ The Allocation Tracker tool in Android Studio gives you a detailed look
+ at how your app allocates memory.
+ The Allocation Tracker records an app's memory allocations and lists
+ all allocated objects within the profiling snapshot. You can use this
+ tool to track down parts of your code that allocate too many objects.
+
+ <p>
+ For more information about how to use the Allocation Tracker tool, see
+ <a href="{docRoot}studio/profile/allocation-tracker-walkthru.html">Allocation Tracker Walkthrough</a>.
+ </p>
+ </li>
+
+</ol>
+
+<!-- Section 1.2 #################################################### -->
+
+<h3 id="release">Release memory in response to events</h3>
+
+<p>
+ An Android device can run with varying amounts of free memory
+ depending on the physical amount of RAM on the device and how the user
+ operates it. The system broadcasts signals to indicate when it is under
+ memory pressure, and apps should listen for these signals and adjust
+ their memory usage as appropriate.
+</p>
+
+</p>
+ You can use the {@link android.content.ComponentCallbacks2} API
+ to listen for these signals and then adjust your memory
+ usage in response to app lifecycle
+ or device events. The
+ {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
+ method allows your app to listen for memory related events when the app runs
+ in the foreground (is visible) and when it runs in the background.
+</p>
+
+<p>
+ To listen for these events, implement the {@link
+ android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
+ callback in your {@link android.app.Activity}
+ classes, as shown in the following code snippet.
+</p>
+
+<pre class="prettyprint">
+import android.content.ComponentCallbacks2;
+// Other import statements ...
+
+public class MainActivity extends AppCompatActivity
+ implements ComponentCallbacks2 {
+
+ // Other activity code ...
+
+ /**
+ * Release memory when the UI becomes hidden or when system resources become low.
+ * @param level the memory-related event that was raised.
+ */
+ public void onTrimMemory(int level) {
+
+ // Determine which lifecycle or system event was raised.
+ switch (level) {
+
+ case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
+
+ /*
+ Release any UI objects that currently hold memory.
+
+ The user interface has moved to the background.
+ */
+
+ break;
+
+ case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
+ case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
+ case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
+
+ /*
+ Release any memory that your app doesn't need to run.
+
+ The device is running low on memory while the app is running.
+ The event raised indicates the severity of the memory-related event.
+ If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system will
+ begin killing background processes.
+ */
+
+ break;
+
+ case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
+ case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
+ case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
+
+ /*
+ Release as much memory as the process can.
+
+ The app is on the LRU list and the system is running low on memory.
+ The event raised indicates where the app sits within the LRU list.
+ If the event is TRIM_MEMORY_COMPLETE, the process will be one of
+ the first to be terminated.
+ */
+
+ break;
+
+ default:
+ /*
+ Release any non-critical data structures.
+
+ The app received an unrecognized memory level value
+ from the system. Treat this as a generic low-memory message.
+ */
+ break;
+ }
+ }
+}
+</pre>
+
+<p>
+ The
+ {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
+ callback was added in Android 4.0 (API level 14). For earlier versions,
+ you can use the
+ {@link android.content.ComponentCallbacks#onLowMemory()}
+ callback as a fallback for older versions, which is roughly equivalent to the
+ {@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.
+</p>
+
+<!-- Section 1.3 #################################################### -->
+
+<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3>
+
+<p>
+ To allow multiple running processes, Android sets a hard limit
+ on the heap size alloted for each app. The exact heap size limit varies
+ between devices based on how much RAM the device
+ has available overall. If your app has reached the heap capacity and
+ tries to allocate more
+ memory, the system throws an {@link java.lang.OutOfMemoryError}.
+</p>
+
+<p>
+ To avoid running out of memory, you can to query the system to determine
+ how much heap space you have available on the current device.
+ You can query the system for this figure by calling
+ {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}.
+ This returns an
+ {@link android.app.ActivityManager.MemoryInfo } object that provides
+ information about the device's
+ current memory status, including available memory, total memory, and
+ the memory threshold—the memory level below which the system begins
+ to kill processes. The
+ {@link android.app.ActivityManager.MemoryInfo } class also exposes a simple
+ boolean field,
+ {@link android.app.ActivityManager.MemoryInfo#lowMemory }
+ that tells you whether the device is running low on memory.
+</p>
+
+<p>
+ The following code snippet shows an example of how you can use the
+ {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}.
+ method in your application.
+</p>
+
+<pre class="prettyprint">
+public void doSomethingMemoryIntensive() {
+
+ // Before doing something that requires a lot of memory,
+ // check to see whether the device is in a low memory state.
+ ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();
+
+ if (!memoryInfo.lowMemory) {
+ // Do memory intensive work ...
+ }
+}
+
+// Get a MemoryInfo object for the device's current memory status.
+private ActivityManager.MemoryInfo getAvailableMemory() {
+ ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
+ ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
+ activityManager.getMemoryInfo(memoryInfo);
+ return memoryInfo;
+}
+</pre>
+
+<!-- Section 2 #################################################### -->
+
+<h2 id="code">Use More Memory-Efficient Code Constructs</h2>
+
+<p>
+ Some Android features, Java classes, and code constructs tend to
+ use more memory than others. You can minimize how
+ much memory your app uses by choosing more efficient alternatives in
+ your code.
+</p>
+
+<!-- Section 2.1 #################################################### -->
+
+<h3 id="Services">Use services sparingly</h3>
+
+<p>
+ Leaving a service running when it’s not needed is
+ <strong>one of the worst memory-management
+ mistakes</strong> an Android app can make. If your app needs a
+ <a href="{@docRoot}guide/components/services.html">service</a>
+ to perform work in the background, do not keep it running unless
+ it needs to run a job. Remember to stop your service when it has completed
+ its task. Otherwise, you can inadvertently cause a memory leak.
+</p>
+
+<p>
+ When you start a service, the system prefers to always keep the process
+ for that service running. This behavior
+ makes services processes very expensive
+ because the RAM used by a service remains unavailable to other processes.
+ This reduces the number of cached processes that the system can keep in
+ the LRU cache, making app switching less efficient. It can even lead to
+ thrashing in the system when memory is tight and the system can’t
+ maintain enough processes to host all the services currently running.
+</p>
+
+<p>
+ You should generally avoid use of persistent services because of
+ the on-going demands they place on available memory. Instead, we
+ recommend that you use an alternative implementation
+ such as {@link android.app.job.JobScheduler}. For more information about
+ how to use {@link android.app.job.JobScheduler} to schedule background
+ processes, see
+ <a href="/topic/performance/background-optimization.html">Background Optimizations</a>.
+<p>
+ If you must use a service, the
+ best way to limit the lifespan of your service is to use an {@link
+ android.app.IntentService}, which finishes
+ itself as soon as it's done handling the intent that started it.
+ For more information, read
+ <a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>.
+</p>
+
+<!-- Section 2.2 #################################################### -->
+
+<h3 id="DataContainers">Use optimized data containers</h3>
+
+<p>
+ Some of the classes provided by the programming language are not optimized for
+ use on mobile devices. For example, the generic
+ {@link java.util.HashMap} implementation can be quite memory
+ inefficient because it needs a separate entry object for every mapping.
+</p>
+
+<p>
+ The Android framework includes several optimized data containers, including
+ {@link android.util.SparseArray}, {@link android.util.SparseBooleanArray},
+ and {@link android.support.v4.util.LongSparseArray}.
+ For example, the {@link android.util.SparseArray} classes are more
+ efficient because they avoid the system's need to
+ <acronym title="Automatic conversion from primitive types to object classes (such as int to Integer)">autobox</acronym>
+ the key and sometimes value (which creates yet another object or
+ two per entry).
+</p>
+
+<p>
+ If necessary, you can always switch to raw arrays for a really lean data
+ structure.
+</p>
+
+<!-- Section 2.3 #################################################### -->
+
+<h3 id="Abstractions">Be careful with code abstractions</h3>
+
+<p>
+ Developers often use abstractions simply as a good programming practice,
+ because abstractions can improve code flexibility and maintenance.
+ However, abstractions come at a significant cost:
+ generally they require a fair amount more code that
+ needs to be executed, requiring more time and
+ more RAM for that code to be mapped into memory.
+ So if your abstractions aren't supplying a
+ significant benefit, you should avoid them.
+</p>
+
+<p>
+ For example, enums often require more than twice as much memory as static
+ constants. You should strictly avoid using enums on Android.
+</p>
+
+<!-- Section 2.4 #################################################### -->
+
+<h3 id="NanoProto">Use nano protobufs for serialized data</h3>
+
+<p>
+ <a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol buffers</a>
+ are a language-neutral, platform-neutral, extensible mechanism
+ designed by Google for serializing structured data—similar to XML, but
+ smaller, faster, and simpler. If you decide to use
+ protobufs for your data, you should always use nano protobufs in your
+ client-side code. Regular protobufs generate extremely verbose code, which
+ can cause many kinds of problems in your app such as
+ increased RAM use, significant APK size increase, and slower execution.
+</p>
+
+<p>
+ For more information, see the "Nano version" section in the
+ <a href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt"
+class="external-link">protobuf readme</a>.
+</p>
+
+<!-- Section 2.5 #################################################### -->
+
+<h3 id="churn">Avoid memory churn</h3>
+
+<p>
+ As mentioned previously, garbage collections events don't normally affect
+ your app's performance. However, many garbage collection events that occur
+ over a short period of time can quickly eat up your frame time. The more time
+ that the system spends on garbage collection, the less time it has to do
+ other stuff like rendering or streaming audio.
+</p>
+
+<p>
+ Often, <em>memory churn</em> can cause a large number of
+ garbage collection events to occur. In practice, memory churn describes the
+ number of allocated temporary objects that occur in a given amount of time.
+</p>
+
+<p>
+ For example, you might allocate multiple temporary objects within a
+ <code>for</code> loop. Or you might create new
+ {@link android.graphics.Paint} or {@link android.graphics.Bitmap}
+ objects inside the
+ {@link android.view.View#onDraw(android.graphics.Canvas) onDraw()}
+ function of a view.
+ In both cases, the app creates a lot of objects quickly at high volume.
+ These can quickly consume all the available memory in the young generation,
+ forcing a garbage collection event to occur.
+</p>
+
+<p>
+ Of course, you need to find the places in your code where
+ the memory churn is high before you can fix them. Use the tools discussed in
+ <a href="#AnalyzeRam">Analyze your RAM usage</a>
+</p>
+
+<p>
+ Once you identify the problem areas in your code, try to reduce the number of
+ allocations within performance critical areas. Consider moving things out of
+ inner loops or perhaps moving them into a
+ <a href="https://en.wikipedia.org/wiki/Factory_method_pattern" class="external-link">Factory</a>
+ based allocation structure.
+</p>
+
+<!-- Section 3 #################################################### -->
+
+<h2 id="remove">Remove Memory-Intensive Resources and Libraries</h2>
+
+<p>
+ Some resources and libraries within your code can gobble up memory without
+ you knowing it. Overall size of your APK, including third-party libraries
+ or embedded resources, can affect how much memory your app consumes. You can
+ improve your app's memory consumption by removing any redundant, unnecessary,
+ or bloated components, resources, or libraries from your code.
+</p>
+
+<!-- Section 3.1 #################################################### -->
+
+<h3 id="reduce">Reduce overall APK size</h3>
+
+<p>
+ You can significantly reduce your app's memory usage by reducing the overall
+ size of your app. Bitmap size, resources, animation frames, and third-party
+ libraries can all contribute to the size of your APK.
+ Android Studio and the Android SDK provide multiple tools
+ to help you reduce the size of your resources and external dependencies.
+</p>
+
+<p>
+ For more information about how to reduce your overall APK size, see
+ <a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a>.
+</p>
+
+<!-- Section 3.2 #################################################### -->
+
+<h3 id="DependencyInjection">Use caution with dependency injection frameworks</h3>
+
+<p>
+ Dependency injection framework such as
+ <a href="https://code.google.com/p/google-guice/" class="external-link">Guice</a>
+ or
+ <a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a>
+ can simplify the code you write and provide an adaptive environment
+ that's useful for testing and other configuration changes. However, dependency
+ frameworks aren't always optimized for mobile devices.
+</p>
+
+<p>
+ For example, these frameworks tend to initialize processes by
+ scanning your code for annotations. This which can require significant
+ amounts of your code to be mapped into RAM unnecessarily. The system
+ allocates these mapped pages into clean memory so Android can drop them; yet
+ that can't happen until the pages have remained in memory for a long period
+ of time.
+ </p>
+
+<p>
+ If you need to use a dependency injection framework in your app, consider
+ using
+ <a class="external-link" href="http://google.github.io/dagger/">Dagger</a>
+ instead. For example, Dagger does not use reflection to scan your app's code.
+ Dagger's strict implementation means that it can be used in Android apps
+ without needlessly increasing memory usage.
+</p>
+
+<!-- Section 3.3 #################################################### -->
+
+<h3 id="ExternalLibs">Be careful about using external libraries</h3>
+
+<p>
+ External library code is often not written for mobile environments and
+ can be inefficient when used
+ for work on a mobile client. When you decide to use an
+ external library, you may need to optimize that library for mobile devices.
+ Plan for that work up-front and analyze the library in terms of code size and
+ RAM footprint before deciding to use it at all.
+</p>
+
+<p>
+ Even some mobile-optimized libraries can cause problems due to differing
+ implementations. For example, one library may use nano protobufs
+ while another uses micro protobufs, resulting in two different protobuf
+ implementations in your app. This can happen with different
+ implementations of logging, analytics, image loading frameworks,
+ caching, and many other things you don't expect.
+</p>
+
+<p>
+ Although <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> can
+ help to remove APIs and resources with the right flags, it can't remove a
+ library's large internal dependencies. The features that you want in these
+ libraries may require lower-level dependencies. This becomes especially
+ problematic when you use an {@link android.app.Activity } subclass from a
+ library (which will tend to have wide swaths of dependencies),
+ when libraries use reflection (which is common and means you need to spend a
+ lot of time manually tweaking ProGuard to get it to work), and so on.
+</p>
+
+<p>
+ Also avoid using a shared library for just one or two features out of dozens.
+ You don't want to pull in a large amount of code and overhead that
+ you don't even use. When you consider whether to use a library, look for
+ an implementation that strongly matches what you need. Otherwise, you might
+ decide to create your own implementation.
+</p>
+
diff --git a/docs/html/topic/performance/network-xfer.jd b/docs/html/topic/performance/network-xfer.jd
new file mode 100644
index 0000000..7fe5594
--- /dev/null
+++ b/docs/html/topic/performance/network-xfer.jd
@@ -0,0 +1,374 @@
+page.title=Reducing Image Download Sizes
+page.metaDescription=Improve network performance by optimizing image size.
+
+meta.tags="performance"
+page.tags="performance"
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+ <ol>
+
+ <li>
+ <a href="#uif">Understanding Image Formats</a>
+ <ul>
+ <li><a href="#png">PNG</a></li>
+ <li><a href="#jpg">JPG</a></li>
+ <li><a href="#webp">WebP</a></li>
+ </ul>
+ </li>
+ <li>
+ <a href="#sf">Selecting a Format</a></li>
+ <li><a href="#doqv">Determining Optimal Quality Values</a>
+ <ul>
+ <li><a href="#sv">Scalar Values (JPG, WebP only)</a></li>
+ <li><a href="#butter">Butteraugli</a></li>
+ </ul>
+ </li>
+ <li><a href="#sizes">Serving Sizes</a></li>
+ </ol>
+ </div>
+</div>
+
+<p>
+Most download traffic consists of images. As a result, the smaller you can make
+your downloadable images, the better a network experience your app can provide
+for users. This page provides guidance on making image files smaller and more
+network-friendly.
+</p>
+
+<h2 id="uif">Understanding Image Formats</h2>
+
+<p>Android apps typically use images that are in one or more of the following file
+formats: PNG, JPG, and WebP. For each of these formats, there are steps you can
+take to reduce image sizes.
+</p>
+
+<h3 id="png">PNG</h3>
+
+<p>
+A key to making your PNG files smaller is reducing the number of unique
+colors used in each row of pixels that comprises the image. By using fewer
+colors, you improve the compression potential at all of the other stages of
+the pipeline.
+</p>
+
+<p>
+Reducing the number of unique colors makes a significant difference because PNG
+compression effectiveness is partly a function of the degree to which
+horizontally adjacent pixel colors vary. Thus, reducing the number of unique
+colors in each row of your PNG images can help in reducing their file sizes.
+</p>
+
+<p>
+When deciding whether to pursue this strategy, you should keep in mind that
+reducing the number of unique colors effectively amounts to applying a lossy
+encoding stage to the image. However, an encoding tool may not be a good
+judge of how bad a seemingly small error looks to the human eye. Therefore,
+you should perform this work manually in order to help ensure
+the right balance between efficient compression and acceptable image quality.
+</p>
+
+<p>
+There are two particularly useful approaches you can take: striving for indexed
+formats, and applying vector quantization.
+</p>
+
+
+<h4 id="strive">Strive for indexed formats</h4>
+
+<p>
+Any attempt at color reduction should start with trying to optimize your colors
+so that you can use the INDEXED format when exporting the image as a PNG. The
+INDEXED color mode works by choosing the best 256 colors to use, and replacing
+all pixel values with indices into that color palette. The result is a
+reduction from 16 million (potential) colors to only 256 colors: from 3 (without
+transparency) or 4 (with transparency) bytes per pixel to 1 byte per pixel.
+This change is a significant first-step file size reduction.
+</p>
+
+<p>
+Figure 1 shows shows an image and its indexed variant.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/beforeafterindexed.png">
+ <p class="img-caption">
+Figure 1. An image before and after conversion to the INDEXED format.
+ </p>
+
+
+<p>
+Figure 2 shows the color palette for the image in Figure 1:
+</p>
+
+ <img src="{@docRoot}topic/performance/images/palette.png">
+ <p class="img-caption">
+Figure 2. The color palette for the image in Figure 1.
+ </p>
+
+<p>
+Representing your image as a paletted image goes a long way toward
+significantly improving the file size, so it's worth investigating if the
+majority of your images can be converted.
+</p>
+
+<p>
+Of course, not every image can be accurately represented with only 256 colors.
+Some images, for example, might need 257, 310, 512, or 912 colors to
+look correct. In such cases, vector quantization can also be helpful.
+</p>
+
+<h4 id="vq">Vector quantization</h4>
+
+<p>
+The process of creating an indexed image may be better described as vector
+quantization (VQ). VQ serves as a rounding process for multidimensional
+numbers. In this process, all the colors in your image get grouped based upon
+their similarity. For a given group, all colors in that group are replaced by a
+single <em>center point</em> value, which minimizes error for colors in that
+cell (or "site" if you're using the Voronoi terminology). In Figure 3,
+the green dots represent input colors, and the red dots are the center points
+that replace the input colors. Each cell is bounded by blue lines.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/vq.gif">
+ <p class="img-caption">
+Figure 3. Applying vector quantization to the colors in an image.
+</p>
+
+<p>
+The result of applying VQ to an image reduces the number of unique colors,
+replacing each group of colors with a single color that's "pretty close"
+in visual quality.
+</p>
+
+<p>
+This technique also allows you to define the maximum number of unique colors in
+your image. For example, Figure 4 shows the a parrot head in 16.7 million colors
+(24 bits per pixel, or bpp) alongside a version that only allows only
+16 (3 bpp) unique colors to be used.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/parrot.png">
+ <p class="img-caption">
+Figure 4. Image before and after application of vector quantification.
+ </p>
+
+<p>
+Immediately, you can see that there's a loss of quality; most of the gradient
+colors have been replaced, imparting a banding effect to the image. This image
+needs more than 16 unique colors.
+</p>
+
+<p>
+Setting up a VQ step in your pipeline can help you get a better sense of the
+true number of unique colors that your image uses, and can help you reduce them
+significantly. There are a number of readily available tools that you can use
+to help you implement this technique.
+</p>
+
+<h3 id="jpg">JPG</h3>
+
+<p>
+If you are using JPG images, there are several small changes you can make that
+potentially provide significant file-size savings. These include:
+</p>
+
+<ul>
+ <li>
+Producing a smaller file size through different encoding methods (without
+impacting quality).
+ </li>
+
+ <li>
+Adjusting quality slightly in order to yield better compression.
+ </li>
+</ul>
+
+<p>Pursuing these strategies can often net you file-size reductions of up to
+25%.
+</p>
+
+<p>
+When choosing tools, remember that photo exporting tools can
+insert unnecessary metadata, such as GPS information, into your images. At
+a minimum, try to leverage existing tools to help strip out this information
+from your files.
+</p>
+
+<h3 id="webp">WebP</h3>
+
+<p>
+WebP is a newer image format supported from Android 4.2.1 (API level 17). This
+format provides superior lossless and lossy compression for images on the web.
+Using WebP, developers can create smaller, richer images. WebP lossless image
+files are, on average,
+<a href="https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#conclusions">
+26% smaller</a> than PNGs. These image files also support
+transparency (also known as alpha channel) at a cost of just
+<a href="https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study#results">
+22% more</a> bytes.
+</p>
+
+<p>
+WebP lossy images are
+<a href="https://developers.google.com/speed/webp/docs/webp_study#experiment_1_webp_vs_jpeg_at_equal_ssim_index">
+25-34% smaller</a> than comparable JPG images at equivalent
+<a href="https://en.wikipedia.org/wiki/Structural_similarity">SSIM</a>
+quality indices. For cases when lossy RGB compression is acceptable, lossy
+WebP also supports transparency, typically producing file sizes 3 times smaller
+than PNG.
+</p>
+
+<p>
+For more information about WebP, visit the
+<a href="https://developers.google.com/speed/webp/">WebP site</a>.
+</p>
+
+<h2 id="sf">Selecting a Format</h2>
+
+<p>
+Different image formats are suitable for different types of images. JPG and PNG
+have very different compression processes, and they produce quite different
+results.
+</p>
+
+<p>
+The decision between PNG and JPG often comes down to the complexity of the
+image itself. Figure 5 shows two images that come out quite differently
+depending on which compression scheme the developer applies. The image on the
+left has many small details, and thus compresses more efficiently with JPG. The
+image on the right, with runs of the same color, compresses more efficiently
+with PNG.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/comparison.png">
+ <p class="img-caption">
+Figure 5. Suitable cases for JPG vs. PNG
+ </p>
+
+
+<p>
+WebP as a format can support both lossy and lossless modes, making it an ideal
+replacement for both PNG and JPG. The only thing to keep in mind is that it
+only has native support on devices running Android 4.2.1 (API level 17) and
+higher. Fortunately, the large
+<a
+href="https://developer.android.com/about/dashboards/index.html#Platform">
+majority of devices</a> satisfy that requirement.
+</p>
+
+<p>
+Figure 6 provides a simple visualization to help you decide which compression
+scheme to use.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/decisions.png">
+ <p class="img-caption">
+Figure 6. Deciding on a compression scheme
+ </p>
+
+<h2 id="doqv">Determining Optimal Quality Values</h2>
+
+<p>
+There are several techniques you can use to achieve the right balance between
+compression and image quality. One technique uses scalar values and therefore
+only works for JPG and WebP. The other technique takes advantage of the
+Butteraugli library, and is usable for all image formats.
+</p>
+
+<h3 id="sv">Scalar values (JPG and WebP only)</h3>
+
+<p>
+The power of JPG and WebP comes from the fact that you can use a scalar value
+to balance quality against file size. The trick is finding out what the correct
+quality value is for your image. Too low a quality level produces a small file
+at the cost of image quality. Too high a quality level increases file size
+without providing a noticeable benefit to the user.
+</p>
+
+<p>
+The most straightforward solution is to pick some non-maximum value, and use
+that value. However, be aware that the quality value affects every image
+differently. While a quality of 75%, for example, may look fine on most images,
+there may be some cases do not fare as well. You should make sure to test your
+chosen maximum value against a representative sample of images. Also, make
+sure to perform all of your tests against the original images, and not on
+compressed versions.
+</p>
+
+<p>
+For large media applications that upload and re-send millions of JPGs a day,
+hand-tuning for each asset is impractical. You might address this challenge by
+specifying several different quality levels, according to image category. For
+example, you might set 35% as the quality setting for thumbnails, since a
+smaller image hides more compression artifacts.
+</p>
+
+<h3 id="butter">Butteraugli</h4>
+
+<p>
+The Butteraugli project is a library to test an image's Psychovisual Error
+Threshold: the point at which a viewer starts to notice image degradation. In
+other words, this project attempts to quantify how distorted your compressed
+image is.
+</p>
+
+<p>
+Butteraugli allows you to define a goal for visual quality, and then run PNG,
+JPG, WebP lossy, and WebP lossless compressions. You can then choose the image
+that is the best balance of file size and Butteraugli level. Figure 7 shows an
+example of how Butteraugli was used to find the minimal JPG quality level
+before the visual distortion was high enough for a user could perceive a
+problem; the result is a roughly 65% reduction in file size.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/moarparrots.png">
+ <p class="img-caption">
+Figure 7. An image before and after application of Butteraugli technology.
+ </p>
+
+<p>
+Butteraugli allows you to proceed based on either output or input. That is, you
+can look for the lowest quality setting before a user perceives noticeable
+distortion in the resulting image, or you can iteratively set image-distortion
+levels to learn their associated quality levels.
+</p>
+
+<h2 id="sizes">Serving Sizes</h2>
+
+<p>
+It is tempting to keep only a single resolution of an image on a server. When a
+device accesses the image, the server serves it at that one resolution and
+leaves downscaling to the device.
+</p>
+
+<p>
+This solution is convenient for the developer, but potentially painful for the
+user, because the solution forces the user to download much more data than they
+need.
+
+You should instead store multiple sizes of images, and serve the size that is
+most appropriate for a particular use case. For example, for a thumbnail,
+serving an actual thumbnail image instead of serving and downscaling a
+full-size version consumes much less network bandwidth
+</p>
+
+</p>
+This approach is good for download speed, and is less costly for users who may
+be using limited or metered data plans. Proceeding like this also results in
+the image's taking less space on the device and in main memory. In the
+case of large images, such as 4K ones, this approach also saves the device
+from having to resize images before loading them.
+</p>
+
+<p>
+Implementing this approach requires that you have a backend image service to
+provide images at various resolutions with proper caching. There are existing
+services that can provide help with this task. For example,
+<a href="https://cloud.google.com/appengine/">App Engine</a> comes
+with image resizing functionality already installed.
+</p>
diff --git a/docs/html/topic/performance/power/battery-historian.jd b/docs/html/topic/performance/power/battery-historian.jd
new file mode 100644
index 0000000..79ea59d
--- /dev/null
+++ b/docs/html/topic/performance/power/battery-historian.jd
@@ -0,0 +1,247 @@
+page.title=Analyzing Power Use with Battery Historian
+page.metaDescription=Improve network performance by optimizing image size.
+
+meta.tags="power"
+page.tags="power"
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+ <ol>
+ <li>
+ <a href="#sv">System-wide View</a>
+ </li>
+ <li>
+ <a href="#asd">App-Specific Data</a>
+ </li>
+ <li>
+ <a href="#usecases">Other Cases Where Battery Historian Can Help</a>
+ </li>
+ </ol>
+<h2>See also</h2>
+ <ol>
+ <li>
+ <a href="https://github.com/google/battery-historian">Battery Historian
+ on GitHub</a>
+ </li>
+
+ <li>
+ <a href="https://developer.android.com/studio/profile/battery-historian.html">
+ Batterystats and Battery Historian Walkthrough
+ </li>
+
+ <li>
+ <a href="https://youtu.be/VC2Hlb22mZM?list=PLOU2XLYxmsILe6_eGvDN3GyiodoV3qNSC&t=2063"
+ target="_blank">
+ Battery Historian talk at Google I/O 2016</a>
+ </li>
+ </ol>
+ </div>
+</div>
+
+<p>
+The Battery Historian tool provides insight into a device’s battery consumption
+over time. At a system-wide level, the tool visualizes power-related events from
+the system logs in an HTML representation. At an app-specific level, the tool
+provides a variety of data that can help you identify battery-draining app
+behavior.
+</p>
+
+<p>
+This document describes some of the ways you can use Battery Historian
+to learn about battery-consumption patterns. The document begins by explaining
+how to read the system-wide data that Battery Historian reports. Then,
+it presents ways in which you can use Battery Historian to diagnose
+and troubleshoot your own app's behavior related to battery consumption.
+Last, it offers several tips on scenarios in which Battery Historian may be
+particularly useful.
+</p>
+
+<h2 id="sv">System-wide View</h2>
+
+<p>
+The Battery Historian tool provides a system-wide visualization of various
+app and system behaviors, along with their correlation against battery
+consumption over time. This view, shown in Figure 1, can help you
+diagnose and identify power use issues with your app.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/generic-timeline.png">
+ <p class="img-caption">
+<strong>Figure 1.</strong>
+Battery Historian’s display of system-wide events affecting power
+consumption.
+ </p>
+
+<p>
+Of particular interest in this figure is the black, horizontal, downward trend
+line representing Battery Level, measured on the y-axis. For example, at the
+very beginning of the Battery Level line, at approximately 6:50 AM, the
+visualization shows a relatively steep drop in battery level.
+</p>
+
+<p>
+Figure 2 provides a close-up of that part of the display.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/s-generic-closeup.png">
+ <p class="img-caption">
+<strong>Figure 2.</strong>
+A close-up of the Battery Historian timeline from roughly 6:50 AM to 7:20 AM.
+ </p>
+
+<p>
+At the very beginning of the Battery Level line, as battery decline steeply,
+the display shows three things happening: The CPU is running, an app has
+acquired a wakelock, and the screen is on. In this way, Battery Historian helps
+you understand what events are happening when battery consumption is high. You
+can then target these behaviors in your app and investigate whether there are
+related optimizations you can make.
+</p>
+
+<p>
+The system-wide visualization can provide other clues, as well. For instance, if
+it shows that the mobile radio is frequently being turned off and on, there may
+be an opportunity to optimize this behavior through <a href=”intelligent
+scheduling page”>intelligent scheduling APIs</a> such as JobScheduler or
+Firebase Job Dispatcher.
+</p>
+
+<p>
+The next section explains how to investigate behavior and events specific to
+your own app.
+</p>
+
+<p>
+<h2 id="asd">App-Specific Data</h2>
+</p>
+
+<p>
+In addition to the macro-level data provided by the system-wide view, Battery
+Historian also provides tables and some visualization of data specific to each
+app running on your device. The tabular data includes:
+</p>
+
+<ul>
+ <li>The app’s estimated power use on the device.</li>
+ <li>Network information.</li>
+ <li>Wakelocks.</li>
+ <li>Services.</li>
+ <li>Process info.</li>
+</ul>
+
+<p>
+The tables provide two dimensions of data about your app. First, you can look
+up where your app’s power usage ranks compared to other apps. To do so, click
+<em>Device Power Estimates</em> table under <em>Tables</em>. This example
+examines a fictional app called Pug Power.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/app-rankings.png">
+ <p class="img-caption">
+<strong>Figure 3.</strong> Investigating which apps consume the most power.
+ </p>
+
+<p>
+The table in Figure 3 reveals that Pug Power is the ninth biggest consumer of
+battery power on this device, and the third biggest app that is not part of the
+OS. This data suggests that this app bears deeper investigation.
+</p>
+
+<p>
+To look up the data for a specific app, enter its package name into the lower
+of the two dropdown menus under <em>App Selection</em>, located under the left
+side of the visualization.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/dropdown.png">
+ <p class="img-caption">
+<strong>Figure 4.</strong> Entering a specific app whose data to view.
+ </p>
+
+<p>
+When you select a specific app, the following data visualization categories
+change to display app-specific data instead of system-wide data:
+</p>
+
+<ul>
+ <li>SyncManager.</li>
+ <li>Foreground process.</li>
+ <li>Userspace Wakelock.</li>
+ <li>Top app.</li>
+ <li>JobScheduler.</li>
+ <li>Activity Manager Proc.</li>
+</ul>
+
+The SyncManager and JobScheduler visualizations immediately make it obvious if
+your app performs syncs and executes jobs more frequently than necessary. In
+doing so, they can quickly reveal an opportunity to optimize your app’s
+behavior for improved battery performance.
+
+<p>
+You can also obtain one more piece of app-specific visualization data,
+<em>Userspace Wakelock</em>. To include this information in the bug report,
+enter the following command in your terminal window:
+</p>
+
+<pre>
+$ adb shell dumpsys batterystats --enable full-wake-history
+</pre>
+
+<p class="note">
+<strong>Note:</strong> From Android 6.0 (API level 23), the platform includes
+Doze functionality, which imposes certain optimizations on apps. For example,
+Doze batches jobs to take place during brief maintenance windows, regardless of
+how JobScheduler has scheduled them.
+</p>
+
+<p>
+Figures 5 and 6 show data for Pug Power: Figure 5
+shows the visualization of
+the app-specific data, and Figure 6 shows the corresponding tabular data.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/pug-visualization.png">
+ <p class="img-caption">
+<strong>Figure 5.</strong> Visualization of data for fictional app Pug Power.
+ </p>
+
+ <img src="{@docRoot}topic/performance/images/pugspecificdata.png">
+ <p class="img-caption">
+<strong>Figure 6.</strong> Tabular data for the fictional Pug Power app.
+ </p>
+
+<p>
+A look at the visualization does not show anything immediately obvious.
+The JobScheduler line shows that the app has no jobs scheduled. The SyncManager
+line shows that the app has not performed any syncs.
+</p>
+
+<p>
+However, examination of the <em>Wakelocks</em> segment of the tabular data
+reveals that Pug Power acquires wakelocks totaling over an hour. This unusual
+and costly behavior can account for the app’s high level of power consumption.
+This piece of information helps the developer target an area where optimization
+is likely to greatly help. In this case, why does the app acquire so much
+wakelock time, and how can the developer ameliorate this behavior?
+</p>
+
+<h2 id="usecases">Other Cases Where Battery Historian Can Help</h2>
+
+<p>
+There are many other cases in which Battery Historian can help you diagnose
+opportunities for improving battery behavior. For example, Battery Historian
+can tell you if your app is:
+</p>
+
+<ul>
+ <li>Firing wakeup alarms overly frequently (every 10 seconds or less).</li>
+ <li>Continuously holding a GPS lock.</li>
+ <li>Scheduling jobs every 30 seconds or less.</li>
+ <li>Scheduling syncs every 30 seconds or less.</li>
+ <li>Using the cellular radio more frequently than you expect.</li>
+</ul>
+
diff --git a/docs/html/topic/performance/power/index.jd b/docs/html/topic/performance/power/index.jd
new file mode 100644
index 0000000..88addce
--- /dev/null
+++ b/docs/html/topic/performance/power/index.jd
@@ -0,0 +1,125 @@
+page.title=Optimizing for Battery Life
+page.metaDescription=Learn how to help your app go easier on the battery.
+
+meta.tags="performance"
+page.tags="performance"
+
+@jd:body
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>
+ In this document
+ </h2>
+ <ol>
+ <li>
+ <a href="#lazy">Lazy First</a>
+ </li>
+ <li>
+ <a href="#features">Platform Features</a>
+ </li>
+ <li>
+ <a href="#toolery">Tooling</a>
+ </li>
+ </ol>
+ </div>
+</div>
+
+<p>Battery life is the single most important aspect of the mobile user
+experience. A device without power offers no functionality at all.
+For this reason, it is critically important that apps be as respectful of
+battery life as possible.</p>
+
+<p>There are three important things to keep in mind in keeping your app
+power-thrifty:</p>
+<ul>
+<li>Make your apps <em>Lazy First</em>.</li>
+<li>Take advantage of platform features that can help manage your app's battery
+consumption.</li>
+<li>Use tools that can help you identify battery-draining culprits.</li>
+</ul>
+
+<h2 id="lazy">Lazy First</h2>
+
+<p>Making your app Lazy First means looking for ways to reduce and optimize
+operations that are particularly battery-intensive. The core questions
+underpinning Lazy First design are:
+
+<ul>
+
+ <li><strong>Reduce:</strong> Are there redundant operations your app can cut
+out? For example, can it cache downloaded data instead of repeatedly waking
+ up the radio to re-download the data?</li>
+
+ <li><strong>Defer:</strong> Does an app need to perform an action right
+ away? For example,
+ can it wait until the device is charging before it backs data up to the
+ cloud?</li>
+
+ <li><strong>Coalesce:</strong> Can work be batched, instead of putting the
+ device
+ into an active state many times? For example, is it really necessary for
+ several dozen apps to each turn on the radio at separate times to send
+ their messages? Can the messages instead be transmitted during a
+ single awakening of the radio?</li>
+</ul>
+
+<p>
+You should ask these questions when it comes to using the CPU,
+the radio, and the screen. Lazy First design is often a good way
+to tame these battery killers.
+</p>
+
+<p>
+To help you achieve these and other efficiencies, the Android platform
+provides a number of features to help maximize battery life.
+</p>
+
+<h2 id="features">Platform Features</h2>
+
+<p>
+Broadly speaking, the Android platform provides two categories of help
+for you to optimize your app's battery use. First, it provides several
+APIs that you can implement in your app. You can learn more about these APIs in
+<a href="/topic/performance/scheduling.html">Intelligent Job Scheduling</a>
+and <a href="/performance/power/network/index.html">
+Network Use and Battery Consumption</a>.
+</p>
+
+<p>
+There are also internal mechanisms in the platform to help conserve
+battery life. While they are not APIs that you implement programmatically,
+you should still be aware of them so that your app can leverage them
+successfully. For more information, see
+<a href="/training/monitoring-device-state/doze-standby.html">Doze and
+App Standby</a>.</p>
+
+<p>
+You can get even more benefit out of these features by using the tools
+available for the platform to discover the parts of your app that consume
+the most power. Finding what to target is a big step toward
+successful optimization.
+</p>
+
+<h2 id ="toolery">Tooling</h2>
+
+<p>There are tools for Android, including
+<a href="/studio/profile/dev-options-rendering.html">Profile GPU Rendering</a>
+and <a class="external-link"
+href="https://github.com/google/battery-historian">Battery Historian</a>
+to help you identify areas that you can optimize for better battery life.
+Take advantage of these tools to target areas where you can apply the
+principles of Lazy First.
+</p>
+
+<section class="dac-section dac-small" id="latest-games"><div class="wrap">
+ <h2 class="norule" style="margin:0 0">More resources</h2>
+ <div class="resource-widget resource-flow-layout col-16"
+ data-query="collection:develop/performance/landing"
+ data-sortOrder="random"
+ data-cardSizes="6x6"
+ data-maxResults="24"
+ data-items-per-page="24"
+ data-initial-results="3"></div>
+ </div>
+</section>
diff --git a/docs/html/topic/performance/rendering/index.jd b/docs/html/topic/performance/rendering/index.jd
new file mode 100644
index 0000000..1b16df0
--- /dev/null
+++ b/docs/html/topic/performance/rendering/index.jd
@@ -0,0 +1,60 @@
+page.title=Rendering
+page.article=true
+
+page.tags=battery
+page.metaDescription=Learn how to optimize your app's rendering performance.
+
+@jd:body
+
+
+<iframe width="448" height="252"
+ src="//www.youtube.com/embed/wIy8g8yNhNk?autohide=1&showinfo=0"
+ frameborder="0" allowfullscreen=""
+ style="float: right; margin: 0 0 20px 20px;"></iframe>
+
+<p>
+ A key aspect of your app that influences your users' perception of quality is
+ the smoothness with which it renders images and text to the screen. It is
+ important to avoid jank and sluggish responsiveness when your app is drawing
+ to the screen.
+</p>
+
+<p>
+ This section helps you learn several ways to optimize your app's rendering
+ performance: reducing overdraw, optimizing view hierarchies, and taking
+ advantage of the Profile GPU tool.
+</p>
+
+<h2>Rendering Actions</h2>
+
+<dl>
+ <dt>
+ <strong><a href="overdraw.html">
+ Reducing Overdraw</a></strong>
+ </dt>
+ <dd>
+ Minimize the number of times you app redraws the same pixel in a single
+ frame.
+ </dd>
+
+ <dt>
+ <strong><a href="optimizing-view-hierarchies.html">
+ Performance and View Hierarchies</a></strong>
+ </dt>
+ <dd>
+ Make sure your layout and measurement are executing efficiently, and
+ avoid double taxation.
+ </dd>
+
+
+ <dt>
+ <strong><a href="profile-gpu.html">
+ Analyzing with Profile GPU Rendering</a></strong>
+ </dt>
+ <dd>
+ Take advantage of this on-device tool to identify bottlenecks that
+ may be slowing your app's rendering down.
+ </dd>
+
+
+</dl>
diff --git a/docs/html/topic/performance/optimizing-view-hierarchies.jd b/docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd
similarity index 100%
rename from docs/html/topic/performance/optimizing-view-hierarchies.jd
rename to docs/html/topic/performance/rendering/optimizing-view-hierarchies.jd
diff --git a/docs/html/topic/performance/rendering/overdraw.jd b/docs/html/topic/performance/rendering/overdraw.jd
new file mode 100644
index 0000000..c1feff5
--- /dev/null
+++ b/docs/html/topic/performance/rendering/overdraw.jd
@@ -0,0 +1,197 @@
+page.title=Reducing Overdraw
+page.metaDescription=Improve performance by reducing unnecessary rendering.
+
+meta.tags="performance"
+page.tags="performance"
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+ <ol>
+
+ <li>
+ <a href="#understanding">Understanding Overdraw</a>
+ </li>
+ <li>
+ <a href="#finding">Finding Overdraw Problems</a>
+ </li>
+ <li>
+ <a href="#fixing">Fixing Overdraw</a>
+ </li>
+ </ol>
+ </div>
+</div>
+
+<p>
+An app may draw the same pixel more than once within a single frame, an event
+called <em>overdraw</em>. Overdraw is usually unnecessary, and best
+eliminated. It manifests itself as a performance problem by wasting GPU time to
+render pixels that don't contribute to what the user sees on the screen.
+</p>
+
+<p>
+This document explains overdraw: what it is, how to diagnose it, and actions you
+can take to eliminate or mitigate it.
+</p>
+
+<h2 name="understanding">Understanding Overdraw</h2>
+
+<p>
+Overdraw refers to the system's drawing a pixel on the screen multiple times
+in a single frame of rendering. For example, if we have a bunch of stacked UI
+cards, each card hides a portion of the one below it.
+</p>
+
+<p>
+However, the system still needs to draw even the hidden portions of the cards
+in the stack. This is because stacked cards are rendered according to the
+<a class="external-link"
+href="https://en.wikipedia.org/wiki/Painter%27s_algorithm">painter's
+algorithm</a>: that is, in back-to-front order.
+This sequence of rendering allows the system to apply proper alpha blending to
+translucent objects such as shadows.
+</p>
+
+<h2 name="finding">Finding Overdraw Problems</h2>
+
+<p>
+The platform offers several tools to help you determine if overdraw is
+affecting your app's performance. These tools are available right on the device,
+and accessible by turning on <strong>Developer Settings</strong></a> under
+<em>Settings</em>. For more information about device developer settings, see
+<a href="/studio/run/device.html#developer-device-options">Run Apps on a
+Hardware Device</a>.
+</p>
+
+<h3 id="dgot">Debug GPU overdraw tool</h3>
+
+<p>
+The Debug GPU Overdraw tool uses color-coding to show the number of times your
+app draws each pixel on the screen. The higher this count, the
+more likely it is that overdraw affects your app's performance.
+</p>
+
+<p>
+For more information on how to use the tool, refer to the related
+<a href="/studio/profile/dev-options-overdraw.html">walkthrough</a>
+and
+<a href="https://io2015codelabs.appspot.com/codelabs/android-performance-debug-gpu-overdraw#1">
+codelab</a>.
+</p>
+
+<h3 id="pgrt">Profile GPU rendering tool</h3>
+
+<p>
+The Profile GPU Rendering tool displays, as a scrolling histogram, the time
+each stage of the rendering pipeline takes to display a single frame. The
+<em>Process</em> part of each bar, indicated in orange, shows when the system
+is swapping buffers; this metric provides important clues about overdraw.
+</p>
+
+<p>
+On less performant GPUs, available fill-rate (the speed at which the GPU can
+fill the frame buffer) can be quite low. As the number of
+pixels required to draw a frame increases, the GPU may take longer to process
+new commands, and ask the rest of the system to wait until it can catch up.
+The <em>Process</em> bar shows that this spike happens as the GPU gets
+overwhelmed trying to draw pixels as fast as possible. Issues other than
+raw numbers of pixels may also cause this metric to spike. For example,
+if the Debug GPU Overdraw tool shows heavy overdraw and <em>Process</em> spikes,
+there's likely an issue with overdraw.
+</p>
+
+<p class="note"><strong>Note: </strong>The
+<a href="https://developer.android.com/studio/profile/dev-options-rendering.html">
+Profile GPU Rendering</a> tool does not
+work with apps that use the NDK. This is because the system pushes framework
+messages to the background whenever OpenGL takes a full-screen context. In
+such cases, you may find a profiling tool provided by the GPU manufacturer
+helpful.</p>
+
+<h2 name="fixing">Fixing Overdraw</h2>
+
+<p>
+There are several strategies you can pursue to reduce or eliminate overdraw:
+</p>
+
+<ul>
+ <li>Removing unneeded backgrounds in layouts.</li>
+ <li>Flattening the view hierarchy.</li>
+ <li>Reducing transparency.</li>
+</ul>
+
+<p>
+This section provides information about each of these approaches.
+</p>
+
+<h3 id="rubil">Removing unneeded backgrounds in layouts</h3>
+
+<p>
+By default, a layout does not have a background, which means it does not render
+anything directly by itself. When layouts do have backgrounds, however, they may
+contribute to overdraw.
+</p>
+
+<p>
+Removing unnecessary backgrounds is a quick way of improving rendering
+performance. An unnecessary background may never be visible because it's
+completely covered by everything else the app is drawing on top of that
+view. For example, the system may entirely cover up a parent's
+background when it draws child views on top of it.
+</p>
+
+<p>
+To find out why you're overdrawing, walk through the hierarchy in
+the <a href="/studio/profile/hierarchy-viewer.html">Hierarchy Viewer</a> tool.
+As you do so, look out for any backgrounds you can eliminate because
+they are not visible to the user. Cases where many containers share a
+common background color offer another opportunity to eliminate unneeded
+backgrounds: You can set the window background to the main background color
+of your app, and leave all of the containers above it with no background values
+defined.
+</p>
+
+<h3 id="fvh">Flattening view hierarchy</h3>
+
+<p>
+Modern layouts make it easy to stack and layer views to produce beautiful
+design. However, doing so can degrade performance by resulting in overdraw,
+especially in scenarios where each stacked view object is opaque, requiring the
+drawing of both seen and unseen pixels to the screen.
+</p>
+
+<p>
+If you encounter this sort of issue, you may be able to improve performance by
+optimizing your view hierarchy to reduce the number of overlapping UI objects.
+For more information about how to accomplish this, see
+<a href="/topic/performance/optimizing-view-hierarchies.html">Optimizing View
+Hierarchies</a>.
+</p>
+
+<h3 id="rt">Reducing transparency</h3>
+
+<p>
+Rendering of transparent pixels on screen, known as alpha rendering, is a key
+contributor to overdraw. Unlike standard overdraw,
+in which the system completely hides existing drawn pixels by drawing
+opaque pixels on top of them, transparent
+objects require existing pixels to be drawn first, so that the right blending
+equation can occur. Visual effects like transparent animations, fade-outs, and
+drop shadows all involve some sort of transparency, and can therefore contribute
+significantly to overdraw. You can improve overdraw in these situations by
+reducing the number of transparent objects you render. For example, you can get
+gray text by drawing black text in a {@link android.widget.TextView} with a
+translucent alpha value set on it. But you can get the same effect with far
+better performance by simply drawing the text in gray.
+</p>
+
+<p>
+To learn more about performance costs that transparency imposes throughout the
+entire drawing pipeline, watch the video
+<a href="https://www.youtube.com/watch?v=wIy8g8yNhNk&index=46&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">
+Hidden Costs of Transparency</a>.
+</p>
+
diff --git a/docs/html/topic/performance/rendering/profile-gpu.jd b/docs/html/topic/performance/rendering/profile-gpu.jd
new file mode 100644
index 0000000..fc98777
--- /dev/null
+++ b/docs/html/topic/performance/rendering/profile-gpu.jd
@@ -0,0 +1,406 @@
+page.title=Analyzing with Profile GPU Rendering
+page.metaDescription=Use the Profile GPU tool to help you optimize your app's rendering performance.
+
+meta.tags="power"
+page.tags="power"
+
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+ <ol>
+ <li>
+ <a href="#visrep">Visual Representation</a></li>
+ </li>
+
+ <li>
+ <a href="#sam">Stages and Their Meanings</a>
+
+ <ul>
+ <li>
+ <a href="#sv">Input Handling</a>
+ </li>
+ <li>
+ <a href="#asd">Animation</a>
+ </li>
+ <li>
+ <a href="#asd">Measurement/Layout</a>
+ </li>
+ <li>
+ <a href="#asd">Drawing</a>
+ </li>
+ </li>
+ <li>
+ <a href="#asd">Sync/Upload</a>
+ </li>
+ <li>
+ <a href="#asd">Issuing Commands</a>
+ </li>
+ <li>
+ <a href="#asd">Processing/Swapping Buffer</a>
+ </li>
+ <li>
+ <a href="#asd">Miscellaneous</a>
+ </li>
+ </ul>
+ </li>
+ </ol>
+ </div>
+</div>
+
+<p>
+The <a href="/studio/profile/dev-options-rendering.html">
+Profile GPU Rendering</a> tool indicates the relative time that each stage of
+the rendering pipeline takes to render the previous frame. This knowledge
+can help you identify bottlenecks in the pipeline, so that you
+can know what to optimize to improve your app's rendering performance.
+</p>
+
+<p>
+This page briefly explains what happens during each pipeline stage, and
+discusses issues that can cause bottlenecks there. Before reading
+this page, you should be familiar with the information presented in the
+<a href="/studio/profile/dev-options-rendering.html">Profile GPU
+Rendering Walkthrough</a>. In addition, to understand how all of the
+stages fit together, it may be helpful to review
+<a href="https://www.youtube.com/watch?v=we6poP0kw6E&index=64&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE">
+how the rendering pipeline works.</a>
+</p>
+
+<h2 id="#visrep">Visual Representation</h2>
+
+<p>
+The Profile GPU Rendering tool displays stages and their relative times in the
+form of a graph: a color-coded histogram. Figure 1 shows an example of
+such a display.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/bars.png">
+ <p class="img-caption">
+<strong>Figure 1.</strong> Profile GPU Rendering Graph
+ </p>
+
+</p>
+
+<p>
+Each segment of each vertical bar displayed in the Profile GPU Rendering
+graph represents a stage of the pipeline and is highlighted using a specific
+color in
+the bar graph. Figure 2 shows a key to the meaning of each displayed color.
+</p>
+
+ <img src="{@docRoot}topic/performance/images/s-profiler-legend.png">
+ <p class="img-caption">
+<strong>Figure 2.</strong> Profile GPU Rendering Graph Legend
+ </p>
+
+<p>
+Once you understand what each color signfiies,
+you can target specific aspects of your
+app to try to optimize its rendering performance.
+</p>
+
+<h2 id="sam">Stages and Their Meanings</a></h2>
+
+<p>
+This section explains what happens during each stage corresponding
+to a color in Figure 2, as well as bottleneck causes to look out for.
+</p>
+
+
+<h3 id="ih">Input Handling</h3>
+
+<p>
+The input handling stage of the pipeline measures how long the app
+spent handling input events. This metric indicates how long the app
+spent executing code called as a result of input event callbacks.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+High values in this area are typically a result of too much work, or
+too-complex work, occurring inside the input-handler event callbacks.
+Since these callbacks always occur on the main thread, solutions to this
+problem focus on optimizing the work directly, or offloading the work to a
+different thread.
+</p>
+
+<p>
+It’s also worth noting that {@link android.support.v7.widget.RecyclerView}
+scrolling can appear in this phase.
+{@link android.support.v7.widget.RecyclerView} scrolls immediately when it
+consumes the touch event. As a result,
+it can inflate or populate new item views. For this reason, it’s important to
+make this operation as fast as possible. Profiling tools like Traceview or
+Systrace can help you investigate further.
+</p>
+
+<h3 id="at">Animation</h3>
+
+<p>
+The Animations phase shows you just how long it took to evaluate all the
+animators that were running in that frame. The most common animators are
+{@link android.animation.ObjectAnimator},
+{@link android.view.ViewPropertyAnimator}, and
+<a href="/training/transitions/overview.html">Transitions</a>.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+High values in this area are typically a result of work that’s executing due
+to some property change of the animation. For example, a fling animation,
+which scrolls your {@link android.widget.ListView} or
+{@link android.support.v7.widget.RecyclerView}, causes large amounts of view
+inflation and population.
+</p>
+
+<h3 id="ml">Measurement/Layout</h3>
+
+<p>
+In order for Android to draw your view items on the screen, it executes
+two specific operations across layouts and views in your view hierarchy.
+</p>
+
+<p>
+First, the system measures the view items. Every view and layout has
+specific data that describes the size of the object on the screen. Some views
+can have a specific size; others have a size that adapts to the size
+of the parent layout container
+</p>
+
+<p>
+Second, the system lays out the view items. Once the system calculates
+the sizes of children views, the system can proceed with layout, sizing
+and positioning the views on the screen.
+</p>
+
+<p>
+The system performs measurement and layout not only for the views to be drawn,
+but also for the parent hierarchies of those views, all the way up to the root
+view.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+If your app spends a lot of time per frame in this area, it is
+usually either because of the sheer volume of views that need to be
+laid out, or problems such as
+<a href="/topic/performance/optimizing-view-hierarchies.html#double">
+double taxation</a> at the wrong spot in your
+hierarchy. In either of these cases, addressing performance involves
+<a href="/topic/performance/optimizing-view-hierarchies.html">improving
+the performance of your view hierarchies</a>.
+</p>
+
+<p>
+Code that you’ve added to
+{@link android.view.View#onLayout(boolean, int, int, int, int)} or
+{@link android.view.View#onMeasure(int, int)}
+can also cause performance
+issues. <a href="/studio/profile/traceview.html">Traceview</a> and
+<a href="/studio/profile/systrace.html">Systrace</a> can help you examine
+the callstacks to identify problems your code may have.
+</p>
+
+<h3 id="draw">Drawing</h3>
+
+<p>
+The draw stage translates a view’s rendering operations, such as drawing
+a background or drawing text, into a sequence of native drawing commands.
+The system captures these commands into a display list.
+</p>
+
+<p>
+The Draw bar records how much time it takes to complete capturing the commands
+into the display list, for all the views that needed to be updated on the screen
+this frame. The measured time applies to any code that you have added to the UI
+objects in your app. Examples of such code may be the
+{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()},
+{@link android.view.View#dispatchDraw(android.graphics.Canvas) dispatchDraw()},
+and the various <code>draw ()methods</code> belonging to the subclasses of the
+{@link android.graphics.drawable.Drawable} class.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+In simplified terms, you can understand this metric as showing how long it took
+to run all of the calls to
+{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()}
+for each invalidated view. This
+measurement includes any time spent dispatching draw commands to children and
+drawables that may be present. For this reason, when you see this bar spike, the
+cause could be that a bunch of views suddenly became invalidated. Invalidation
+makes it necessary to regenerate views' display lists. Alternatively, a
+lengthy time may be the result of a few custom views that have some extremely
+complex logic in their
+{@link android.view.View#onDraw(android.graphics.Canvas) onDraw()} methods.
+</p>
+
+<h3 id="su">Sync/Upload</h3>
+
+<p>
+The Sync & Upload metric represents the time it takes to transfer
+bitmap objects from CPU memory to GPU memory during the current frame.
+</p>
+
+<p>
+As different processors, the CPU and the GPU have different RAM areas
+dedicated to processing. When you draw a bitmap on Android, the system
+transfers the bitmap to GPU memory before the GPU can render it to the
+screen. Then, the GPU caches the bitmap so that the system doesn’t need to
+transfer the data again unless the texture gets evicted from the GPU texture
+cache.
+</p>
+
+<p class="note"><strong>Note:</strong> On Lollipop devices, this stage is
+purple.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+All resources for a frame need to reside in GPU memory before they can be
+used to draw a frame. This means that a high value for this metric could mean
+either a large number of small resource loads or a small number of very large
+resources. A common case is when an app displays a single bitmap that’s
+close to the size of the screen. Another case is when an app displays a
+large number of thumbnails.
+</p>
+
+<p>
+To shrink this bar, you can employ techniques such as:
+</p>
+
+<ul>
+ <li>
+Ensuring your bitmap resolutions are not much larger than the size at which they
+will be displayed. For example, your app should avoid displaying a 1024x1024
+image as a 48x48 image.
+ </li>
+
+ <li>
+Taking advantage of {@link android.graphics.Bitmap#prepareToDraw()}
+to asynchronously pre-upload a bitmap before the next sync phase.
+ </li>
+</ul>
+
+<h3 id="ic">Issuing Commands</h3>
+
+<p>
+The <em>Issue Commands</em> segment represents the time it takes to issue all
+of the commands necessary for drawing display lists to the screen.
+</p>
+
+<p>
+For the system to draw display lists to the screen, it sends the
+necessary commands to the GPU. Typically, it performs this action through the
+<a href="/guide/topics/graphics/opengl.html">OpenGL ES</a> API.
+</p>
+
+<p>
+This process takes some time, as the system performs final transformation
+and clipping for each command before sending the command to the GPU. Additional
+overhead then arises on the GPU side, which computes the final commands. These
+commands include final transformations, and additional clipping.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+The time spent in this stage is a direct measure of the complexity and
+quantity of display lists that the system renders in a given
+frame. For example, having many draw operations, especially in cases where
+there's a small inherent cost to each draw primitive, could inflate this time.
+For example:
+</p>
+
+<pre>
+for (int i = 0; i < 1000; i++)
+canvas.drawPoint()
+</pre>
+
+<p>
+is a lot more expensive to issue than:
+</p>
+
+<pre>
+canvas.drawPoints(mThousandPointArray);
+</pre>
+
+<p>
+There isn’t always a 1:1 correlation between issuing commands and
+actually drawing display lists. Unlike <em>Issue Commands</em>,
+which captures the time it takes to send drawing commands to the GPU,
+the <em>Draw</em> metric represents the time that it took to capture the issued
+commands into the display list.
+</p>
+
+<p>
+This difference arises because the display lists are cached by
+the system wherever possible. As a result, there are situations where a
+scroll, transform, or animation requires the system to re-send a display
+list, but not have to actually rebuild it—recapture the drawing
+commands—from scratch. As a result, you can see a high “Issue
+commands” bar without seeing a high <em>Draw commands</em> bar.
+</p>
+
+<h3 id="psb">Processing/Swapping Buffers</h3>
+
+<p>
+Once Android finishes submitting all its display list to the GPU,
+the system issues one final command to tell the graphics driver that it's
+done with the current frame. At this point, the driver can finally present
+the updated image to the screen.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+It’s important to understand that the GPU executes work in parallel with the
+CPU. The Android system issues draw commands to the GPU, and then moves on to
+the next task. The GPU reads those draw commands from a queue and processes
+them.
+</p>
+
+<p>
+In situations where the CPU issues commands faster than the GPU
+consumes them, the communications queue between the processors can become
+full. When this occurs, the CPU blocks, and waits until there is space in the
+queue to place the next command. This full-queue state arises often during the
+<em>Swap Buffers</em> stage, because at that point, a whole frame’s worth of
+commands have been submitted.
+</p>
+
+</p>
+The key to mitigating this problem is to reduce the complexity of work occurring
+on the GPU, in similar fashion to what you would do for the “Issue Commands”
+phase.
+</p>
+
+
+<h3 id="mt">Miscellaneous</h3>
+
+<p>
+In addition to the time it takes the rendering system to perform its work,
+there’s an additional set of work that occurs on the main thread and has
+nothing to do with rendering. Time that this work consumes is reported as
+<em>misc time</em>. Misc time generally represents work that might be occurring
+on the UI thread between two consecutive frames of rendering.
+</p>
+
+<h4>When this segment is large</h4>
+
+<p>
+If this value is high, it is likely that your app has callbacks, intents, or
+other work that should be happening on another thread. Tools such as
+<a href="/studio/profile/traceview.html">Method
+Tracing</a> or <a href="/studio/profile/systrace.html">Systrace</a> can provide
+visibility into the tasks that are running on
+the main thread. This information can help you target performance improvements.
+</p>
diff --git a/docs/html/training/_book.yaml b/docs/html/training/_book.yaml
index e9635be..47862e2 100644
--- a/docs/html/training/_book.yaml
+++ b/docs/html/training/_book.yaml
@@ -438,16 +438,6 @@
path: /training/efficient-downloads/redundant_redundant.html
- title: Modifying Patterns Based on the Connectivity Type
path: /training/efficient-downloads/connectivity_patterns.html
- - title: Backing up App Data to the Cloud
- path: /training/backup/index.html
- path_attributes:
- - name: description
- value: How to sync and back up app and user data to remote web services in the cloud and how to restore the data back to multiple devices.
- section:
- - title: Configuring Auto Backup
- path: /training/backup/autosyncapi.html
- - title: Using the Backup API
- path: /training/backup/backupapi.html
- title: Resolving Cloud Save Conflicts
path: /training/cloudsave/conflict-res.html
path_attributes:
@@ -1156,7 +1146,7 @@
value: 维护兼容性
- name: zh-tw-lang
value: 維持相容性
- - title: Selecting Colors with the Palette API
+ - title: Selecting Colors with the Palette API
path: /training/material/palette-colors.html
- title: Best Practices for User Input
@@ -1242,15 +1232,9 @@
path: /training/scheduling/wakelock.html
- title: Scheduling Repeating Alarms
path: /training/scheduling/alarms.html
-
- title: Best Practices for Performance
path: /training/best-performance.html
section:
- - title: Managing Your App's Memory
- path: /training/articles/memory.html
- path_attributes:
- - name: description
- value: How to keep your app's memory footprint small in order to improve performance on a variety of mobile devices.
- title: Performance Tips
path: /training/articles/perf-tips.html
path_attributes:
@@ -1282,23 +1266,6 @@
- name: description
value: How to minimize the amount of power your app requires by adapting to current power conditions and performing power-hungry tasks at proper intervals.
section:
- - title: Reducing Network Battery Drain
- path: /training/performance/battery/network/index.html
- section:
- - title: Collecting Network Traffic Data
- path: /training/performance/battery/network/gather-data.html
- - title: Analyzing Network Traffic Data
- path: /training/performance/battery/network/analyze-data.html
- - title: Optimizing User-Initiated Network Use
- path: /training/performance/battery/network/action-user-traffic.html
- - title: Optimizing App-Initiated Network Use
- path: /training/performance/battery/network/action-app-traffic.html
- - title: Optimizing Server-Initiated Network Use
- path: /training/performance/battery/network/action-server-traffic.html
- - title: Optimizing General Network Use
- path: /training/performance/battery/network/action-any-traffic.html
- - title: Optimizing for Doze and App Standby
- path: /training/monitoring-device-state/doze-standby.html
- title: Monitoring the Battery Level and Charging State
path: /training/monitoring-device-state/battery-monitoring.html
path_attributes:
diff --git a/docs/html/training/articles/memory.jd b/docs/html/training/articles/memory.jd
deleted file mode 100644
index de7af58..0000000
--- a/docs/html/training/articles/memory.jd
+++ /dev/null
@@ -1,740 +0,0 @@
-page.title=Managing Your App's Memory
-page.tags=ram,low memory,OutOfMemoryError,onTrimMemory
-page.article=true
-@jd:body
-
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>In this document</h2>
-<ol class="nolist">
- <li><a href="#Android">How Android Manages Memory</a>
- <ol>
- <li><a href="#SharingRAM">Sharing Memory</a></li>
- <li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li>
- <li><a href="#RestrictingMemory">Restricting App Memory</a></li>
- <li><a href="#SwitchingApps">Switching Apps</a></li>
- </ol>
- </li>
- <li><a href="#YourApp">How Your App Should Manage Memory</a>
- <ol>
- <li><a href="#Services">Use services sparingly</a></li>
- <li><a href="#ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</a></li>
- <li><a href="#ReleaseMemoryAsTight">Release memory as memory becomes tight</a></li>
- <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li>
- <li><a href="#Bitmaps">Avoid wasting memory with bitmaps</a></li>
- <li><a href="#DataContainers">Use optimized data containers</a></li>
- <li><a href="#Overhead">Be aware of memory overhead</a></li>
- <li><a href="#Abstractions">Be careful with code abstractions</a></li>
- <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li>
- <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li>
- <li><a href="#ExternalLibs">Be careful about using external libraries</a></li>
- <li><a href="#OverallPerf">Optimize overall performance</a></li>
- <li><a href="#Proguard">Use ProGuard to strip out any unneeded code</a></li>
- <li><a href="#Zipalign">Use zipalign on your final APK</a></li>
- <li><a href="#AnalyzeRam">Analyze your RAM usage</a></li>
- <li><a href="#MultipleProcesses">Use multiple processes</a></li>
- </ol>
- </li>
-</ol>
-<h2>See Also</h2>
-<ul>
- <li><a href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>
- </li>
-</ul>
-
-</div>
-</div>
-
-
-<p>Random-access memory (RAM) is a valuable resource in any software development environment, but
-it's even more valuable on a mobile operating system where physical memory is often constrained.
-Although Android's Dalvik virtual machine performs routine garbage collection, this doesn't allow
-you to ignore when and where your app allocates and releases memory.</p>
-
-<p>In order for the garbage collector to reclaim memory from your app, you need to avoid
-introducing memory leaks (usually caused by holding onto object references in global members) and
-release any {@link java.lang.ref.Reference} objects at the appropriate time (as defined by
-lifecycle callbacks discussed further below). For most apps, the Dalvik garbage collector takes
-care of the rest: the system reclaims your memory allocations when the corresponding objects leave
-the scope of your app's active threads.</p>
-
-<p>This document explains how Android manages app processes and memory allocation, and how you can
-proactively reduce memory usage while developing for Android. For more information about general
-practices to clean up your resources when programming in Java, refer to other books or online
-documentation about managing resource references. If you’re looking for information about how to
-analyze your app’s memory once you’ve already built it, read <a
-href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
-
-
-
-
-<h2 id="Android">How Android Manages Memory</h2>
-
-<p>Android does not offer swap space for memory, but it does use <a href=
-"http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a> and <a href=
-"http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a>
-(mmapping) to manage memory. This means that any memory you modify—whether by allocating
-new objects or touching mmapped pages—remains resident in RAM and cannot be paged out.
-So the only way to completely release memory from your app is to release object references you may
-be holding, making the memory available to the garbage collector. That is with one exception:
-any files mmapped in without modification, such as code, can be paged out of RAM if the system
-wants to use that memory elsewhere.</p>
-
-
-<h3 id="SharingRAM">Sharing Memory</h3>
-
-<p>In order to fit everything it needs in RAM, Android tries to share RAM pages across processes. It
-can do so in the following ways:</p>
-<ul>
-<li>Each app process is forked from an existing process called Zygote.
-The Zygote process starts when the system boots and loads common framework code and resources
-(such as activity themes). To start a new app process, the system forks the Zygote process then
-loads and runs the app's code in the new process. This allows most of the RAM pages allocated for
-framework code and resources to be shared across all app processes.</li>
-
-<li>Most static data is mmapped into a process. This not only allows that same data to be shared
-between processes but also allows it to be paged out when needed. Example static data include:
-Dalvik code (by placing it in a pre-linked {@code .odex} file for direct mmapping), app resources
-(by designing the resource table to be a structure that can be mmapped and by aligning the zip
-entries of the APK), and traditional project elements like native code in {@code .so} files.</li>
-
-<li>In many places, Android shares the same dynamic RAM across processes using explicitly allocated
-shared memory regions (either with ashmem or gralloc). For example, window surfaces use shared
-memory between the app and screen compositor, and cursor buffers use shared memory between the
-content provider and client.</li>
-</ul>
-
-<p>Due to the extensive use of shared memory, determining how much memory your app is using requires
-care. Techniques to properly determine your app's memory use are discussed in <a
-href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
-
-
-<h3 id="AllocatingRAM">Allocating and Reclaiming App Memory</h3>
-
-<p>Here are some facts about how Android allocates then reclaims memory from your app:</p>
-
-<ul>
-<li>The Dalvik heap for each process is constrained to a single virtual memory range. This defines
-the logical heap size, which can grow as it needs to (but only up to a limit that the system defines
-for each app).</li>
-
-<li>The logical size of the heap is not the same as the amount of physical memory used by the heap.
-When inspecting your app's heap, Android computes a value called the Proportional Set Size (PSS),
-which accounts for both dirty and clean pages that are shared with other processes—but only in an
-amount that's proportional to how many apps share that RAM. This (PSS) total is what the system
-considers to be your physical memory footprint. For more information about PSS, see the <a
-href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating Your
-RAM Usage</a> guide.</li>
-
-<li>The Dalvik heap does not compact the logical size of the heap, meaning that Android does not
-defragment the heap to close up space. Android can only shrink the logical heap size when there
-is unused space at the end of the heap. But this doesn't mean the physical memory used by the heap
-can't shrink. After garbage collection, Dalvik walks the heap and finds unused pages, then returns
-those pages to the kernel using madvise. So, paired allocations and deallocations of large
-chunks should result in reclaiming all (or nearly all) the physical memory used. However,
-reclaiming memory from small allocations can be much less efficient because the page used
-for a small allocation may still be shared with something else that has not yet been freed.</li>
-</ul>
-
-
-<h3 id="RestrictingMemory">Restricting App Memory</h3>
-
-<p>To maintain a functional multi-tasking environment, Android sets a hard limit on the heap size
-for each app. The exact heap size limit varies between devices based on how much RAM the device
-has available overall. If your app has reached the heap capacity and tries to allocate more
-memory, it will receive an {@link java.lang.OutOfMemoryError}.</p>
-
-<p>In some cases, you might want to query the system to determine exactly how much heap space you
-have available on the current device—for example, to determine how much data is safe to keep in a
-cache. You can query the system for this figure by calling {@link
-android.app.ActivityManager#getMemoryClass()}. This returns an integer indicating the number of
-megabytes available for your app's heap. This is discussed further below, under
-<a href="#CheckHowMuchMemory">Check how much memory you should use</a>.</p>
-
-
-<h3 id="SwitchingApps">Switching Apps</h3>
-
-<p>Instead of using swap space when the user switches between apps, Android keeps processes that
-are not hosting a foreground ("user visible") app component in a least-recently used (LRU) cache.
-For example, when the user first launches an app, a process is created for it, but when the user
-leaves the app, that process does <em>not</em> quit. The system keeps the process cached, so if
-the user later returns to the app, the process is reused for faster app switching.</p>
-
-<p>If your app has a cached process and it retains memory that it currently does not need,
-then your app—even while the user is not using it—is constraining the system's
-overall performance. So, as the system runs low on memory, it may kill processes in the LRU cache
-beginning with the process least recently used, but also giving some consideration toward
-which processes are most memory intensive. To keep your process cached as long as possible, follow
-the advice in the following sections about when to release your references.</p>
-
-<p>More information about how processes are cached while not running in the foreground and how
-Android decides which ones
-can be killed is available in the <a href="{@docRoot}guide/components/processes-and-threads.html"
->Processes and Threads</a> guide.</p>
-
-
-
-
-<h2 id="YourApp">How Your App Should Manage Memory</h2>
-
-<p>You should consider RAM constraints throughout all phases of development, including during app
-design (before you begin development). There are many
-ways you can design and write code that lead to more efficient results, through aggregation of the
-same techniques applied over and over.</p>
-
-<p>You should apply the following techniques while designing and implementing your app to make it
-more memory efficient.</p>
-
-
-<h3 id="Services">Use services sparingly</h3>
-
-<p>If your app needs a <a href="{@docRoot}guide/components/services.html">service</a>
-to perform work in the background, do not keep it running unless
-it's actively performing a job. Also be careful to never leak your service by failing to stop it
-when its work is done.</p>
-
-<p>When you start a service, the system prefers to always keep the process for that service
-running. This makes the process very expensive because the RAM used by the service can’t be used by
-anything else or paged out. This reduces the number of cached processes that the system can keep in
-the LRU cache, making app switching less efficient. It can even lead to thrashing in the system
-when memory is tight and the system can’t maintain enough processes to host all the services
-currently running.</p>
-
-<p>The best way to limit the lifespan of your service is to use an {@link
-android.app.IntentService}, which finishes
-itself as soon as it's done handling the intent that started it. For more information, read
-<a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>
-.</p>
-
-<p>Leaving a service running when it’s not needed is <strong>one of the worst memory-management
-mistakes</strong> an Android app can make. So don’t be greedy by keeping a service for your app
-running. Not only will it increase the risk of your app performing poorly due to RAM constraints,
-but users will discover such misbehaving apps and uninstall them.</p>
-
-
-<h3 id="ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</h3>
-
-<p>When the user navigates to a different app and your UI is no longer visible, you should
-release any resources that are used by only your UI. Releasing UI resources at this time can
-significantly increase the system's capacity for cached processes, which has a direct impact on the
-quality of the user experience.</p>
-
-<p>To be notified when the user exits your UI, implement the {@link
-android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback in your {@link
-android.app.Activity} classes. You should use this
-method to listen for the {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN} level,
-which indicates your UI is now hidden from view and you should free resources that only your UI
-uses.</p>
-
-
-<p>Notice that your app receives the {@link android.content.ComponentCallbacks2#onTrimMemory
-onTrimMemory()} callback with {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN}
-only when <em>all the UI components</em> of your app process become hidden from the user.
-This is distinct
-from the {@link android.app.Activity#onStop onStop()} callback, which is called when an {@link
-android.app.Activity} instance becomes hidden, which occurs even when the user moves to
-another activity in your app. So although you should implement {@link android.app.Activity#onStop
-onStop()} to release activity resources such as a network connection or to unregister broadcast
-receivers, you usually should not release your UI resources until you receive {@link
-android.content.ComponentCallbacks2#onTrimMemory onTrimMemory(TRIM_MEMORY_UI_HIDDEN)}. This ensures
-that if the user navigates <em>back</em> from another activity in your app, your UI resources are
-still available to resume the activity quickly.</p>
-
-
-
-<h3 id="ReleaseMemoryAsTight">Release memory as memory becomes tight</h3>
-
-<p>During any stage of your app's lifecycle, the {@link
-android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback also tells you when
-the overall device memory is getting low. You should respond by further releasing resources based
-on the following memory levels delivered by {@link android.content.ComponentCallbacks2#onTrimMemory
-onTrimMemory()}:</p>
-
-<ul>
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_MODERATE}
-<p>Your app is running and not considered killable, but the device is running low on memory and the
-system is actively killing processes in the LRU cache.</p>
-</li>
-
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_LOW}
-<p>Your app is running and not considered killable, but the device is running much lower on
-memory so you should release unused resources to improve system performance (which directly
-impacts your app's performance).</p>
-</li>
-
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_CRITICAL}
-<p>Your app is still running, but the system has already killed most of the processes in the
-LRU cache, so you should release all non-critical resources now. If the system cannot reclaim
-sufficient amounts of RAM, it will clear all of the LRU cache and begin killing processes that
-the system prefers to keep alive, such as those hosting a running service.</p>
-</li>
-</ul>
-
-<p>Also, when your app process is currently cached, you may receive one of the following
-levels from {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}:</p>
-<ul>
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_BACKGROUND}
-<p>The system is running low on memory and your process is near the beginning of the LRU list.
-Although your app process is not at a high risk of being killed, the system may already be killing
-processes in the LRU cache. You should release resources that are easy to recover so your process
-will remain in the list and resume quickly when the user returns to your app.</p>
-</li>
-
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_MODERATE}
-<p>The system is running low on memory and your process is near the middle of the LRU list. If the
-system becomes further constrained for memory, there's a chance your process will be killed.</p>
-</li>
-
-<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE}
-<p>The system is running low on memory and your process is one of the first to be killed if the
-system does not recover memory now. You should release everything that's not critical to
-resuming your app state.</p>
-
-</li>
-</ul>
-
-<p>Because the {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback was
-added in API level 14, you can use the {@link android.content.ComponentCallbacks#onLowMemory()}
-callback as a fallback for older versions, which is roughly equivalent to the {@link
-android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.</p>
-
-<p class="note"><strong>Note:</strong> When the system begins killing processes in the LRU cache,
-although it primarily works bottom-up, it does give some consideration to which processes are
-consuming more memory and will thus provide the system more memory gain if killed.
-So the less memory you consume while in the LRU list overall, the better your chances are
-to remain in the list and be able to quickly resume.</p>
-
-
-
-<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3>
-
-<p>As mentioned earlier, each Android-powered device has a different amount of RAM available to the
-system and thus provides a different heap limit for each app. You can call {@link
-android.app.ActivityManager#getMemoryClass()} to get an estimate of your app's available heap in
-megabytes. If your app tries to allocate more memory than is available here, it will receive an
-{@link java.lang.OutOfMemoryError}.</p>
-
-<p>In very special situations, you can request a larger heap size by setting the <a
-href="{@docRoot}guide/topics/manifest/application-element.html#largeHeap">{@code largeHeap}</a>
-attribute to "true" in the manifest <a
-href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a>
-tag. If you do so, you can call {@link
-android.app.ActivityManager#getLargeMemoryClass()} to get an estimate of the large heap size.</p>
-
-<p>However, the ability to request a large heap is intended only for a small set of apps that can
-justify the need to consume more RAM (such as a large photo editing app). <strong>Never request a
-large heap simply because you've run out of memory</strong> and you need a quick fix—you
-should use it only when you know exactly where all your memory is being allocated and why it must
-be retained. Yet, even when you're confident your app can justify the large heap, you should avoid
-requesting it to whatever extent possible. Using the extra memory will increasingly be to the
-detriment of the overall user experience because garbage collection will take longer and system
-performance may be slower when task switching or performing other common operations.</p>
-
-<p>Additionally, the large heap size is not the same on all devices and, when running on
-devices that have limited RAM, the large heap size may be exactly the same as the regular heap
-size. So even if you do request the large heap size, you should call {@link
-android.app.ActivityManager#getMemoryClass()} to check the regular heap size and strive to always
-stay below that limit.</p>
-
-
-<h3 id="Bitmaps">Avoid wasting memory with bitmaps</h3>
-
-<p>When you load a bitmap, keep it in RAM only at the resolution you need for the current device's
-screen, scaling it down if the original bitmap is a higher resolution. Keep in mind that an
-increase in bitmap resolution results in a corresponding (increase<sup>2</sup>) in memory needed,
-because both the X and Y dimensions increase.</p>
-
-<p class="note"><strong>Note:</strong> On Android 2.3.x (API level 10) and below, bitmap objects
-always appear as the same size in your app heap regardless of the image resolution (the actual
-pixel data is stored separately in native memory). This makes it more difficult to debug the bitmap
-memory allocation because most heap analysis tools do not see the native allocation. However,
-beginning in Android 3.0 (API level 11), the bitmap pixel data is allocated in your app's Dalvik
-heap, improving garbage collection and debuggability. So if your app uses bitmaps and you're having
-trouble discovering why your app is using some memory on an older device, switch to a device
-running Android 3.0 or higher to debug it.</p>
-
-<p>For more tips about working with bitmaps, read <a
-href="{@docRoot}training/displaying-bitmaps/manage-memory.html">Managing Bitmap Memory</a>.</p>
-
-
-<h3 id="DataContainers">Use optimized data containers</h3>
-
-<p>Take advantage of optimized containers in the Android framework, such as {@link
-android.util.SparseArray}, {@link android.util.SparseBooleanArray}, and {@link
-android.support.v4.util.LongSparseArray}. The generic {@link java.util.HashMap}
-implementation can be quite memory
-inefficient because it needs a separate entry object for every mapping. Additionally, the {@link
-android.util.SparseArray} classes are more efficient because they avoid the system's need
-to <acronym title=
-"Automatic conversion from primitive types to object classes (such as int to Integer)"
->autobox</acronym>
-the key and sometimes value (which creates yet another object or two per entry). And don't be
-afraid of dropping down to raw arrays when that makes sense.</p>
-
-
-
-<h3 id="Overhead">Be aware of memory overhead</h3>
-
-<p>Be knowledgeable about the cost and overhead of the language and libraries you are using, and
-keep this information in mind when you design your app, from start to finish. Often, things on the
-surface that look innocuous may in fact have a large amount of overhead. Examples include:</p>
-<ul>
-<li>Enums often require more than twice as much memory as static constants. You should strictly
-avoid using enums on Android.</li>
-
-<li>Every class in Java (including anonymous inner classes) uses about 500 bytes of code.</li>
-
-<li>Every class instance has 12-16 bytes of RAM overhead.</li>
-
-<li>Putting a single entry into a {@link java.util.HashMap} requires the allocation of an
-additional entry object that takes 32 bytes (see the previous section about <a
-href="#DataContainers">optimized data containers</a>).</li>
-</ul>
-
-<p>A few bytes here and there quickly add up—app designs that are class- or object-heavy will suffer
-from this overhead. That can leave you in the difficult position of looking at a heap analysis and
-realizing your problem is a lot of small objects using up your RAM.</p>
-
-
-<h3 id="Abstractions">Be careful with code abstractions</h3>
-
-<p>Often, developers use abstractions simply as a "good programming practice," because abstractions
-can improve code flexibility and maintenance. However, abstractions come at a significant cost:
-generally they require a fair amount more code that needs to be executed, requiring more time and
-more RAM for that code to be mapped into memory. So if your abstractions aren't supplying a
-significant benefit, you should avoid them.</p>
-
-
-<h3 id="NanoProto">Use nano protobufs for serialized data</h3>
-
-<p><a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol
-buffers</a> are a language-neutral, platform-neutral, extensible mechanism designed by Google for
-serializing structured data—think XML, but smaller, faster, and simpler. If you decide to use
-protobufs for your data, you should always use nano protobufs in your client-side code. Regular
-protobufs generate extremely verbose code, which will cause many kinds of problems in your app:
-increased RAM use, significant APK size increase, slower execution, and quickly hitting the DEX
-symbol limit.</p>
-
-<p>For more information, see the "Nano version" section in the <a
-href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt"
-class="external-link">protobuf readme</a>.</p>
-
-
-
-<h3 id="DependencyInjection">Avoid dependency injection frameworks</h3>
-
-<p>Using a dependency injection framework such as <a
-href="https://code.google.com/p/google-guice/" class="external-link">Guice</a> or
-<a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a> may be
-attractive because they can simplify the code you write and provide an adaptive environment
-that's useful for testing and other configuration changes. However, these frameworks tend to perform
-a lot of process initialization by scanning your code for annotations, which can require significant
-amounts of your code to be mapped into RAM even though you don't need it. These mapped pages are
-allocated into clean memory so Android can drop them, but that won't happen until the pages have
-been left in memory for a long period of time.</p>
-
-
-<h3 id="ExternalLibs">Be careful about using external libraries</h3>
-
-<p>External library code is often not written for mobile environments and can be inefficient when used
-for work on a mobile client. At the very least, when you decide to use an external library, you
-should assume you are taking on a significant porting and maintenance burden to optimize the
-library for mobile. Plan for that work up-front and analyze the library in terms of code size and
-RAM footprint before deciding to use it at all.</p>
-
-<p>Even libraries supposedly designed for use on Android are potentially dangerous because each
-library may do things differently. For example, one library may use nano protobufs while another
-uses micro protobufs. Now you have two different protobuf implementations in your app. This can and
-will also happen with different implementations of logging, analytics, image loading frameworks,
-caching, and all kinds of other things you don't expect. <a
-href="{@docRoot}tools/help/proguard.html">ProGuard</a> won't save you here because these
-will all be lower-level dependencies that are required by the features for which you want the
-library. This becomes especially problematic when you use an {@link android.app.Activity}
-subclass from a library (which
-will tend to have wide swaths of dependencies), when libraries use reflection (which is common and
-means you need to spend a lot of time manually tweaking ProGuard to get it to work), and so on.</p>
-
-<p>Also be careful not to fall into the trap of using a shared library for one or two features out of
-dozens of other things it does; you don't want to pull in a large amount of code and overhead that
-you don't even use. At the end of the day, if there isn't an existing implementation that is a
-strong match for what you need to do, it may be best if you create your own implementation.</p>
-
-
-<h3 id="OverallPerf">Optimize overall performance</h3>
-
-<p>A variety of information about optimizing your app's overall performance is available
-in other documents listed in <a href="{@docRoot}training/best-performance.html">Best Practices
-for Performance</a>. Many of these documents include optimizations tips for CPU performance, but
-many of these tips also help optimize your app's memory use, such as by reducing the number of
-layout objects required by your UI.</p>
-
-<p>You should also read about <a href="{@docRoot}tools/debugging/debugging-ui.html">optimizing
-your UI</a> with the layout debugging tools and take advantage of
-the optimization suggestions provided by the <a
-href="{@docRoot}tools/debugging/improving-w-lint.html">lint tool</a>.</p>
-
-
-<h3 id="Proguard">Use ProGuard to strip out any unneeded code</h3>
-
-<p>The <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> tool shrinks,
-optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and
-methods with semantically obscure names. Using ProGuard can make your code more compact, requiring
-fewer RAM pages to be mapped.</p>
-
-
-<h3 id="Zipalign">Use zipalign on your final APK</h3>
-
-<p>If you do any post-processing of an APK generated by a build system (including signing it
-with your final production certificate), then you must run <a
-href="{@docRoot}tools/help/zipalign.html">zipalign</a> on it to have it re-aligned.
-Failing to do so can cause your app to require significantly more RAM, because things like
-resources can no longer be mmapped from the APK.</p>
-
-<p class="note"><strong>Note:</strong> Google Play Store does not accept APK files that
-are not zipaligned.</p>
-
-
-<h3 id="AnalyzeRam">Analyze your RAM usage</h3>
-
-<p>Once you achieve a relatively stable build, begin analyzing how much RAM your app is using
-throughout all stages of its lifecycle. For information about how to analyze your app, read <a
-href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
-
-
-
-
-<h3 id="MultipleProcesses">Use multiple processes</h3>
-
-<p>If it's appropriate for your app, an advanced technique that may help you manage your app's
-memory is dividing components of your app into multiple processes. This technique must always be
-used carefully and <strong>most apps should not run multiple processes</strong>, as it can easily
-increase—rather than decrease—your RAM footprint if done incorrectly. It is primarily
-useful to apps that may run significant work in the background as well as the foreground and can
-manage those operations separately.</p>
-
-
-<p>An example of when multiple processes may be appropriate is when building a music player that
-plays music from a service for long period of time. If
-the entire app runs in one process, then many of the allocations performed for its activity UI must
-be kept around as long as it is playing music, even if the user is currently in another app and the
-service is controlling the playback. An app like this may be split into two process: one for its
-UI, and the other for the work that continues running in the background service.</p>
-
-<p>You can specify a separate process for each app component by declaring the <a href=
-"{@docRoot}guide/topics/manifest/service-element.html#proc">{@code android:process}</a> attribute
-for each component in the manifest file. For example, you can specify that your service should run
-in a process separate from your app's main process by declaring a new process named "background"
-(but you can name the process anything you like):</p>
-
-<pre>
-<service android:name=".PlaybackService"
- android:process=":background" />
-</pre>
-
-<p>Your process name should begin with a colon (':') to ensure that the process remains private to
-your app.</p>
-
-<p>Before you decide to create a new process, you need to understand the memory implications.
-To illustrate the consequences of each process, consider that an empty process doing basically
-nothing has an extra memory footprint of about 1.4MB, as shown by the memory information
-dump below.</p>
-
-<pre class="no-pretty-print">
-adb shell dumpsys meminfo com.example.android.apis:empty
-
-** MEMINFO in pid 10172 [com.example.android.apis:empty] **
- Pss Pss Shared Private Shared Private Heap Heap Heap
- Total Clean Dirty Dirty Clean Clean Size Alloc Free
- ------ ------ ------ ------ ------ ------ ------ ------ ------
- Native Heap 0 0 0 0 0 0 1864 1800 63
- Dalvik Heap 764 0 5228 316 0 0 5584 5499 85
- Dalvik Other 619 0 3784 448 0 0
- Stack 28 0 8 28 0 0
- Other dev 4 0 12 0 0 4
- .so mmap 287 0 2840 212 972 0
- .apk mmap 54 0 0 0 136 0
- .dex mmap 250 148 0 0 3704 148
- Other mmap 8 0 8 8 20 0
- Unknown 403 0 600 380 0 0
- TOTAL 2417 148 12480 1392 4832 152 7448 7299 148
-</pre>
-
-<p class="note"><strong>Note:</strong> More information about how to read this output is provided
-in <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating
-Your RAM Usage</a>. The key data here is the <em>Private Dirty</em> and <em>Private
-Clean</em> memory, which shows that this process is using almost 1.4MB of non-pageable RAM
-(distributed across the Dalvik heap, native allocations, book-keeping, and library-loading),
-and another 150K of RAM for code that has been mapped in to execute.</p>
-
-<p>This memory footprint for an empty process is fairly significant and it can quickly
-grow as you start doing work in that process. For
-example, here is the memory use of a process that is created only to show an activity with some
-text in it:</p>
-
-<pre class="no-pretty-print">
-** MEMINFO in pid 10226 [com.example.android.helloactivity] **
- Pss Pss Shared Private Shared Private Heap Heap Heap
- Total Clean Dirty Dirty Clean Clean Size Alloc Free
- ------ ------ ------ ------ ------ ------ ------ ------ ------
- Native Heap 0 0 0 0 0 0 3000 2951 48
- Dalvik Heap 1074 0 4928 776 0 0 5744 5658 86
- Dalvik Other 802 0 3612 664 0 0
- Stack 28 0 8 28 0 0
- Ashmem 6 0 16 0 0 0
- Other dev 108 0 24 104 0 4
- .so mmap 2166 0 2824 1828 3756 0
- .apk mmap 48 0 0 0 632 0
- .ttf mmap 3 0 0 0 24 0
- .dex mmap 292 4 0 0 5672 4
- Other mmap 10 0 8 8 68 0
- Unknown 632 0 412 624 0 0
- TOTAL 5169 4 11832 4032 10152 8 8744 8609 134
-</pre>
-
-<p>The process has now almost tripled in size, to 4MB, simply by showing some text in the UI. This
-leads to an important conclusion: If you are going to split your app into multiple processes, only
-one process should be responsible for UI. Other processes should avoid any UI, as this will quickly
-increase the RAM required by the process (especially once you start loading bitmap assets and other
-resources). It may then be hard or impossible to reduce the memory usage once the UI is drawn.</p>
-
-<p>Additionally, when running more than one process, it's more important than ever that you keep your
-code as lean as possible, because any unnecessary RAM overhead for common implementations are now
-replicated in each process. For example, if you are using enums (though <a
-href="#Overhead">you should not use enums</a>), all of
-the RAM needed to create and initialize those constants is duplicated in each process, and any
-abstractions you have with adapters and temporaries or other overhead will likewise be replicated.</p>
-
-<p>Another concern with multiple processes is the dependencies that exist between them. For example,
-if your app has a content provider that you have running in the default process which also hosts
-your UI, then code in a background process that uses that content provider will also require that
-your UI process remain in RAM. If your goal is to have a background process that can run
-independently of a heavy-weight UI process, it can't have dependencies on content providers or
-services that execute in the UI process.</p>
-
-
-
-
-
-
-
-
-
-
-<!-- THE FOLLOWING IS OVERWHELMING AND NOT NECESSARY FOR MOST APPS, LEAVING OUT FOR NOW
-
-
-<p>You can examine the dependencies between your processes with the command:</p>
-
-<pre class="no-pretty-print">
-adb shell dumpsys activity
-</pre>
-
-<p>This dumps various information about the Activity Manager's state, ending with a list of all
-processes in their memory management order, including the reason each process is at its given
-level. For example, below is a dump with the Music app in the foreground.</p>
-
-<pre class="no-pretty-print">
-ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)
- Process LRU list (sorted by oom_adj):
- PERS # 4: adj=sys /F trm= 0 20674:system/1000 (fixed)
- PERS #39: adj=pers /F trm= 0 20964:com.android.nfc/1027 (fixed)
- PERS # 2: adj=pers /F trm= 0 20959:com.android.phone/1001 (fixed)
- PERS # 1: adj=pers /F trm= 0 20779:com.android.systemui/u0a10057 (fixed)
- Proc #11: adj=fore /FA trm= 0 8663:com.google.android.music:ui/u0a10043 (top-activity)
- Proc #10: adj=fore /F trm= 0 30881:com.google.android.music:main/u0a10043 (provider)
- com.google.android.music/.store.MusicContentProvider<=Proc{8663:com.google.android.music:ui/u0a10043}
- Proc # 6: adj=fore /F trm= 0 21014:com.google.process.gapps/u0a10023 (provider)
- com.google.android.gsf/.settings.GoogleSettingsProvider<=Proc{20935:com.google.process.location/u0a10023}
- Proc #38: adj=vis /F trm= 0 21028:com.android.nfc:handover/1027 (service)
- com.android.nfc/.handover.HandoverService<=Proc{20964:com.android.nfc/1027}
- Proc # 7: adj=vis /B trm= 0 20935:com.google.process.location/u0a10023 (service)
- com.google.android.location/.GeocodeService<=Proc{20674:system/1000}
- Proc # 3: adj=vis /F trm= 0 21225:com.android.bluetooth/1002 (service)
- com.android.bluetooth/.hfp.HeadsetService<=Proc{20674:system/1000}
- Proc # 0: adj=vis /F trm= 0 20908:com.google.android.inputmethod.latin/u0a10035 (service)
- com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME<=Proc{20674:system/1000}
- Proc #34: adj=svc /B trm= 0 16765:com.google.android.apps.currents/u0a10012 (started-services)
- Proc #14: adj=svc /B trm= 0 21148:com.google.android.gms/u0a10023 (started-services)
- Proc #12: adj=home /B trm= 0 20989:com.android.launcher/u0a10036 (home)
- Proc #37: adj=svcb /B trm= 0 15194:com.google.android.apps.googlevoice/u0a10089 (started-services)
- Proc #17: adj=svcb /B trm= 0 24537:android.process.media/u0a10016 (started-services)
- Proc #35: adj=bak /B trm= 0 16087:com.android.defcontainer/u0a10013 (service)
- com.android.defcontainer/.DefaultContainerService<=Proc{16050:com.android.settings/1000}
- Proc #16: adj=bak /B trm= 0 7334:com.google.android.gm/u0a10022 (bg-act)
- Proc #15: adj=bak /B trm= 0 22499:com.google.android.googlequicksearchbox/u0a10060 (bg-act)
- Proc # 9: adj=bak /B trm= 0 20856:com.google.android.gsf.login/u0a10023 (bg-empty)
- Proc #26: adj=bak+1/B trm= 0 9923:com.android.mms/u0a10042 (bg-act)
- Proc #23: adj=bak+1/B trm= 0 16721:com.android.chrome/u0a10010 (bg-act)
- Proc #22: adj=bak+1/B trm= 0 17596:com.android.chrome:sandboxed_process0/u0a10010i33 (service)
- com.android.chrome/org.chromium.content.app.SandboxedProcessService0<=Proc{16721:com.android.chrome/u0a10010}
- Proc #19: adj=bak+1/B trm= 0 17442:com.google.android.youtube/u0a10067 (bg-services)
- Proc #18: adj=bak+2/B trm= 0 16740:com.google.android.apps.plus/u0a10052 (bg-empty)
- Proc #13: adj=bak+2/B trm= 0 7707:com.android.musicfx/u0a10044 (bg-empty)
- Proc #36: adj=bak+3/B trm= 0 16050:com.android.settings/1000 (bg-act)
- Proc #33: adj=bak+3/B trm= 0 16863:com.android.dialer/u0a10015 (bg-act)
-</pre>
-
-
-<p class="note"><strong>Note:</strong> The exact details of what is shown here will vary across
-platform versions as process management policies are tweaked and improved.</p>
-
-
-<p>Details on the highlighted sections are:</p>
-
-<ol>
-<li>Foreground app: This is the current app running in the foreground -- it is in the "fore" memory
-class because it is the top activity on the activity stack.</li>
-
-<li>Persistent processes: These are processes that are part of the core system that must always be
-running.</li>
-
-<li>Dependent process: This shows how the Music app is using two processes. Its UI process has a
-dependency on the "main" process (through a content provider). So while the UI process is in use,
-the main process must also be kept around. This means the app's memory footprint is actually the
-sum of both processes. You will have this kind of connection on a content provider any time you
-have active calls into it or have unclosed cursors or file streams that came from it.</li>
-
-<li>Visible processes: These are processes that count in some way as "visible" to the user. This
-generally means that it is either something the user can literally see (such as a process hosting a
-paused but visible activity that is behind a non-full-screen dialog) or is something the user might
-notice if the process disappeared (such as a foreground service playing music). You should be
-certain that any process you have running at the "visible" level is indeed critical to the user,
-because they are very expensive to the overall RAM load.</li>
-
-<li>Service processes: These are processes running long-term jobs in a service. This level of the
-list is the start of less-critical processes, which the system has some freedom to kill if RAM is
-needed elsewhere. These services are still quite expensive because they can be killed only
-temporarily and the system tries to keep them running whenever possible.</li>
-
-<li>Home process: A special slot for the process that hosts the current Home activity, to try to
-prevent it from being killed as much as possible. Killing this process is much more damaging to the
-user experience than killing other cached processes, because so much user interaction goes through
-home.</li>
-
-<li>Secondary service processes: These are services that have been running for a relatively long time
-and so should be killed more aggressively when RAM is needed elsewhere.</li>
-
-<li>Cached processes: These are cached processes held in the LRU cache, which allow for fast app
-switching and component launching. These processes are not required and the system will kill them
-as needed to reclaim memory. You will often see a process hosting a running service here—this is
-part of a platform policy of allowing very long-running services to drop down into the LRU list and
-eventually be killed. If the service should continue running (as defined by the {@link
-android.app.Service#onStartCommand onStartCommand()} return value, such as {@link
-android.app.Service#START_STICKY}), the the system eventually restarts it. This avoids issues with
-such services having memory leaks that over time reduce the number of regular cached processes that
-can be kept.</li>
-
-</ol>
-
-<p>This numbered list of processes is essentially the LRU list of processes that the framework
-provides to the kernel to help it determine which processes it should kill as it needs more RAM.
-The kernel's out of memory killer will generally begin from the bottom of this list, killing the
-last process and working its way up. It may not do it in exactly this order, as it can also take
-into consideration other factors such as the relative RAM footprint of processes to some degree.</p>
-
-<p>There are many other options you can use with the activity command to analyze further details of
-your app's state—use <code>adb shell dumpsys activity -h</code> for help on its use.</p>
-
--->
diff --git a/docs/html/training/articles/perf-tips.jd b/docs/html/training/articles/perf-tips.jd
index 82de69a..30cab14 100644
--- a/docs/html/training/articles/perf-tips.jd
+++ b/docs/html/training/articles/perf-tips.jd
@@ -28,7 +28,8 @@
performance effects. Choosing the right algorithms and data structures should always be your
priority, but is outside the scope of this document. You should use the tips in this document
as general coding practices that you can incorporate into your habits for general code
-efficiency.</p>
+efficiency.
+</p>
<p>There are two basic rules for writing efficient code:</p>
<ul>
@@ -49,8 +50,7 @@
without.</p>
<p>To ensure your app performs well across a wide variety of devices, ensure
-your code is efficient at all levels and agressively optimize your performance.</p>
-
+your code is efficient at all levels and aggressively optimize your performance.</p>
<h2 id="ObjectCreation">Avoid Creating Unnecessary Objects</h2>
diff --git a/docs/html/training/auto/audio/index.jd b/docs/html/training/auto/audio/index.jd
index 3a1b1e88..6588367 100644
--- a/docs/html/training/auto/audio/index.jd
+++ b/docs/html/training/auto/audio/index.jd
@@ -596,7 +596,7 @@
</a>
<h2 id="support_voice">Support Voice Actions</h2>
-<p>To reduce driver distractions, you can add voice actions in your audio playback app. With voice
+<p>To reduce driver distractions, you must add voice actions in your audio playback app. With voice
action support, users can launch your app and play audio by providing voice input on Auto screens.
If your audio playback app is already active and the user says
<i>“Play a song”</i>, the system starts playing music without requiring the user to look at or touch
diff --git a/docs/html/training/backup/autosyncapi.jd b/docs/html/training/backup/autosyncapi.jd
deleted file mode 100644
index e0df7bb..0000000
--- a/docs/html/training/backup/autosyncapi.jd
+++ /dev/null
@@ -1,370 +0,0 @@
-page.title=Configuring Auto Backup for Apps
-page.tags=backup, marshmallow, androidm
-page.keywords=backup, autobackup
-page.image=images/cards/card-auto-backup_2x.png
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-<h2>This lesson teaches you to</h2>
-<ol>
- <li><a href="#configuring">Configure Data Backup</a></li>
- <li><a href="#previous-androids">Support Lower Versions of Android</a></li>
- <li><a href="#testing">Test Backup Configuration</a></li>
- <li><a href="#issues">Handle Google Cloud Messaging</a></li>
-</ol>
- <h2>You should also read</h2>
- <ul>
- <li><a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li>
- <li><a href="{@docRoot}training/backup/backupapi.html">Using the Backup API</a>
- </li>
- </ul>
-
-</div>
-</div>
-
-<p>
- Users frequently invest time and effort to configure apps just the way they like them. Switching
- to a new device can cancel out all that careful configuration. For apps whose <a href=
- "{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">target SDK version</a>
- is Android 6.0 (API level 23) and higher, devices running Android 6.0 and higher automatically
- back up app data to the cloud. The system performs this automatic backup
- for nearly all app data by default, and does so without your having to write any additional app
- code.
-</p>
-
-<p class="note">
-<strong>Note:</strong> To protect user privacy, the device user must have opted in to Google
-services for Auto Backup to work. The Google services opt-in dialog appears when the user goes
-through the Setup Wizard or configures the first Google account on the device.
-</p>
-
-<p>
- When a user installs your app on
- a new device, or reinstalls your app on one (for example, after a factory reset), the system
- automatically restores the app data from the cloud. This lesson provides information about how to
- configure the Auto Backup for Apps feature, explaining its default behavior and how to
- exclude data that you don't want the system to back up.
-</p>
-
-<p>
- The automatic backup feature preserves the data your app creates on a user device by uploading it
- to the user’s Google Drive account and encrypting it. There is no charge to you or the user for
- data storage, and the saved data does not count towards the user's personal Google Drive quota.
- Each app can store up to 25MB. Once its backed-up data reaches 25MB, the app no longer sends
- data to the cloud. If the system performs a data restore, it uses the last data snapshot that
- the app had sent to the cloud.
-</p>
-
-<p>Automatic backups occur when the following conditions are met:</p>
- <ul>
- <li>The device is idle.</li>
- <li>The device is charging.</li>
- <li>The device is connected to a Wi-Fi network.</li>
- <li>At least 24 hours have elapsed since the last backup.</li>
- </ul>
-</p>
-
-<h2 id="configuring">Configure Data Backup</h2>
-
-<p>
- On devices running Android 6.0 (API level 23) or higher, the default system behavior is to back up
- almost all data that an app creates. The exception is <a href="#auto-exclude">
- automatically excluded data files</a>. This section explains how you can use settings in
- your app <a href="{@docRoot}guide/topics/manifest/manifest-intro.html">manifest</a> to further
- limit and configure what data the system backs up.
-</p>
-
-<h3 id="include-exclude">Including or excluding data</h3>
-
-<p>
- Depending on what data your app needs and how you save it, you may need to set specific
- rules for including or excluding certain files or directories. Auto Backup for Apps
- lets you set these backup rules through the app manifest, in which you specify a backup scheme
- configuration XML file. For example:
-</p>
-
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.my.appexample">
- <uses-sdk android:minSdkVersion="23"/>
- <uses-sdk android:targetSdkVersion="23"/>
- <application ...
-<strong> android:fullBackupContent="@xml/mybackupscheme"></strong>
- </app>
- ...
-</manifest>
-</pre>
-
-<p>
- In this example, the <code>android:fullBackupContent</code> attribute specifies an XML file
- called {@code mybackupscheme.xml}, which resides in the <code>res/xml/</code> directory of your
- app development project. This configuration file contains rules controlling which files are backed
- up. The following example code shows a configuration file that excludes a specific file,
- {@code device_info.db}:
-</p>
-
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<full-backup-content>
- <exclude domain="database" path="device_info.db"/>
-</full-backup-content>
-</pre>
-
-<h3 id="auto-exclude">Automatically excluded data files</h3>
-
-<p>
- Most apps do not need to, and in fact should not, back up all data. For example, the system
- should not back up temporary files and caches. For this reason, the automatic backup
- service excludes certain data files by default:
-</p>
-
-<ul>
- <li>Files in the directories to which the
- {@link android.content.Context#getCacheDir getCacheDir()} and
- {@link android.content.Context#getCodeCacheDir getCodeCacheDir()} methods refer.
- </li>
-
- <li>Files located on external storage, unless they reside in the directory to which the
- {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method refers.
- </li>
-
- <li>Files located in the directory to which the
- {@link android.content.Context#getNoBackupFilesDir getNoBackupFilesDir()} method refers.
- </li>
-</ul>
-<h3>Backup Configuration Syntax</h3>
-
-<p>
- The backup service configuration allows you to specify what files to include or exclude from
- backup. The syntax for the data backup configuration XML file is as follows:
-</p>
-
-<pre>
-<full-backup-content>
- <include domain=["file" | "database" | "sharedpref" | "external" | "root"]
- path="string" />
- <exclude domain=["file" | "database" | "sharedpref" | "external" | "root"]
- path="string" />
-</full-backup-content>
-</pre>
-
-<p>
- The following elements and attributes allow you to specify the files to include in, and exclude
- from, backup:
-</p>
-
-<ul>
- <li>
- <code><include></code>: Specifies a set of resources to
- back up, instead of having the system back up all data in your app by default. If you specify
- an <code><include></code> element, the system backs up <em>only the resources specified</em>
- with this element. You can specify multiple sets of resources to back up by using multiple
- <code><include></code> elements
- </li>
-
- <li>
- <code><exclude></code>: Specifies any data you want the system to exclude
- when it does a full backup. If you target the same set of resources with both the
- <code><include></code> and <code><exclude></code> elements,
- <code><exclude></code> takes precedence.
- </li>
-
- <li>
- <code>domain</code>: Specifies the type of resource you want to include in,
- or exclude from, backup. Valid values for this attribute include:
-
-
-
- <ul>
- <li>
- <code>root</code>: Specifies that the resource is in the app’s root directory.
- </li>
-
- <li>
- <code>file</code>: Specifies a resource in the directory returned by the
- {@link android.content.Context#getFilesDir getFilesDir()} method.
- </li>
-
- <li>
- <code>database</code>: Specifies a database that the
- {@link android.content.Context#getDatabasePath getDatabasePath()} method returns, or that
- the app interacts with via the {@link android.database.sqlite.SQLiteOpenHelper} class.
- </li>
-
- <li>
- <code>sharedpref</code>: Specifies a {@link android.content.SharedPreferences} object
- that the {@link android.content.Context#getSharedPreferences getSharedPreferences()}
- method returns.
- </li>
-
- <li>
- <code>external</code>: Specifies that the resource is in external storage, and corresponds
- to a file in the directory that the
- {@link android.content.Context#getExternalFilesDir getExternalFilesDir()} method returns.
- </li>
- </ul>
- </li>
- <li>
- <code>path</code>: Specifies the file path to a resource that you want to include in, or
- exclude from, backup.
- </li>
-
- </li>
-</ul>
-
-
-<h3 id="disabling">Disabling data backups</h3>
-
-<p>
- You can choose to prevent automatic backups of any of your app data by setting the
- <code>android:allowBackup</code> attribute to <code>false</code> in the {@code app} element of
- your manifest. This setting is illustrated in the following example:
-</p>
-
-<pre>
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="com.my.appexample">
- <uses-sdk android:minSdkVersion="23"/>
- <uses-sdk android:targetSdkVersion="23"/>
- <application ...
-<strong> android:allowBackup="false"></strong>
- </application>
- ...
-</manifest>
-</pre>
-
-<h2 id="previous-androids">Support Lower Versions of Android</h2>
-
-<p>There are two scenarios in which you may also need to support versions of Android lower
-than 6.0 (API level 23): You may be updating your existing app to take advantage of the
-new auto backup functionality in Android 6.0, while wanting
-to continue supporting earlier versions of Android. Or you may be releasing a new app, but
-want to make sure devices running on versions of Android predating 6.0 also have backup
-functionality.</p>
-
-<h3 id="updating">Updating an existing app to support auto backup</h3>
-
-<p>Earlier versions of Android supported a key/value-pair-based backup mechanism, in which the app
-defines a subclass of {@link android.app.backup.BackupAgent} and sets
-<a href="{@docRoot}guide/topics/manifest/application-element.html#agent">
-{@code android:backupAgent}</a> in its
-<a href="{@docRoot}guide/topics/manifest/application-element.html">app manifest</a>. If your app
-used this legacy approach, you can transition to full-data backups by adding the
-{@code android:fullBackupOnly="true"} attribute to the
-<a href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application/>}</a>
-element in the manifest. When running on a device with Android 5.1
-(API level 22) or lower, your app ignores this value in the manifest, and continues performing
-backups in the previous manner.</p>
-
-<p>Even if you’re not using key/value backups, you can still use the approach described above to do
-any custom processing in {@link android.app.Activity#onCreate(android.os.Bundle) onCreate()}
-or {@link android.app.backup.BackupAgent#onFullBackup onFullBackup()}. You can also use that
-approach to receive a notification when a restore operation happens in
-{@link android.app.backup.BackupAgent#onRestoreFinished onRestoreFinished()}. If you want to retain
-the system's default implementation of
-<a href="#include-exclude">XML include/exclude rules handling</a>, call
-{@link android.app.backup.BackupAgent#onFullBackup super.onFullBackup()}.</p>
-
-<h3 id="lower-versions">Giving your new app support for lower versions of Android</h3>
-
-<p>If you are creating a new app that targets Android 6.0, but you also want to enable cloud backup
-for devices running on Android 5.1 (API level 22) and lower, you must also
-<a href="{@docRoot}training/backup/backupapi.html">implement the Backup API</a>.</p>
-
-<h2 id="testing">Test Backup Configuration</h2>
-
-<p>
- Once you have created a backup configuration, you should test it to make sure your app saves data
- and can restore it properly.
-</p>
-
-
-<h3>Enabling Backup Logging</h3>
-
-<p>
- To help determine how the backup feature is parsing your XML file, enable logging before
- performing a test backup:
-</p>
-
-<pre class="no-pretty-print">
-$ adb shell setprop log.tag.BackupXmlParserLogging VERBOSE
-</pre>
-
-<h3>Testing Backup</h3>
-
-<p>To manually run a backup, first initialize the Backup Manager by executing the following
- command:
-</p>
-
-<pre class="no-pretty-print">
-$ adb shell bmgr run
-</pre>
-
-<p>
- Next, manually back up your application using the following command. Use the
- <code><PACKAGE></code> parameter to specify the package name for your app:
-</p>
-
-<pre class="no-pretty-print">
-$ adb shell bmgr fullbackup <PACKAGE></pre>
-
-
-<h3>Testing restore</h3>
-
-<p>
- To manually initiate a restore after the system has backed up your app data, execute the following
- command, using the <code><PACKAGE></code> parameter to specify the package name for your
- app:
-</p>
-
-<pre class="noprettyprint">
-$ adb shell bmgr restore <PACKAGE>
-</pre>
-
-<p class="warning">
- <b>Warning:</b> This action stops your app and wipes its data before performing the restore
- operation.
-</p>
-
-<p>
- You can test automatic restore for your app by uninstalling and reinstalling your app. The app
- data is automatically restored from the cloud once the app installation is complete.
-</p>
-
-
-<h3>Troubleshooting backups</h3>
-
-<p>
- If backup fails, you can clear the backup data and associated metadata either by turning backup
- off and on in <strong>Settings > Backup</strong>, factory-resetting the device, or
- executing this command:
-</p>
-
-<pre>$ adb shell bmgr wipe <TRANSPORT> <PACKAGE></pre>
-
-<p>
- You must prepend <code>com.google.android.gms</code> to the {@code <TRANSPORT>} value.
- To get the list of <a href="{@docRoot}google/backup/index.html">transports</a>, execute the
- following command:
-</p>
-
-<pre>$ adb shell bmgr list transports</pre>
-
-<h2 id="gcm">Handle Google Cloud Messaging</h2>
-
- <p>
- For apps that use <a href="https://developers.google.com/cloud-messaging/gcm">Google Cloud
- Messaging</a> (GCM) for push notifications, backing up the registration
- token that Google Cloud Messaging registration returned can cause unexpected behavior in
- notifications for the restored app. This is because when a user installs your app on a new device,
- the app must <a href="https://developers.google.com/cloud-messaging/android/client#sample-register">
- query the GCM API for a new registration token</a>. If the old registration is present, because the
- system had backed it up and restored it, the app doesn't seek the new token. To prevent this issue
- from arising, exclude the registration token from the set of backed-up files.
- </p>
diff --git a/docs/html/training/backup/backupapi.jd b/docs/html/training/backup/backupapi.jd
deleted file mode 100644
index 2f3e939..0000000
--- a/docs/html/training/backup/backupapi.jd
+++ /dev/null
@@ -1,200 +0,0 @@
-page.title=Using the Backup API
-parent.title=Backing up App Data to the Cloud
-parent.link=index.html
-
-trainingnavtop=true
-
-next.title=Making the Most of Google Cloud Messaging
-next.link=gcm.html
-
-@jd:body
-
-<div id="tb-wrapper">
- <div id="tb">
- <h2>This lesson teaches you to</h2>
- <ol>
- <li><a href="#register">Register for the Android Backup Service</a></li>
- <li><a href="#manifest">Configure Your Manifest</a></li>
- <li><a href="#agent">Write Your Backup Agent</a></li>
- <li><a href="#backup">Request a Backup</a></li>
- <li><a href="#restore">Restore from a Backup</a></li>
- </ol>
- <h2>You should also read</h2>
- <ul>
- <li><a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a></li>
- <li><a href="{@docRoot}training/backup/autosyncapi.html">Configuring Auto Backup for Apps</a>
- (Android 6.0 (API level 23) and higher)</li>
- </ul>
- </div>
-</div>
-
-<p>When a user purchases a new device or resets their existing one, they might
-expect that when Google Play restores your app back to their device during the
-initial setup, the previous data associated with the app restores as well. On versions of Android
-prior to 6.0 (API level 23), app data is not restored by default, and all the user's accomplishments
-or settings in your app are lost.</p>
-<p>For situations where the volume of data is relatively light (less than a
-megabyte), like the user's preferences, notes, game high scores or other
-stats, the Backup API provides a lightweight solution. This lesson walks you
-through integrating the Backup API into your application, and restoring data to
-new devices using the Backup API.
-
-<p class="note">
-<strong>Note:</strong> Devices running Android 6.0 and higher
-<a href="{@docRoot}training/backup/autosyncapi.html">automatically back up</a>
-nearly all data by default.
-</p>
-
-<h2 id="register">Register for the Android Backup Service</h2>
-<p>This lesson requires the use of the <a
- href="{@docRoot}google/backup/index.html">Android Backup
- Service</a>, which requires registration. Go ahead and <a
- href="http://code.google.com/android/backup/signup.html">register here</a>. Once
-that's done, the service pre-populates an XML tag for insertion in your Android
-Manifest, which looks like this:</p>
-<pre>
-<meta-data android:name="com.google.android.backup.api_key"
-android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" />
-</pre>
-<p>Note that each backup key works with a specific package name. If you have
-different applications, register separate keys for each one.</p>
-
-
-<h2 id="manifest">Configure Your Manifest</h2>
-<p>Use of the Android Backup Service requires two additions to your application
-manifest. First, declare the name of the class that acts as your backup agent,
-then add the snippet above as a child element of the Application tag. Assuming
-your backup agent is going to be called {@code TheBackupAgent}, here's an example of
-what the manifest looks like with this tag included:</p>
-
-<pre>
-<application android:label="MyApp"
- android:backupAgent="TheBackupAgent">
- ...
- <meta-data android:name="com.google.android.backup.api_key"
- android:value="ABcDe1FGHij2KlmN3oPQRs4TUvW5xYZ" />
- ...
-</application>
-</pre>
-<h2 id="agent">Write Your Backup Agent</h2>
-<p>The easiest way to create your backup agent is by extending the wrapper class
-{@link android.app.backup.BackupAgentHelper}. Creating this helper class is
-actually a very simple process. Just create a class with the same name as you
-used in the manifest in the previous step (in this example, {@code
-TheBackupAgent}),
-and extend {@code BackupAgentHelper}. Then override the {@link
-android.app.backup.BackupAgent#onCreate()}.</p>
-
-<p>Inside the {@link android.app.backup.BackupAgent#onCreate()} method, create a {@link
-android.app.backup.BackupHelper}. These helpers are
-specialized classes for backing up certain kinds of data. The Android framework
-currently includes two such helpers: {@link
-android.app.backup.FileBackupHelper} and {@link
-android.app.backup.SharedPreferencesBackupHelper}. After you create the helper
-and point it at the data you want to back up, just add it to the
-BackupAgentHelper using the {@link android.app.backup.BackupAgentHelper#addHelper(String, BackupHelper) addHelper()}
-method, adding a key which is used to
-retrieve the data later. In most cases the entire
-implementation is perhaps 10 lines of code.</p>
-
-<p>Here's an example that backs up a high scores file.</p>
-
-<pre>
-import android.app.backup.BackupAgentHelper;
-import android.app.backup.FileBackupHelper;
-
-
-public class TheBackupAgent extends BackupAgentHelper {
- // The name of the SharedPreferences file
- static final String HIGH_SCORES_FILENAME = "scores";
-
- // A key to uniquely identify the set of backup data
- static final String FILES_BACKUP_KEY = "myfiles";
-
- // Allocate a helper and add it to the backup agent
- @Override
- void onCreate() {
- FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME);
- addHelper(FILES_BACKUP_KEY, helper);
- }
-}
-</pre>
-<p>For added flexibility, {@link android.app.backup.FileBackupHelper}'s
-constructor can take a variable number of filenames. You could just as easily
-have backed up both a high scores file and a game progress file just by adding
-an extra parameter, like this:</p>
-<pre>
-@Override
- void onCreate() {
- FileBackupHelper helper = new FileBackupHelper(this, HIGH_SCORES_FILENAME, PROGRESS_FILENAME);
- addHelper(FILES_BACKUP_KEY, helper);
- }
-</pre>
-<p>Backing up preferences is similarly easy. Create a {@link
-android.app.backup.SharedPreferencesBackupHelper} the same way you did a {@link
-android.app.backup.FileBackupHelper}. In this case, instead of adding filenames
-to the constructor, add the names of the shared preference groups being used by
-your application. Here's an example of how your backup agent helper might look if
-high scores are implemented as preferences instead of a flat file:</p>
-
-<pre>
-import android.app.backup.BackupAgentHelper;
-import android.app.backup.SharedPreferencesBackupHelper;
-
-public class TheBackupAgent extends BackupAgentHelper {
- // The names of the SharedPreferences groups that the application maintains. These
- // are the same strings that are passed to getSharedPreferences(String, int).
- static final String PREFS_DISPLAY = "displayprefs";
- static final String PREFS_SCORES = "highscores";
-
- // An arbitrary string used within the BackupAgentHelper implementation to
- // identify the SharedPreferencesBackupHelper's data.
- static final String MY_PREFS_BACKUP_KEY = "myprefs";
-
- // Simply allocate a helper and install it
- void onCreate() {
- SharedPreferencesBackupHelper helper =
- new SharedPreferencesBackupHelper(this, PREFS_DISPLAY, PREFS_SCORES);
- addHelper(MY_PREFS_BACKUP_KEY, helper);
- }
-}
-</pre>
-
-<p>You can add as many backup helper instances to your backup agent helper as you
-like, but remember that you only need one of each type. One {@link
-android.app.backup.FileBackupHelper} handles all the files that you need to back up, and one
-{@link android.app.backup.SharedPreferencesBackupHelper} handles all the shared
-preferencegroups you need backed up.
-</p>
-
-
-<h2 id="backup">Request a Backup</h2>
-<p>In order to request a backup, just create an instance of the {@link
-android.app.backup.BackupManager}, and call it's {@link
-android.app.backup.BackupManager#dataChanged()} method.</p>
-
-<pre>
-import android.app.backup.BackupManager;
-...
-
-public void requestBackup() {
- BackupManager bm = new BackupManager(this);
- bm.dataChanged();
-}
-</pre>
-
-<p>This call notifies the backup manager that there is data ready to be backed
-up to the cloud. At some point in the future, the backup manager then calls
-your backup agent's {@link
-android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor, BackupDataOutput,
-ParcelFileDescriptor) onBackup()} method. You can make
-the call whenever your data has changed, without having to worry about causing
-excessive network activity. If you request a backup twice before a backup
-occurs, the backup only occurs once.</p>
-
-
-<h2 id="restore">Restore from a Backup</h2>
-<p>Typically you shouldn't ever have to manually request a restore, as it
-happens automatically when your application is installed on a device. However,
-if it <em>is</em> necessary to trigger a manual restore, just call the
-{@link android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} method.</p>
diff --git a/docs/html/training/backup/index.jd b/docs/html/training/backup/index.jd
deleted file mode 100644
index 4449fde..0000000
--- a/docs/html/training/backup/index.jd
+++ /dev/null
@@ -1,47 +0,0 @@
-page.title=Backing up App Data to the Cloud
-page.tags=cloud,sync,backup
-
-trainingnavtop=true
-startpage=true
-
-@jd:body
-
-<div id="tb-wrapper">
-<div id="tb">
-
-<h2>Dependencies and prerequisites</h2>
-<ul>
- <li>Android 2.2 (API level 8) and higher</li>
-</ul>
-</div>
-</div>
-
-<p>Users often invest significant time and effort creating data and setting
-preferences within apps. Preserving that data for users if they replace a broken
-device or upgrade to a new one is an important part of ensuring a great user
-experience.</p>
-
-<p>This class covers techniques for backing up data to the cloud so that
-users can restore their data when recovering from a data loss (such as a factory
-reset) or installing your application on a new device.</p>
-
-<p>It is important to note that the API for cloud backup changed with the
-release of Android 6.0 (API level 23). For your app to support backup both
-on devices running Android 6.0, and those running Android 5.1 (API level
-22) and lower, you must implement both techniques that this class explains.</p>
-
-<h2>Lessons</h2>
-
-<dl>
- <dt><strong><a href="autosyncapi.html">Configuring Auto Backup for Apps</a></strong></dt>
- <dd>This lesson applies to Android 6.0 (API level 23) and higher. Learn how to accomplish
- seamless app data backup and restore with zero additional lines of application code.</dd>
-</dl>
-
-<dl>
- <dt><strong><a href="backupapi.html">Using the Backup API</a></strong></dt>
- <dd>This lesson applies to Android 5.1 (API level 22) and lower. Learn how to integrate the Backup
- API into your Android app, so all of that app's user data, such as preferences, notes, and high
- scores, updates seamlessly across all devices linked to that Google account.</dd>
-</dl>
-
diff --git a/docs/html/training/best-performance.jd b/docs/html/training/best-performance.jd
index 8ea6fd5..bb88e99 100644
--- a/docs/html/training/best-performance.jd
+++ b/docs/html/training/best-performance.jd
@@ -5,4 +5,9 @@
<p>These classes and articles help you build an app that's smooth, responsive,
-and uses as little battery as possible.</p>
\ No newline at end of file
+and uses as little battery as possible.</p>
+
+<p>Along with this section, you can find additional information about optimizing
+your app in the <a href="/topic/performance/index.html">Performance and
+Power</a> section.</p>
+
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index d0dccba..d2bf881 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -649,25 +649,7 @@
</li>
</ul>
</li>
-
<li class="nav-section">
- <div class="nav-section-header">
- <a href="<?cs var:toroot ?>training/backup/index.html"
- description=
- "How to sync and back up app and user data to remote web services in the
- cloud and how to restore the data back to multiple devices."
- >Backing up App Data to the Cloud</a>
- </div>
- <ul>
- <li><a href="<?cs var:toroot ?>training/backup/autosyncapi.html">
- Configuring Auto Backup
- </a>
- </li>
- <li><a href="<?cs var:toroot ?>training/backup/backupapi.html">
- Using the Backup API
- </a>
- </li>
- </ul>
<li><a href="<?cs var:toroot ?>training/cloudsave/conflict-res.html"
description=
"How to design a robust conflict resolution strategy for apps that save data to the cloud."
@@ -1888,6 +1870,12 @@
>Managing Your App's Memory</a>
</li>
<li>
+ <a href="<?cs var:toroot ?>training/articles/memory-overview.html"
+ description=
+ "How Android manages app process and memory allocation."
+ >Overview of Android Memory Management</a>
+ </li>
+ <li>
<a href="<?cs var:toroot ?>training/articles/perf-tips.html"
description=
"How to optimize your app's performance in various ways to improve its
diff --git a/docs/html/training/wearables/data-layer/messages.jd b/docs/html/training/wearables/data-layer/messages.jd
index ef9bfb1..8c4b730 100644
--- a/docs/html/training/wearables/data-layer/messages.jd
+++ b/docs/html/training/wearables/data-layer/messages.jd
@@ -10,12 +10,6 @@
<li><a href="#SendMessage">Send a Message</a></li>
<li><a href="#ReceiveMessage">Receive a Message</a></li>
</ol>
-<h2>Try it out</h2>
-<ul>
- <li>
- <a href="https://github.com/googlesamples/android-FindMyPhone/" class="external-link">FindMyPhone</a>
- </li>
-</ul>
</div>
</div>
@@ -27,6 +21,7 @@
<li>An arbitrary payload (optional)</li>
<li>A path that uniquely identifies the message's action</li>
</ul>
+
<p>
Unlike with data items, there is no syncing between the handheld and wearable apps.
Messages are a one-way communication mechanism that's good for remote procedure calls (RPC),
@@ -149,11 +144,9 @@
<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>
to detect capability changes, you may want to override the
<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onConnectedNodes(java.util.List<com.google.android.gms.wearable.Node>)"><code>onConnectedNodes()</code></a>
-method to listen to finer-grained connectivity details, such as when a wearable device switches
-from Wi-Fi to a Bluetooth connection to the handset. For an example implementation, see the
-<code>DisconnectListenerService</code> class in the
-<a href="https://github.com/googlesamples/android-FindMyPhone/" class="external-link">FindMyPhone</a>
-sample. For more information on how to listen for important events, see
+method to listen to finer-grained connectivity details, such as when a wearable
+device switches from Wi-Fi to a Bluetooth connection to the handset.
+For more information on how to listen for important events, see
<a href="{@docRoot}training/wearables/data-layer/events.html#Listen">Listen for Data Layer Events</a>.
</p>
diff --git a/docs/html/tv/_project.yaml b/docs/html/tv/_project.yaml
new file mode 100644
index 0000000..d2d41e1
--- /dev/null
+++ b/docs/html/tv/_project.yaml
@@ -0,0 +1,6 @@
+name: "TV"
+home_url: /tv/
+description: "Bring your apps, games, and content to the biggest screen in the house."
+content_license: cc3-apache2
+buganizer_id: 30209417
+parent_project_metadata_path: /about/_project.yaml
diff --git a/docs/html/wear/_project.yaml b/docs/html/wear/_project.yaml
index 2a94274..114cc5b 100644
--- a/docs/html/wear/_project.yaml
+++ b/docs/html/wear/_project.yaml
@@ -3,3 +3,4 @@
description: "Small, powerful devices, worn on the body. Useful information when you need it most."
content_license: cc3-apache2
buganizer_id: 30209417
+parent_project_metadata_path: /about/_project.yaml
diff --git a/docs/html/wear/preview/_project.yaml b/docs/html/wear/preview/_project.yaml
new file mode 100644
index 0000000..4f7083e
--- /dev/null
+++ b/docs/html/wear/preview/_project.yaml
@@ -0,0 +1,6 @@
+name: "Wear Preview"
+home_url: /wear/preview/
+description: "Small, powerful devices, worn on the body. Useful information when you need it most."
+content_license: cc3-apache2
+buganizer_id: 30209417
+parent_project_metadata_path: /wear/_project.yaml
diff --git a/docs/html/wear/preview/downloads.jd b/docs/html/wear/preview/downloads.jd
index 08ed233..bfa384b 100644
--- a/docs/html/wear/preview/downloads.jd
+++ b/docs/html/wear/preview/downloads.jd
@@ -346,7 +346,8 @@
</p>
<p class="warning">
- <strong>Warning:</strong> Installing a system image on a watch removes all data from the
+ <strong>Warning:</strong> Installing a system image on a watch
+ removes all data from the
watch, so you should back up your data first.
</p>
@@ -355,8 +356,7 @@
</h4>
<p>
- From the phone, unpair ("Forget") the watch.
- Then on the watch, enable the Developer Options menu and ADB debugging as
+ On the watch, enable the Developer Options menu and ADB debugging as
follows:
</p>
@@ -365,14 +365,14 @@
</li>
<li>Scroll to the bottom of the menu. If no <strong>Developer
- Options</strong> item is provided, tap <strong>About</strong>.
+ Options</strong> item is provided, tap <strong>System</strong>
+ and then <strong>About</strong>.
</li>
<li>Tap the build number 7 times.
</li>
- <li>From the Settings menu, tap the <strong>Developer Options</strong>
- item.
+ <li>From the Settings menu, tap <strong>Developer Options</strong>.
</li>
<li>Enable ADB debugging.
@@ -418,7 +418,9 @@
</li>
<li>Use the following <a href="{@docRoot}tools/help/adb.html">adb
- command</a> to confirm that the watch is available for flashing:
+ command</a> to confirm that the watch is recognized.
+ You may need to turn ADB debugging off and then on for the watch to
+ be recognized:
<code>adb devices</code>
</li>
@@ -432,11 +434,11 @@
devices, <code>fastboot oem unlock</code>
</li>
- <li>On the watch, select the <strong>Unlock</strong> option.
+ <li>On the watch, select the option to unlock the bootloader.
</li>
- <li>Navigate to the directory where you unzipped the system image in Step
- 1. At the top level of that directory,
+ <li>On your computer, navigate to the directory where you unzipped the
+ system image in Step 1. At the top level of that directory,
execute the <code>flash-all</code> script by typing
<code>flash-all.sh</code> or, in the case of Windows,
<code>flash-all.bat</code>. The following may need to
@@ -449,16 +451,16 @@
Set up the watch
</h4>
- <p>
- After the <code>flash-all</code> script finishes, your watch reboots.
- Only pair the watch with a phone (so you can begin testing the preview)
- by using the instructions in <a href="#set_up_a_phone">Set Up a Phone</a>.
- Additionally, before installing an app, perform the
- following steps on the watch to re-secure the watch's bootloader:
+ <p>
+ After the <code>flash-all</code> script finishes, the watch reboots.
+ Only pair the watch with a phone (so you can begin testing the preview)
+ by using the instructions in <a href="#set_up_a_phone">Set Up a Phone</a>.
+ Additionally, before installing an app, perform the
+ following steps on the watch to re-secure the watch's bootloader:
</p>
<ol>
- <li>Open the Settings menu (on the watch).
+ <li>Open the Settings menu by long-pressing the physical button.
</li>
<li>Scroll to the bottom of the menu and tap <strong>About</strong>.
@@ -467,15 +469,16 @@
<li>Tap the build number 7 times.
</li>
- <li>From the Settings menu, tap the <strong>Developer Options</strong>
- item.
+ <li>From the Settings menu, tap <strong>Developer Options</strong>.
</li>
<li>Enable ADB debugging.
</li>
<li>Connect the watch to your computer and tap <strong>Always allow from
- this computer</strong>.
+ this computer</strong>. (You may need to turn ADB debugging off
+ and then on, to be prompted to always allow ADB debugging from
+ the connected computer.)
</li>
<li>Use the following adb command to start the device in fastboot mode:
@@ -487,8 +490,11 @@
devices, <code>fastboot oem lock</code>
</li>
- <li>On the watch, continue the boot by choosing
- <strong>Start</strong> and touching <strong>'0'</strong>.
+ <li>On the watch, continue the boot as follows:
+ On an LGE Watch Urbane 2nd Edition, choose
+ <strong>Start</strong> and touch <strong>'0'</strong>.
+ On a Huawei Watch, confirm that <strong>Reboot</strong> is chosen and
+ long-press the physical button.
</li>
</ol>
@@ -610,7 +616,8 @@
<p>
After you install the beta version of the companion app on a phone,
- you can pair the phone to the watch:
+ unpair ("Forget") any obsolete watch pairings, if necessary.
+ Then you can pair the phone to a newly-imaged watch:
</p>
<ol>
@@ -626,7 +633,7 @@
the accounts on the phone.
</li>
- <li>Choose a Google account to add and sync to your watch.
+ <li>Choose a Google Account to add and sync to your watch.
</li>
<li>Confirm the screen lock and enter the password to start the copying of
@@ -647,8 +654,19 @@
</h2>
<p>
- To test with the Android Emulator, create a virtual device in Android
- Studio as follows:
+ To test with the Android Emulator,
+ confirm that you have the latest version of the <strong>Android SDK
+ Platform-tools</strong> from the <a href=
+ "{@docRoot}studio/intro/update.html#sdk-manager">SDK Manager</a>.
+ </p>
+
+ <p>
+ After you create a virtual device as described below, follow the steps for
+ <a href="#set_up_a_phone">setting up a phone</a> with the beta version of
+ the Android Wear companion app.
+ </p>
+
+ <p>Create a new virtual device in Android Studio as follows:
</p>
<ol>
@@ -659,8 +677,8 @@
<li>Click <strong>Create Virtual Device</strong>.
</li>
- <li>In the <strong>Category</strong> pane, select Wear and
- choose a hardware profile.
+ <li>In the <strong>Category</strong> pane, select <strong>Wear</strong>
+ and choose a hardware profile.
The Android Wear 2.0 Developer Preview
is only optimized for round devices currently, so we recommend not
using the square or chin profiles for now.
@@ -679,16 +697,68 @@
<li>Verify the configuration of the Android Virtual Device (AVD) and
click <strong>Finish</strong>.
</li>
+
+ <li>Start the emulator by selecting the new virtual device, clicking the
+ <strong>Play</strong> button, and waiting until
+ the emulator initializes and shows the Android Wear home screen.
+ </li>
</ol>
<p>
- You can now test an application with a virtual preview device
+ Pair the phone with the emulator, and sync a Google Account, as follows:
+ </p>
+
+ <ol>
+ <li>Follow the steps for
+ <a href="#set_up_a_phone">setting up a phone</a> with the beta version of
+ the Android Wear companion app.
+ </li>
+
+ <li>On the phone, enable Developer Options and USB Debugging.
+ </li>
+
+ <li>Connect the phone to your computer through USB.
+ </li>
+
+ <li>Forward the AVD's communication port to the connected handheld device
+ (each time the phone is connected):<br>
+ <code>adb -d forward tcp:5601 tcp:5601</code>
+ </li>
+
+ <li>On the phone, in the Android Wear app, begin the standard pairing
+ process. For example, on the Welcome screen, tap the
+ <strong>Set It Up</strong> button.
+ Alternatively, if an existing watch already is paired, in the upper-left
+ drop-down, tap <strong>Add a New Watch</strong>.
+ </li>
+
+ <li>On the phone, in the Android Wear app, tap the
+ Overflow button, and then tap
+ <strong>Pair with Emulator</strong>.
+ </li>
+
+ <li>Tap the Settings icon.
+ </li>
+
+ <li>Under Device Settings, tap <strong>Emulator</strong>.
+ </li>
+
+ <li>Tap <strong>Accounts</strong> and select a Google Account,
+ and follow the steps in the wizard to
+ sync the account with the emulator. If necessary, type the screen-lock
+ device password, and Google Account password, to start the account sync.
+ </li>
+ </ol>
+
+ <p>
+ You can now test an app with a virtual preview device
in the <a href=
"{@docRoot}tools/devices/emulator.html">Android Emulator</a>. For more
information about using virtual devices, see <a href=
- "{@docRoot}tools/devices/managing-avds.html">Managing AVDs with the AVD
- Manager</a>.
+ "{@docRoot}studio/run/managing-avds.html">
+ Create and Manage Virtual Devices</a>.
</p>
+
</div><!-- landing -->
</div><!-- relative wrapper -->
diff --git a/docs/html/wear/preview/features/app-distribution.jd b/docs/html/wear/preview/features/app-distribution.jd
index 319efa6..afc9516 100644
--- a/docs/html/wear/preview/features/app-distribution.jd
+++ b/docs/html/wear/preview/features/app-distribution.jd
@@ -132,6 +132,9 @@
<pre>
android {
+ // Allows you to reference product flavors in your
+ // phone module's build.gradle file
+ publishNonDefault true
...
defaultConfig
{
@@ -148,6 +151,7 @@
minSdkVersion 24
}
}
+}
</pre>
<p>
@@ -158,7 +162,7 @@
<pre>
dependencies {
...
- wearApp project(path: ':wearable', configuration: 'wear1Release')
+ wearApp project(path: ':wear', configuration: 'wear1Release')
}
</pre>
diff --git a/docs/html/wear/preview/support.jd b/docs/html/wear/preview/support.jd
index 7636d86..6006627 100644
--- a/docs/html/wear/preview/support.jd
+++ b/docs/html/wear/preview/support.jd
@@ -319,6 +319,22 @@
</li>
</ul>
+ <h4 id="account">
+ Account sync
+ </h4>
+
+ <ul>
+ <li>Account sync initiated from watch settings may not work reliably.
+ Instead, add accounts from the setup flow of the Android Wear app, or using
+ the Accounts settings for a device from the Android Wear app.
+ </li>
+
+ <li>The list of accounts that can be synced is the same as the list of accounts
+ on the phone. So to add a new account, use the Android settings on the phone,
+ and then proceed to Android Wear app to sync that account.
+ </li>
+ </ul>
+
<h4 id="devices">
Devices
</h4>
diff --git a/graphics/java/android/graphics/Atlas.java b/graphics/java/android/graphics/Atlas.java
deleted file mode 100644
index e0a5345..0000000
--- a/graphics/java/android/graphics/Atlas.java
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-/**
- * @hide
- */
-public class Atlas {
- /**
- * WARNING: These flag values are part of the on-disk configuration information,
- * do not change their values.
- */
-
- /** DELETED: FLAG_ROTATION = 0x01 */
-
- /**
- * This flag indicates whether the packing algorithm should leave
- * an empty 1 pixel wide border around each bitmap. This border can
- * be useful if the content of the atlas will be used in OpenGL using
- * bilinear filtering.
- */
- public static final int FLAG_ADD_PADDING = 0x2;
- /**
- * Default flags: allow rotations and add padding.
- */
- public static final int FLAG_DEFAULTS = FLAG_ADD_PADDING;
-
- /**
- * Each type defines a different packing algorithm that can
- * be used by an {@link Atlas}. The best algorithm to use
- * will depend on the source dataset and the dimensions of
- * the atlas.
- */
- public enum Type {
- SliceMinArea,
- SliceMaxArea,
- SliceShortAxis,
- SliceLongAxis
- }
-
- /**
- * Represents a bitmap packed in the atlas. Each entry has a location in
- * pixels in the atlas and a rotation flag.
- */
- public static class Entry {
- /**
- * Location, in pixels, of the bitmap on the X axis in the atlas.
- */
- public int x;
- /**
- * Location, in pixels, of the bitmap on the Y axis in the atlas.
- */
- public int y;
- }
-
- private final Policy mPolicy;
-
- /**
- * Creates a new atlas with the specified algorithm and dimensions
- * in pixels. Calling this constructor is equivalent to calling
- * {@link #Atlas(Atlas.Type, int, int, int)} with {@link #FLAG_DEFAULTS}.
- *
- * @param type The algorithm to use to pack rectangles in the atlas
- * @param width The width of the atlas in pixels
- * @param height The height of the atlas in pixels
- *
- * @see #Atlas(Atlas.Type, int, int, int)
- */
- public Atlas(Type type, int width, int height) {
- this(type, width, height, FLAG_DEFAULTS);
- }
-
- /**
- * Creates a new atlas with the specified algorithm and dimensions
- * in pixels. A set of flags can also be specified to control the
- * behavior of the atlas.
- *
- * @param type The algorithm to use to pack rectangles in the atlas
- * @param width The width of the atlas in pixels
- * @param height The height of the atlas in pixels
- * @param flags Optional flags to control the behavior of the atlas:
- * {@link #FLAG_ADD_PADDING}, {@link #FLAG_ALLOW_ROTATIONS}
- *
- * @see #Atlas(Atlas.Type, int, int)
- */
- public Atlas(Type type, int width, int height, int flags) {
- mPolicy = findPolicy(type, width, height, flags);
- }
-
- /**
- * Packs a rectangle of the specified dimensions in this atlas.
- *
- * @param width The width of the rectangle to pack in the atlas
- * @param height The height of the rectangle to pack in the atlas
- *
- * @return An {@link Entry} instance if the rectangle was packed in
- * the atlas, or null if the rectangle could not fit
- *
- * @see #pack(int, int, Atlas.Entry)
- */
- public Entry pack(int width, int height) {
- return pack(width, height, null);
- }
-
- /**
- * Packs a rectangle of the specified dimensions in this atlas.
- *
- * @param width The width of the rectangle to pack in the atlas
- * @param height The height of the rectangle to pack in the atlas
- * @param entry Out parameter that will be filled in with the location
- * and attributes of the packed rectangle, can be null
- *
- * @return An {@link Entry} instance if the rectangle was packed in
- * the atlas, or null if the rectangle could not fit
- *
- * @see #pack(int, int)
- */
- public Entry pack(int width, int height, Entry entry) {
- if (entry == null) entry = new Entry();
- return mPolicy.pack(width, height, entry);
- }
-
- private static Policy findPolicy(Type type, int width, int height, int flags) {
- switch (type) {
- case SliceMinArea:
- return new SlicePolicy(width, height, flags,
- new SlicePolicy.MinAreaSplitDecision());
- case SliceMaxArea:
- return new SlicePolicy(width, height, flags,
- new SlicePolicy.MaxAreaSplitDecision());
- case SliceShortAxis:
- return new SlicePolicy(width, height, flags,
- new SlicePolicy.ShorterFreeAxisSplitDecision());
- case SliceLongAxis:
- return new SlicePolicy(width, height, flags,
- new SlicePolicy.LongerFreeAxisSplitDecision());
- }
- return null;
- }
-
- /**
- * A policy defines how the atlas performs the packing operation.
- */
- private static abstract class Policy {
- abstract Entry pack(int width, int height, Entry entry);
- }
-
- /**
- * The Slice algorightm divides the remaining empty space either
- * horizontally or vertically after a bitmap is placed in the atlas.
- *
- * NOTE: the algorithm is explained below using a tree but is
- * implemented using a linked list instead for performance reasons.
- *
- * The algorithm starts with a single empty cell covering the entire
- * atlas:
- *
- * -----------------------
- * | |
- * | |
- * | |
- * | Empty space |
- * | (C0) |
- * | |
- * | |
- * | |
- * -----------------------
- *
- * The tree of cells looks like this:
- *
- * N0(free)
- *
- * The algorithm then places a bitmap B1, if possible:
- *
- * -----------------------
- * | | |
- * | B1 | |
- * | | |
- * |-------- |
- * | |
- * | |
- * | |
- * | |
- * -----------------------
- *
- * After placing a bitmap in an empty cell, the algorithm splits
- * the remaining space in two new empty cells. The split can occur
- * vertically or horizontally (this is controlled by the "split
- * decision" parameter of the algorithm.)
- *
- * Here is for the instance the result of a vertical split:
- *
- * -----------------------
- * | | |
- * | B1 | |
- * | | |
- * |--------| C2 |
- * | | |
- * | | |
- * | C1 | |
- * | | |
- * -----------------------
- *
- * The cells tree now looks like this:
- *
- * C0(occupied)
- * / \
- * / \
- * / \
- * / \
- * C1(free) C2(free)
- *
- * For each bitmap to place in the atlas, the Slice algorithm
- * will visit the free cells until it finds one where a bitmap can
- * fit. It will then split the now occupied cell and proceed onto
- * the next bitmap.
- */
- private static class SlicePolicy extends Policy {
- private final Cell mRoot = new Cell();
-
- private final SplitDecision mSplitDecision;
-
- private final int mPadding;
-
- /**
- * A cell represents a sub-rectangle of the atlas. A cell is
- * a node in a linked list representing the available free
- * space in the atlas.
- */
- private static class Cell {
- int x;
- int y;
-
- int width;
- int height;
-
- Cell next;
-
- @Override
- public String toString() {
- return String.format("cell[x=%d y=%d width=%d height=%d", x, y, width, height);
- }
- }
-
- SlicePolicy(int width, int height, int flags, SplitDecision splitDecision) {
- mPadding = (flags & FLAG_ADD_PADDING) != 0 ? 1 : 0;
-
- // The entire atlas is empty at first, minus padding
- Cell first = new Cell();
- first.x = first.y = mPadding;
- first.width = width - 2 * mPadding;
- first.height = height - 2 * mPadding;
-
- mRoot.next = first;
- mSplitDecision = splitDecision;
- }
-
- @Override
- Entry pack(int width, int height, Entry entry) {
- Cell cell = mRoot.next;
- Cell prev = mRoot;
-
- while (cell != null) {
- if (insert(cell, prev, width, height, entry)) {
- return entry;
- }
-
- prev = cell;
- cell = cell.next;
- }
-
- return null;
- }
-
- /**
- * Defines how the remaining empty space should be split up:
- * vertically or horizontally.
- */
- private static interface SplitDecision {
- /**
- * Returns true if the remaining space defined by
- * <code>freeWidth</code> and <code>freeHeight</code>
- * should be split horizontally.
- *
- * @param freeWidth The rectWidth of the free space after packing a rectangle
- * @param freeHeight The rectHeight of the free space after packing a rectangle
- * @param rectWidth The rectWidth of the rectangle that was packed in a cell
- * @param rectHeight The rectHeight of the rectangle that was packed in a cell
- */
- boolean splitHorizontal(int freeWidth, int freeHeight,
- int rectWidth, int rectHeight);
- }
-
- // Splits the free area horizontally to minimize the horizontal section area
- private static class MinAreaSplitDecision implements SplitDecision {
- @Override
- public boolean splitHorizontal(int freeWidth, int freeHeight,
- int rectWidth, int rectHeight) {
- return rectWidth * freeHeight > freeWidth * rectHeight;
- }
- }
-
- // Splits the free area horizontally to maximize the horizontal section area
- private static class MaxAreaSplitDecision implements SplitDecision {
- @Override
- public boolean splitHorizontal(int freeWidth, int freeHeight,
- int rectWidth, int rectHeight) {
- return rectWidth * freeHeight <= freeWidth * rectHeight;
- }
- }
-
- // Splits the free area horizontally if the horizontal axis is shorter
- private static class ShorterFreeAxisSplitDecision implements SplitDecision {
- @Override
- public boolean splitHorizontal(int freeWidth, int freeHeight,
- int rectWidth, int rectHeight) {
- return freeWidth <= freeHeight;
- }
- }
-
- // Splits the free area horizontally if the vertical axis is shorter
- private static class LongerFreeAxisSplitDecision implements SplitDecision {
- @Override
- public boolean splitHorizontal(int freeWidth, int freeHeight,
- int rectWidth, int rectHeight) {
- return freeWidth > freeHeight;
- }
- }
-
- /**
- * Attempts to pack a rectangle of specified dimensions in the available
- * empty space.
- *
- * @param cell The cell representing free space in which to pack the rectangle
- * @param prev The previous cell in the free space linked list
- * @param width The width of the rectangle to pack
- * @param height The height of the rectangle to pack
- * @param entry Stores the location of the packged rectangle, if it fits
- *
- * @return True if the rectangle was packed in the atlas, false otherwise
- */
- private boolean insert(Cell cell, Cell prev, int width, int height, Entry entry) {
- if (cell.width < width || cell.height < height) {
- return false;
- }
-
- // Remaining free space after packing the rectangle
- int deltaWidth = cell.width - width;
- int deltaHeight = cell.height - height;
-
- // Split the remaining free space into two new cells
- Cell first = new Cell();
- Cell second = new Cell();
-
- first.x = cell.x + width + mPadding;
- first.y = cell.y;
- first.width = deltaWidth - mPadding;
-
- second.x = cell.x;
- second.y = cell.y + height + mPadding;
- second.height = deltaHeight - mPadding;
-
- if (mSplitDecision.splitHorizontal(deltaWidth, deltaHeight,
- width, height)) {
- first.height = height;
- second.width = cell.width;
- } else {
- first.height = cell.height;
- second.width = width;
-
- // The order of the cells matters for efficient packing
- // We want to give priority to the cell chosen by the
- // split decision heuristic
- Cell temp = first;
- first = second;
- second = temp;
- }
-
- // Remove degenerate cases to keep the free list as small as possible
- if (first.width > 0 && first.height > 0) {
- prev.next = first;
- prev = first;
- }
-
- if (second.width > 0 && second.height > 0) {
- prev.next = second;
- second.next = cell.next;
- } else {
- prev.next = cell.next;
- }
-
- // The cell is now completely removed from the free list
- cell.next = null;
-
- // Return the location and rotation of the packed rectangle
- entry.x = cell.x;
- entry.y = cell.y;
-
- return true;
- }
- }
-}
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 49721cf..7ce750d 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -48,11 +48,6 @@
// pixel data.
private static final long NATIVE_ALLOCATION_SIZE = 32;
- /**
- * Backing buffer for the Bitmap.
- */
- private byte[] mBuffer;
-
// Convenience for JNI access
private final long mNativePtr;
@@ -108,7 +103,7 @@
* int (pointer).
*/
// called from JNI
- Bitmap(long nativeBitmap, byte[] buffer, int width, int height, int density,
+ Bitmap(long nativeBitmap, int width, int height, int density,
boolean isMutable, boolean requestPremultiplied,
byte[] ninePatchChunk, NinePatch.InsetStruct ninePatchInsets) {
if (nativeBitmap == 0) {
@@ -119,7 +114,6 @@
mHeight = height;
mIsMutable = isMutable;
mRequestPremultiplied = requestPremultiplied;
- mBuffer = buffer;
mNinePatchChunk = ninePatchChunk;
mNinePatchInsets = ninePatchInsets;
@@ -128,10 +122,7 @@
}
mNativePtr = nativeBitmap;
- long nativeSize = NATIVE_ALLOCATION_SIZE;
- if (buffer == null) {
- nativeSize += getByteCount();
- }
+ long nativeSize = NATIVE_ALLOCATION_SIZE + getAllocationByteCount();
NativeAllocationRegistry registry = new NativeAllocationRegistry(
Bitmap.class.getClassLoader(), nativeGetNativeFinalizer(), nativeSize);
registry.registerNativeAllocation(this, nativeBitmap);
@@ -256,12 +247,8 @@
if (!isMutable()) {
throw new IllegalStateException("only mutable bitmaps may be reconfigured");
}
- if (mBuffer == null) {
- throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
- }
- nativeReconfigure(mNativePtr, width, height, config.nativeInt,
- mBuffer.length, mRequestPremultiplied);
+ nativeReconfigure(mNativePtr, width, height, config.nativeInt, mRequestPremultiplied);
mWidth = width;
mHeight = height;
}
@@ -343,7 +330,6 @@
// false indicates that it is still in use at the native level and these
// objects should not be collected now. They will be collected later when the
// Bitmap itself is collected.
- mBuffer = null;
mNinePatchChunk = null;
}
mRecycled = true;
@@ -1273,12 +1259,7 @@
* @see #reconfigure(int, int, Config)
*/
public final int getAllocationByteCount() {
- if (mBuffer == null) {
- // native backed bitmaps don't support reconfiguration,
- // so alloc size is always content size
- return getByteCount();
- }
- return mBuffer.length;
+ return nativeGetAllocationByteCount(mNativePtr);
}
/**
@@ -1695,8 +1676,7 @@
private static native long nativeGetNativeFinalizer();
private static native boolean nativeRecycle(long nativeBitmap);
private static native void nativeReconfigure(long nativeBitmap, int width, int height,
- int config, int allocSize,
- boolean isPremultiplied);
+ int config, boolean isPremultiplied);
private static native boolean nativeCompress(long nativeBitmap, int format,
int quality, OutputStream stream,
@@ -1742,4 +1722,5 @@
private static native boolean nativeSameAs(long nativeBitmap0, long nativeBitmap1);
private static native long nativeRefPixelRef(long nativeBitmap);
private static native void nativePrepareToDraw(long nativeBitmap);
+ private static native int nativeGetAllocationByteCount(long nativeBitmap);
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index d29005c..0692a09 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -26,13 +26,15 @@
import android.text.SpannedString;
import android.text.TextUtils;
+import dalvik.annotation.optimization.FastNative;
+
+import libcore.util.NativeAllocationRegistry;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.microedition.khronos.opengles.GL;
-import libcore.util.NativeAllocationRegistry;
-
/**
* The Canvas class holds the "draw" calls. To draw something, you need
* 4 basic components: A Bitmap to hold the pixels, a Canvas to host
@@ -2008,155 +2010,201 @@
public static native void freeTextLayoutCaches();
private static native long initRaster(Bitmap bitmap);
- private static native void native_setBitmap(long canvasHandle,
- Bitmap bitmap);
- private static native boolean native_isOpaque(long canvasHandle);
- private static native void native_setHighContrastText(long renderer, boolean highContrastText);
- private static native int native_getWidth(long canvasHandle);
- private static native int native_getHeight(long canvasHandle);
+ private static native long getNativeFinalizer();
- private static native int native_save(long canvasHandle, int saveFlags);
- private static native int native_saveLayer(long nativeCanvas, float l,
- float t, float r, float b,
- long nativePaint,
- int layerFlags);
- private static native int native_saveLayerAlpha(long nativeCanvas, float l,
- float t, float r, float b,
- int alpha, int layerFlags);
- private static native void native_restore(long canvasHandle, boolean tolerateUnderflow);
- private static native void native_restoreToCount(long canvasHandle,
- int saveCount,
- boolean tolerateUnderflow);
- private static native int native_getSaveCount(long canvasHandle);
-
- private static native void native_translate(long canvasHandle,
- float dx, float dy);
- private static native void native_scale(long canvasHandle,
- float sx, float sy);
- private static native void native_rotate(long canvasHandle, float degrees);
- private static native void native_skew(long canvasHandle,
- float sx, float sy);
- private static native void native_concat(long nativeCanvas,
- long nativeMatrix);
- private static native void native_setMatrix(long nativeCanvas,
- long nativeMatrix);
- private static native boolean native_clipRect(long nativeCanvas,
- float left, float top,
- float right, float bottom,
- int regionOp);
- private static native boolean native_clipPath(long nativeCanvas,
- long nativePath,
- int regionOp);
- private static native boolean native_clipRegion(long nativeCanvas,
- long nativeRegion,
- int regionOp);
- private static native void nativeSetDrawFilter(long nativeCanvas,
- long nativeFilter);
- private static native boolean native_getClipBounds(long nativeCanvas,
- Rect bounds);
- private static native void native_getCTM(long nativeCanvas,
- long nativeMatrix);
- private static native boolean native_quickReject(long nativeCanvas,
- long nativePath);
- private static native boolean native_quickReject(long nativeCanvas,
- float left, float top,
- float right, float bottom);
- private static native void native_drawColor(long nativeCanvas, int color,
- int mode);
- private static native void native_drawPaint(long nativeCanvas,
- long nativePaint);
- private static native void native_drawPoint(long canvasHandle, float x, float y,
- long paintHandle);
- private static native void native_drawPoints(long canvasHandle, float[] pts,
- int offset, int count,
- long paintHandle);
- private static native void native_drawLine(long nativeCanvas, float startX,
- float startY, float stopX,
- float stopY, long nativePaint);
- private static native void native_drawLines(long canvasHandle, float[] pts,
- int offset, int count,
- long paintHandle);
- private static native void native_drawRect(long nativeCanvas, float left,
- float top, float right,
- float bottom,
- long nativePaint);
- private static native void native_drawOval(long nativeCanvas, float left, float top,
- float right, float bottom, long nativePaint);
- private static native void native_drawCircle(long nativeCanvas, float cx,
- float cy, float radius,
- long nativePaint);
- private static native void native_drawArc(long nativeCanvas, float left, float top,
- float right, float bottom,
- float startAngle, float sweep, boolean useCenter,
- long nativePaint);
- private static native void native_drawRoundRect(long nativeCanvas,
- float left, float top, float right, float bottom,
- float rx, float ry, long nativePaint);
- private static native void native_drawPath(long nativeCanvas,
- long nativePath,
- long nativePaint);
- private static native void native_drawRegion(long nativeCanvas,
- long nativeRegion, long nativePaint);
- private native void native_drawNinePatch(long nativeCanvas, long nativeBitmap,
- long ninePatch, float dstLeft, float dstTop, float dstRight, float dstBottom,
- long nativePaintOrZero, int screenDensity, int bitmapDensity);
- private native void native_drawBitmap(long nativeCanvas, Bitmap bitmap,
- float left, float top,
- long nativePaintOrZero,
- int canvasDensity,
- int screenDensity,
- int bitmapDensity);
+ private native void native_drawBitmap(long nativeCanvas, Bitmap bitmap, float left, float top,
+ long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity);
private native void native_drawBitmap(long nativeCanvas, Bitmap bitmap,
float srcLeft, float srcTop, float srcRight, float srcBottom,
float dstLeft, float dstTop, float dstRight, float dstBottom,
long nativePaintOrZero, int screenDensity, int bitmapDensity);
private static native void native_drawBitmap(long nativeCanvas, int[] colors,
- int offset, int stride, float x,
- float y, int width, int height,
- boolean hasAlpha,
- long nativePaintOrZero);
+ int offset, int stride, float x, float y, int width, int height,
+ boolean hasAlpha, long nativePaintOrZero);
+
+ // ---------------- @FastNative -------------------
+
+ @FastNative
+ private static native void native_setBitmap(long canvasHandle,
+ Bitmap bitmap);
+ @FastNative
+ private static native boolean native_isOpaque(long canvasHandle);
+ @FastNative
+ private static native void native_setHighContrastText(long renderer, boolean highContrastText);
+ @FastNative
+ private static native int native_getWidth(long canvasHandle);
+ @FastNative
+ private static native int native_getHeight(long canvasHandle);
+
+ @FastNative
+ private static native int native_save(long canvasHandle, int saveFlags);
+ @FastNative
+ private static native int native_saveLayer(long nativeCanvas, float l,
+ float t, float r, float b,
+ long nativePaint,
+ int layerFlags);
+ @FastNative
+ private static native int native_saveLayerAlpha(long nativeCanvas, float l,
+ float t, float r, float b,
+ int alpha, int layerFlags);
+ @FastNative
+ private static native void native_restore(long canvasHandle, boolean tolerateUnderflow);
+ @FastNative
+ private static native void native_restoreToCount(long canvasHandle,
+ int saveCount,
+ boolean tolerateUnderflow);
+ @FastNative
+ private static native int native_getSaveCount(long canvasHandle);
+
+ @FastNative
+ private static native void native_translate(long canvasHandle,
+ float dx, float dy);
+ @FastNative
+ private static native void native_scale(long canvasHandle,
+ float sx, float sy);
+ @FastNative
+ private static native void native_rotate(long canvasHandle, float degrees);
+ @FastNative
+ private static native void native_skew(long canvasHandle,
+ float sx, float sy);
+ @FastNative
+ private static native void native_concat(long nativeCanvas,
+ long nativeMatrix);
+ @FastNative
+ private static native void native_setMatrix(long nativeCanvas,
+ long nativeMatrix);
+ @FastNative
+ private static native boolean native_clipRect(long nativeCanvas,
+ float left, float top,
+ float right, float bottom,
+ int regionOp);
+ @FastNative
+ private static native boolean native_clipPath(long nativeCanvas,
+ long nativePath,
+ int regionOp);
+ @FastNative
+ private static native boolean native_clipRegion(long nativeCanvas,
+ long nativeRegion,
+ int regionOp);
+ @FastNative
+ private static native void nativeSetDrawFilter(long nativeCanvas,
+ long nativeFilter);
+ @FastNative
+ private static native boolean native_getClipBounds(long nativeCanvas,
+ Rect bounds);
+ @FastNative
+ private static native void native_getCTM(long nativeCanvas,
+ long nativeMatrix);
+ @FastNative
+ private static native boolean native_quickReject(long nativeCanvas,
+ long nativePath);
+ @FastNative
+ private static native boolean native_quickReject(long nativeCanvas,
+ float left, float top,
+ float right, float bottom);
+ @FastNative
+ private static native void native_drawColor(long nativeCanvas, int color,
+ int mode);
+ @FastNative
+ private static native void native_drawPaint(long nativeCanvas,
+ long nativePaint);
+ @FastNative
+ private static native void native_drawPoint(long canvasHandle, float x, float y,
+ long paintHandle);
+ @FastNative
+ private static native void native_drawPoints(long canvasHandle, float[] pts,
+ int offset, int count,
+ long paintHandle);
+ @FastNative
+ private static native void native_drawLine(long nativeCanvas, float startX,
+ float startY, float stopX,
+ float stopY, long nativePaint);
+ @FastNative
+ private static native void native_drawLines(long canvasHandle, float[] pts,
+ int offset, int count,
+ long paintHandle);
+ @FastNative
+ private static native void native_drawRect(long nativeCanvas, float left,
+ float top, float right,
+ float bottom,
+ long nativePaint);
+ @FastNative
+ private static native void native_drawOval(long nativeCanvas, float left, float top,
+ float right, float bottom, long nativePaint);
+ @FastNative
+ private static native void native_drawCircle(long nativeCanvas, float cx,
+ float cy, float radius,
+ long nativePaint);
+ @FastNative
+ private static native void native_drawArc(long nativeCanvas, float left, float top,
+ float right, float bottom,
+ float startAngle, float sweep, boolean useCenter,
+ long nativePaint);
+ @FastNative
+ private static native void native_drawRoundRect(long nativeCanvas,
+ float left, float top, float right, float bottom,
+ float rx, float ry, long nativePaint);
+ @FastNative
+ private static native void native_drawPath(long nativeCanvas,
+ long nativePath,
+ long nativePaint);
+ @FastNative
+ private static native void native_drawRegion(long nativeCanvas,
+ long nativeRegion, long nativePaint);
+ @FastNative
+ private static native void native_drawNinePatch(long nativeCanvas, long nativeBitmap,
+ long ninePatch, float dstLeft, float dstTop, float dstRight, float dstBottom,
+ long nativePaintOrZero, int screenDensity, int bitmapDensity);
+ @FastNative
private static native void nativeDrawBitmapMatrix(long nativeCanvas,
Bitmap bitmap,
long nativeMatrix,
long nativePaint);
+ @FastNative
private static native void nativeDrawBitmapMesh(long nativeCanvas,
Bitmap bitmap,
int meshWidth, int meshHeight,
float[] verts, int vertOffset,
int[] colors, int colorOffset,
long nativePaint);
+ @FastNative
private static native void nativeDrawVertices(long nativeCanvas, int mode, int n,
float[] verts, int vertOffset, float[] texs, int texOffset,
int[] colors, int colorOffset, short[] indices,
int indexOffset, int indexCount, long nativePaint);
+ @FastNative
private static native void native_drawText(long nativeCanvas, char[] text,
int index, int count, float x,
float y, int flags, long nativePaint,
long nativeTypeface);
+ @FastNative
private static native void native_drawText(long nativeCanvas, String text,
int start, int end, float x,
float y, int flags, long nativePaint,
long nativeTypeface);
+ @FastNative
private static native void native_drawTextRun(long nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
+ @FastNative
private static native void native_drawTextRun(long nativeCanvas, char[] text,
int start, int count, int contextStart, int contextCount,
float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
+ @FastNative
private static native void native_drawTextOnPath(long nativeCanvas,
char[] text, int index,
int count, long nativePath,
float hOffset,
float vOffset, int bidiFlags,
long nativePaint, long nativeTypeface);
+ @FastNative
private static native void native_drawTextOnPath(long nativeCanvas,
String text, long nativePath,
float hOffset,
float vOffset,
int flags, long nativePaint, long nativeTypeface);
- private static native long getNativeFinalizer();
}
diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java
index 1e8f11b..35cedae 100644
--- a/graphics/java/android/graphics/Matrix.java
+++ b/graphics/java/android/graphics/Matrix.java
@@ -16,8 +16,12 @@
package android.graphics;
-import java.io.PrintWriter;
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+import libcore.util.NativeAllocationRegistry;
+
+import java.io.PrintWriter;
/**
* The Matrix class holds a 3x3 matrix for transforming coordinates.
@@ -216,352 +220,345 @@
}
};
+ // sizeof(SkMatrix) is 9 * sizeof(float) + uint32_t
+ private static final long NATIVE_ALLOCATION_SIZE = 40;
+
+ private static class NoImagePreloadHolder {
+ public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+ Matrix.class.getClassLoader(), nGetNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+ }
+
/**
* @hide
*/
- public long native_instance;
+ public final long native_instance;
/**
* Create an identity matrix
*/
public Matrix() {
- native_instance = native_create(0);
+ native_instance = nCreate(0);
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
}
/**
* Create a matrix that is a (deep) copy of src
+ *
* @param src The matrix to copy into this matrix
*/
public Matrix(Matrix src) {
- native_instance = native_create(src != null ? src.native_instance : 0);
+ native_instance = nCreate(src != null ? src.native_instance : 0);
+ NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
}
/**
- * Returns true if the matrix is identity.
- * This maybe faster than testing if (getType() == 0)
+ * Returns true if the matrix is identity. This maybe faster than testing if (getType() == 0)
*/
public boolean isIdentity() {
- return native_isIdentity(native_instance);
+ return nIsIdentity(native_instance);
}
/**
- * Gets whether this matrix is affine. An affine matrix preserves
- * straight lines and has no perspective.
+ * Gets whether this matrix is affine. An affine matrix preserves straight lines and has no
+ * perspective.
*
* @return Whether the matrix is affine.
*/
public boolean isAffine() {
- return native_isAffine(native_instance);
+ return nIsAffine(native_instance);
}
/**
- * Returns true if will map a rectangle to another rectangle. This can be
- * true if the matrix is identity, scale-only, or rotates a multiple of 90
- * degrees.
+ * Returns true if will map a rectangle to another rectangle. This can be true if the matrix is
+ * identity, scale-only, or rotates a multiple of 90 degrees.
*/
public boolean rectStaysRect() {
- return native_rectStaysRect(native_instance);
+ return nRectStaysRect(native_instance);
}
/**
- * (deep) copy the src matrix into this matrix. If src is null, reset this
- * matrix to the identity matrix.
+ * (deep) copy the src matrix into this matrix. If src is null, reset this matrix to the
+ * identity matrix.
*/
public void set(Matrix src) {
if (src == null) {
reset();
} else {
- native_set(native_instance, src.native_instance);
+ nSet(native_instance, src.native_instance);
}
}
- /** Returns true iff obj is a Matrix and its values equal our values.
- */
+ /**
+ * Returns true iff obj is a Matrix and its values equal our values.
+ */
@Override
public boolean equals(Object obj) {
- //if (obj == this) return true; -- NaN value would mean matrix != itself
- if (!(obj instanceof Matrix)) return false;
- return native_equals(native_instance, ((Matrix)obj).native_instance);
+ // if (obj == this) return true; -- NaN value would mean matrix != itself
+ if (!(obj instanceof Matrix)) {
+ return false;
+ }
+ return nEquals(native_instance, ((Matrix) obj).native_instance);
}
@Override
public int hashCode() {
// This should generate the hash code by performing some arithmetic operation on all
// the matrix elements -- our equals() does an element-by-element comparison, and we
- // need to ensure that the hash code for two equal objects is the same. We're not
+ // need to ensure that the hash code for two equal objects is the same. We're not
// really using this at the moment, so we take the easy way out.
return 44;
}
/** Set the matrix to identity */
public void reset() {
- native_reset(native_instance);
+ nReset(native_instance);
}
/** Set the matrix to translate by (dx, dy). */
public void setTranslate(float dx, float dy) {
- native_setTranslate(native_instance, dx, dy);
+ nSetTranslate(native_instance, dx, dy);
}
/**
- * Set the matrix to scale by sx and sy, with a pivot point at (px, py).
- * The pivot point is the coordinate that should remain unchanged by the
- * specified transformation.
+ * Set the matrix to scale by sx and sy, with a pivot point at (px, py). The pivot point is the
+ * coordinate that should remain unchanged by the specified transformation.
*/
public void setScale(float sx, float sy, float px, float py) {
- native_setScale(native_instance, sx, sy, px, py);
+ nSetScale(native_instance, sx, sy, px, py);
}
/** Set the matrix to scale by sx and sy. */
public void setScale(float sx, float sy) {
- native_setScale(native_instance, sx, sy);
+ nSetScale(native_instance, sx, sy);
}
/**
- * Set the matrix to rotate by the specified number of degrees, with a pivot
- * point at (px, py). The pivot point is the coordinate that should remain
- * unchanged by the specified transformation.
+ * Set the matrix to rotate by the specified number of degrees, with a pivot point at (px, py).
+ * The pivot point is the coordinate that should remain unchanged by the specified
+ * transformation.
*/
public void setRotate(float degrees, float px, float py) {
- native_setRotate(native_instance, degrees, px, py);
+ nSetRotate(native_instance, degrees, px, py);
}
/**
* Set the matrix to rotate about (0,0) by the specified number of degrees.
*/
public void setRotate(float degrees) {
- native_setRotate(native_instance, degrees);
+ nSetRotate(native_instance, degrees);
}
/**
- * Set the matrix to rotate by the specified sine and cosine values, with a
- * pivot point at (px, py). The pivot point is the coordinate that should
- * remain unchanged by the specified transformation.
+ * Set the matrix to rotate by the specified sine and cosine values, with a pivot point at (px,
+ * py). The pivot point is the coordinate that should remain unchanged by the specified
+ * transformation.
*/
public void setSinCos(float sinValue, float cosValue, float px, float py) {
- native_setSinCos(native_instance, sinValue, cosValue, px, py);
+ nSetSinCos(native_instance, sinValue, cosValue, px, py);
}
/** Set the matrix to rotate by the specified sine and cosine values. */
public void setSinCos(float sinValue, float cosValue) {
- native_setSinCos(native_instance, sinValue, cosValue);
+ nSetSinCos(native_instance, sinValue, cosValue);
}
/**
- * Set the matrix to skew by sx and sy, with a pivot point at (px, py).
- * The pivot point is the coordinate that should remain unchanged by the
- * specified transformation.
+ * Set the matrix to skew by sx and sy, with a pivot point at (px, py). The pivot point is the
+ * coordinate that should remain unchanged by the specified transformation.
*/
public void setSkew(float kx, float ky, float px, float py) {
- native_setSkew(native_instance, kx, ky, px, py);
+ nSetSkew(native_instance, kx, ky, px, py);
}
/** Set the matrix to skew by sx and sy. */
public void setSkew(float kx, float ky) {
- native_setSkew(native_instance, kx, ky);
+ nSetSkew(native_instance, kx, ky);
}
/**
- * Set the matrix to the concatenation of the two specified matrices and
- * return true.
- *
- * <p>Either of the two matrices may also be the target matrix, that is
- * <code>matrixA.setConcat(matrixA, matrixB);</code> is valid.</p>
- *
- * <p class="note">In {@link android.os.Build.VERSION_CODES#GINGERBREAD_MR1} and below, this
- * function returns true only if the result can be represented. In
- * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and above, it always returns true.</p>
+ * Set the matrix to the concatenation of the two specified matrices and return true.
+ * <p>
+ * Either of the two matrices may also be the target matrix, that is
+ * <code>matrixA.setConcat(matrixA, matrixB);</code> is valid.
+ * </p>
+ * <p class="note">
+ * In {@link android.os.Build.VERSION_CODES#GINGERBREAD_MR1} and below, this function returns
+ * true only if the result can be represented. In
+ * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and above, it always returns true.
+ * </p>
*/
public boolean setConcat(Matrix a, Matrix b) {
- native_setConcat(native_instance, a.native_instance, b.native_instance);
+ nSetConcat(native_instance, a.native_instance, b.native_instance);
return true;
}
/**
- * Preconcats the matrix with the specified translation.
- * M' = M * T(dx, dy)
+ * Preconcats the matrix with the specified translation. M' = M * T(dx, dy)
*/
public boolean preTranslate(float dx, float dy) {
- native_preTranslate(native_instance, dx, dy);
+ nPreTranslate(native_instance, dx, dy);
return true;
}
/**
- * Preconcats the matrix with the specified scale.
- * M' = M * S(sx, sy, px, py)
+ * Preconcats the matrix with the specified scale. M' = M * S(sx, sy, px, py)
*/
public boolean preScale(float sx, float sy, float px, float py) {
- native_preScale(native_instance, sx, sy, px, py);
+ nPreScale(native_instance, sx, sy, px, py);
return true;
}
/**
- * Preconcats the matrix with the specified scale.
- * M' = M * S(sx, sy)
+ * Preconcats the matrix with the specified scale. M' = M * S(sx, sy)
*/
public boolean preScale(float sx, float sy) {
- native_preScale(native_instance, sx, sy);
+ nPreScale(native_instance, sx, sy);
return true;
}
/**
- * Preconcats the matrix with the specified rotation.
- * M' = M * R(degrees, px, py)
+ * Preconcats the matrix with the specified rotation. M' = M * R(degrees, px, py)
*/
public boolean preRotate(float degrees, float px, float py) {
- native_preRotate(native_instance, degrees, px, py);
+ nPreRotate(native_instance, degrees, px, py);
return true;
}
/**
- * Preconcats the matrix with the specified rotation.
- * M' = M * R(degrees)
+ * Preconcats the matrix with the specified rotation. M' = M * R(degrees)
*/
public boolean preRotate(float degrees) {
- native_preRotate(native_instance, degrees);
+ nPreRotate(native_instance, degrees);
return true;
}
/**
- * Preconcats the matrix with the specified skew.
- * M' = M * K(kx, ky, px, py)
+ * Preconcats the matrix with the specified skew. M' = M * K(kx, ky, px, py)
*/
public boolean preSkew(float kx, float ky, float px, float py) {
- native_preSkew(native_instance, kx, ky, px, py);
+ nPreSkew(native_instance, kx, ky, px, py);
return true;
}
/**
- * Preconcats the matrix with the specified skew.
- * M' = M * K(kx, ky)
+ * Preconcats the matrix with the specified skew. M' = M * K(kx, ky)
*/
public boolean preSkew(float kx, float ky) {
- native_preSkew(native_instance, kx, ky);
+ nPreSkew(native_instance, kx, ky);
return true;
}
/**
- * Preconcats the matrix with the specified matrix.
- * M' = M * other
+ * Preconcats the matrix with the specified matrix. M' = M * other
*/
public boolean preConcat(Matrix other) {
- native_preConcat(native_instance, other.native_instance);
+ nPreConcat(native_instance, other.native_instance);
return true;
}
/**
- * Postconcats the matrix with the specified translation.
- * M' = T(dx, dy) * M
+ * Postconcats the matrix with the specified translation. M' = T(dx, dy) * M
*/
public boolean postTranslate(float dx, float dy) {
- native_postTranslate(native_instance, dx, dy);
+ nPostTranslate(native_instance, dx, dy);
return true;
}
/**
- * Postconcats the matrix with the specified scale.
- * M' = S(sx, sy, px, py) * M
+ * Postconcats the matrix with the specified scale. M' = S(sx, sy, px, py) * M
*/
public boolean postScale(float sx, float sy, float px, float py) {
- native_postScale(native_instance, sx, sy, px, py);
+ nPostScale(native_instance, sx, sy, px, py);
return true;
}
/**
- * Postconcats the matrix with the specified scale.
- * M' = S(sx, sy) * M
+ * Postconcats the matrix with the specified scale. M' = S(sx, sy) * M
*/
public boolean postScale(float sx, float sy) {
- native_postScale(native_instance, sx, sy);
+ nPostScale(native_instance, sx, sy);
return true;
}
/**
- * Postconcats the matrix with the specified rotation.
- * M' = R(degrees, px, py) * M
+ * Postconcats the matrix with the specified rotation. M' = R(degrees, px, py) * M
*/
public boolean postRotate(float degrees, float px, float py) {
- native_postRotate(native_instance, degrees, px, py);
+ nPostRotate(native_instance, degrees, px, py);
return true;
}
/**
- * Postconcats the matrix with the specified rotation.
- * M' = R(degrees) * M
+ * Postconcats the matrix with the specified rotation. M' = R(degrees) * M
*/
public boolean postRotate(float degrees) {
- native_postRotate(native_instance, degrees);
+ nPostRotate(native_instance, degrees);
return true;
}
/**
- * Postconcats the matrix with the specified skew.
- * M' = K(kx, ky, px, py) * M
+ * Postconcats the matrix with the specified skew. M' = K(kx, ky, px, py) * M
*/
public boolean postSkew(float kx, float ky, float px, float py) {
- native_postSkew(native_instance, kx, ky, px, py);
+ nPostSkew(native_instance, kx, ky, px, py);
return true;
}
/**
- * Postconcats the matrix with the specified skew.
- * M' = K(kx, ky) * M
+ * Postconcats the matrix with the specified skew. M' = K(kx, ky) * M
*/
public boolean postSkew(float kx, float ky) {
- native_postSkew(native_instance, kx, ky);
+ nPostSkew(native_instance, kx, ky);
return true;
}
/**
- * Postconcats the matrix with the specified matrix.
- * M' = other * M
+ * Postconcats the matrix with the specified matrix. M' = other * M
*/
public boolean postConcat(Matrix other) {
- native_postConcat(native_instance, other.native_instance);
+ nPostConcat(native_instance, other.native_instance);
return true;
}
- /** Controlls how the src rect should align into the dst rect for
- setRectToRect().
- */
+ /**
+ * Controlls how the src rect should align into the dst rect for setRectToRect().
+ */
public enum ScaleToFit {
/**
- * Scale in X and Y independently, so that src matches dst exactly.
- * This may change the aspect ratio of the src.
+ * Scale in X and Y independently, so that src matches dst exactly. This may change the
+ * aspect ratio of the src.
*/
- FILL (0),
+ FILL(0),
/**
- * Compute a scale that will maintain the original src aspect ratio,
- * but will also ensure that src fits entirely inside dst. At least one
- * axis (X or Y) will fit exactly. START aligns the result to the
- * left and top edges of dst.
+ * Compute a scale that will maintain the original src aspect ratio, but will also ensure
+ * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. START
+ * aligns the result to the left and top edges of dst.
*/
- START (1),
+ START(1),
/**
- * Compute a scale that will maintain the original src aspect ratio,
- * but will also ensure that src fits entirely inside dst. At least one
- * axis (X or Y) will fit exactly. The result is centered inside dst.
+ * Compute a scale that will maintain the original src aspect ratio, but will also ensure
+ * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. The
+ * result is centered inside dst.
*/
- CENTER (2),
+ CENTER(2),
/**
- * Compute a scale that will maintain the original src aspect ratio,
- * but will also ensure that src fits entirely inside dst. At least one
- * axis (X or Y) will fit exactly. END aligns the result to the
- * right and bottom edges of dst.
+ * Compute a scale that will maintain the original src aspect ratio, but will also ensure
+ * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. END
+ * aligns the result to the right and bottom edges of dst.
*/
- END (3);
+ END(3);
// the native values must match those in SkMatrix.h
ScaleToFit(int nativeInt) {
this.nativeInt = nativeInt;
}
+
final int nativeInt;
}
/**
- * Set the matrix to the scale and translate values that map the source
- * rectangle to the destination rectangle, returning true if the the result
- * can be represented.
+ * Set the matrix to the scale and translate values that map the source rectangle to the
+ * destination rectangle, returning true if the the result can be represented.
*
* @param src the source rectangle to map from.
* @param dst the destination rectangle to map to.
@@ -572,13 +569,13 @@
if (dst == null || src == null) {
throw new NullPointerException();
}
- return native_setRectToRect(native_instance, src, dst, stf.nativeInt);
+ return nSetRectToRect(native_instance, src, dst, stf.nativeInt);
}
// private helper to perform range checks on arrays of "points"
private static void checkPointArrays(float[] src, int srcIndex,
- float[] dst, int dstIndex,
- int pointCount) {
+ float[] dst, int dstIndex,
+ int pointCount) {
// check for too-small and too-big indices
int srcStop = srcIndex + (pointCount << 1);
int dstStop = dstIndex + (pointCount << 1);
@@ -589,84 +586,81 @@
}
/**
- * Set the matrix such that the specified src points would map to the
- * specified dst points. The "points" are represented as an array of floats,
- * order [x0, y0, x1, y1, ...], where each "point" is 2 float values.
+ * Set the matrix such that the specified src points would map to the specified dst points. The
+ * "points" are represented as an array of floats, order [x0, y0, x1, y1, ...], where each
+ * "point" is 2 float values.
*
- * @param src The array of src [x,y] pairs (points)
+ * @param src The array of src [x,y] pairs (points)
* @param srcIndex Index of the first pair of src values
- * @param dst The array of dst [x,y] pairs (points)
+ * @param dst The array of dst [x,y] pairs (points)
* @param dstIndex Index of the first pair of dst values
* @param pointCount The number of pairs/points to be used. Must be [0..4]
* @return true if the matrix was set to the specified transformation
*/
public boolean setPolyToPoly(float[] src, int srcIndex,
- float[] dst, int dstIndex,
- int pointCount) {
+ float[] dst, int dstIndex,
+ int pointCount) {
if (pointCount > 4) {
throw new IllegalArgumentException();
}
checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
- return native_setPolyToPoly(native_instance, src, srcIndex,
- dst, dstIndex, pointCount);
+ return nSetPolyToPoly(native_instance, src, srcIndex,
+ dst, dstIndex, pointCount);
}
/**
- * If this matrix can be inverted, return true and if inverse is not null,
- * set inverse to be the inverse of this matrix. If this matrix cannot be
- * inverted, ignore inverse and return false.
+ * If this matrix can be inverted, return true and if inverse is not null, set inverse to be the
+ * inverse of this matrix. If this matrix cannot be inverted, ignore inverse and return false.
*/
public boolean invert(Matrix inverse) {
- return native_invert(native_instance, inverse.native_instance);
+ return nInvert(native_instance, inverse.native_instance);
}
/**
- * Apply this matrix to the array of 2D points specified by src, and write
- * the transformed points into the array of points specified by dst. The
- * two arrays represent their "points" as pairs of floats [x, y].
+ * Apply this matrix to the array of 2D points specified by src, and write the transformed
+ * points into the array of points specified by dst. The two arrays represent their "points" as
+ * pairs of floats [x, y].
*
- * @param dst The array of dst points (x,y pairs)
+ * @param dst The array of dst points (x,y pairs)
* @param dstIndex The index of the first [x,y] pair of dst floats
- * @param src The array of src points (x,y pairs)
+ * @param src The array of src points (x,y pairs)
* @param srcIndex The index of the first [x,y] pair of src floats
* @param pointCount The number of points (x,y pairs) to transform
*/
public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
- int pointCount) {
+ int pointCount) {
checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
- native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
- pointCount, true);
+ nMapPoints(native_instance, dst, dstIndex, src, srcIndex,
+ pointCount, true);
}
/**
- * Apply this matrix to the array of 2D vectors specified by src, and write
- * the transformed vectors into the array of vectors specified by dst. The
- * two arrays represent their "vectors" as pairs of floats [x, y].
+ * Apply this matrix to the array of 2D vectors specified by src, and write the transformed
+ * vectors into the array of vectors specified by dst. The two arrays represent their "vectors"
+ * as pairs of floats [x, y]. Note: this method does not apply the translation associated with
+ * the matrix. Use {@link Matrix#mapPoints(float[], int, float[], int, int)} if you want the
+ * translation to be applied.
*
- * Note: this method does not apply the translation associated with the matrix. Use
- * {@link Matrix#mapPoints(float[], int, float[], int, int)} if you want the translation
- * to be applied.
- *
- * @param dst The array of dst vectors (x,y pairs)
+ * @param dst The array of dst vectors (x,y pairs)
* @param dstIndex The index of the first [x,y] pair of dst floats
- * @param src The array of src vectors (x,y pairs)
+ * @param src The array of src vectors (x,y pairs)
* @param srcIndex The index of the first [x,y] pair of src floats
* @param vectorCount The number of vectors (x,y pairs) to transform
*/
public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex,
- int vectorCount) {
+ int vectorCount) {
checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount);
- native_mapPoints(native_instance, dst, dstIndex, src, srcIndex,
- vectorCount, false);
+ nMapPoints(native_instance, dst, dstIndex, src, srcIndex,
+ vectorCount, false);
}
/**
- * Apply this matrix to the array of 2D points specified by src, and write
- * the transformed points into the array of points specified by dst. The
- * two arrays represent their "points" as pairs of floats [x, y].
+ * Apply this matrix to the array of 2D points specified by src, and write the transformed
+ * points into the array of points specified by dst. The two arrays represent their "points" as
+ * pairs of floats [x, y].
*
- * @param dst The array of dst points (x,y pairs)
- * @param src The array of src points (x,y pairs)
+ * @param dst The array of dst points (x,y pairs)
+ * @param src The array of src points (x,y pairs)
*/
public void mapPoints(float[] dst, float[] src) {
if (dst.length != src.length) {
@@ -676,15 +670,14 @@
}
/**
- * Apply this matrix to the array of 2D vectors specified by src, and write
- * the transformed vectors into the array of vectors specified by dst. The
- * two arrays represent their "vectors" as pairs of floats [x, y].
+ * Apply this matrix to the array of 2D vectors specified by src, and write the transformed
+ * vectors into the array of vectors specified by dst. The two arrays represent their "vectors"
+ * as pairs of floats [x, y]. Note: this method does not apply the translation associated with
+ * the matrix. Use {@link Matrix#mapPoints(float[], float[])} if you want the translation to be
+ * applied.
*
- * Note: this method does not apply the translation associated with the matrix. Use
- * {@link Matrix#mapPoints(float[], float[])} if you want the translation to be applied.
- *
- * @param dst The array of dst vectors (x,y pairs)
- * @param src The array of src vectors (x,y pairs)
+ * @param dst The array of dst vectors (x,y pairs)
+ * @param src The array of src vectors (x,y pairs)
*/
public void mapVectors(float[] dst, float[] src) {
if (dst.length != src.length) {
@@ -694,8 +687,8 @@
}
/**
- * Apply this matrix to the array of 2D points, and write the transformed
- * points back into the array
+ * Apply this matrix to the array of 2D points, and write the transformed points back into the
+ * array
*
* @param pts The array [x0, y0, x1, y1, ...] of points to transform.
*/
@@ -704,10 +697,8 @@
}
/**
- * Apply this matrix to the array of 2D vectors, and write the transformed
- * vectors back into the array.
- *
- * Note: this method does not apply the translation associated with the matrix. Use
+ * Apply this matrix to the array of 2D vectors, and write the transformed vectors back into the
+ * array. Note: this method does not apply the translation associated with the matrix. Use
* {@link Matrix#mapPoints(float[])} if you want the translation to be applied.
*
* @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform.
@@ -717,9 +708,9 @@
}
/**
- * Apply this matrix to the src rectangle, and write the transformed
- * rectangle into dst. This is accomplished by transforming the 4 corners of
- * src, and then setting dst to the bounds of those points.
+ * Apply this matrix to the src rectangle, and write the transformed rectangle into dst. This is
+ * accomplished by transforming the 4 corners of src, and then setting dst to the bounds of
+ * those points.
*
* @param dst Where the transformed rectangle is written.
* @param src The original rectangle to be transformed.
@@ -729,13 +720,13 @@
if (dst == null || src == null) {
throw new NullPointerException();
}
- return native_mapRect(native_instance, dst, src);
+ return nMapRect(native_instance, dst, src);
}
/**
- * Apply this matrix to the rectangle, and write the transformed rectangle
- * back into it. This is accomplished by transforming the 4 corners of rect,
- * and then setting it to the bounds of those points
+ * Apply this matrix to the rectangle, and write the transformed rectangle back into it. This is
+ * accomplished by transforming the 4 corners of rect, and then setting it to the bounds of
+ * those points
*
* @param rect The rectangle to transform.
* @return the result of calling rectStaysRect()
@@ -745,34 +736,33 @@
}
/**
- * Return the mean radius of a circle after it has been mapped by
- * this matrix. NOTE: in perspective this value assumes the circle
- * has its center at the origin.
+ * Return the mean radius of a circle after it has been mapped by this matrix. NOTE: in
+ * perspective this value assumes the circle has its center at the origin.
*/
public float mapRadius(float radius) {
- return native_mapRadius(native_instance, radius);
+ return nMapRadius(native_instance, radius);
}
- /** Copy 9 values from the matrix into the array.
- */
+ /**
+ * Copy 9 values from the matrix into the array.
+ */
public void getValues(float[] values) {
if (values.length < 9) {
throw new ArrayIndexOutOfBoundsException();
}
- native_getValues(native_instance, values);
+ nGetValues(native_instance, values);
}
- /** Copy 9 values from the array into the matrix.
- Depending on the implementation of Matrix, these may be
- transformed into 16.16 integers in the Matrix, such that
- a subsequent call to getValues() will not yield exactly
- the same values.
- */
+ /**
+ * Copy 9 values from the array into the matrix. Depending on the implementation of Matrix,
+ * these may be transformed into 16.16 integers in the Matrix, such that a subsequent call to
+ * getValues() will not yield exactly the same values.
+ */
public void setValues(float[] values) {
if (values.length < 9) {
throw new ArrayIndexOutOfBoundsException();
}
- native_setValues(native_instance, values);
+ nSetValues(native_instance, values);
}
@Override
@@ -798,122 +788,155 @@
float[] values = new float[9];
getValues(values);
sb.append('[');
- sb.append(values[0]); sb.append(", "); sb.append(values[1]); sb.append(", ");
- sb.append(values[2]); sb.append("][");
- sb.append(values[3]); sb.append(", "); sb.append(values[4]); sb.append(", ");
- sb.append(values[5]); sb.append("][");
- sb.append(values[6]); sb.append(", "); sb.append(values[7]); sb.append(", ");
- sb.append(values[8]); sb.append(']');
+ sb.append(values[0]);
+ sb.append(", ");
+ sb.append(values[1]);
+ sb.append(", ");
+ sb.append(values[2]);
+ sb.append("][");
+ sb.append(values[3]);
+ sb.append(", ");
+ sb.append(values[4]);
+ sb.append(", ");
+ sb.append(values[5]);
+ sb.append("][");
+ sb.append(values[6]);
+ sb.append(", ");
+ sb.append(values[7]);
+ sb.append(", ");
+ sb.append(values[8]);
+ sb.append(']');
}
/**
* Print short string, to optimize dumping.
+ *
* @hide
*/
public void printShortString(PrintWriter pw) {
float[] values = new float[9];
getValues(values);
pw.print('[');
- pw.print(values[0]); pw.print(", "); pw.print(values[1]); pw.print(", ");
- pw.print(values[2]); pw.print("][");
- pw.print(values[3]); pw.print(", "); pw.print(values[4]); pw.print(", ");
- pw.print(values[5]); pw.print("][");
- pw.print(values[6]); pw.print(", "); pw.print(values[7]); pw.print(", ");
- pw.print(values[8]); pw.print(']');
+ pw.print(values[0]);
+ pw.print(", ");
+ pw.print(values[1]);
+ pw.print(", ");
+ pw.print(values[2]);
+ pw.print("][");
+ pw.print(values[3]);
+ pw.print(", ");
+ pw.print(values[4]);
+ pw.print(", ");
+ pw.print(values[5]);
+ pw.print("][");
+ pw.print(values[6]);
+ pw.print(", ");
+ pw.print(values[7]);
+ pw.print(", ");
+ pw.print(values[8]);
+ pw.print(']');
}
- @Override
- protected void finalize() throws Throwable {
- try {
- finalizer(native_instance);
- native_instance = 0; // Other finalizers can still call us.
- } finally {
- super.finalize();
- }
- }
-
- /*package*/ final long ni() {
+ /* package */ final long ni() {
return native_instance;
}
- private static native long native_create(long native_src_or_zero);
- private static native boolean native_isIdentity(long native_object);
- private static native boolean native_isAffine(long native_object);
- private static native boolean native_rectStaysRect(long native_object);
- private static native void native_reset(long native_object);
- private static native void native_set(long native_object,
- long native_other);
- private static native void native_setTranslate(long native_object,
- float dx, float dy);
- private static native void native_setScale(long native_object,
- float sx, float sy, float px, float py);
- private static native void native_setScale(long native_object,
- float sx, float sy);
- private static native void native_setRotate(long native_object,
- float degrees, float px, float py);
- private static native void native_setRotate(long native_object,
- float degrees);
- private static native void native_setSinCos(long native_object,
- float sinValue, float cosValue, float px, float py);
- private static native void native_setSinCos(long native_object,
- float sinValue, float cosValue);
- private static native void native_setSkew(long native_object,
- float kx, float ky, float px, float py);
- private static native void native_setSkew(long native_object,
- float kx, float ky);
- private static native void native_setConcat(long native_object,
- long native_a,
- long native_b);
- private static native void native_preTranslate(long native_object,
- float dx, float dy);
- private static native void native_preScale(long native_object,
- float sx, float sy, float px, float py);
- private static native void native_preScale(long native_object,
- float sx, float sy);
- private static native void native_preRotate(long native_object,
- float degrees, float px, float py);
- private static native void native_preRotate(long native_object,
- float degrees);
- private static native void native_preSkew(long native_object,
- float kx, float ky, float px, float py);
- private static native void native_preSkew(long native_object,
- float kx, float ky);
- private static native void native_preConcat(long native_object,
- long native_other_matrix);
- private static native void native_postTranslate(long native_object,
- float dx, float dy);
- private static native void native_postScale(long native_object,
- float sx, float sy, float px, float py);
- private static native void native_postScale(long native_object,
- float sx, float sy);
- private static native void native_postRotate(long native_object,
- float degrees, float px, float py);
- private static native void native_postRotate(long native_object,
- float degrees);
- private static native void native_postSkew(long native_object,
- float kx, float ky, float px, float py);
- private static native void native_postSkew(long native_object,
- float kx, float ky);
- private static native void native_postConcat(long native_object,
- long native_other_matrix);
- private static native boolean native_setRectToRect(long native_object,
- RectF src, RectF dst, int stf);
- private static native boolean native_setPolyToPoly(long native_object,
- float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount);
- private static native boolean native_invert(long native_object,
- long native_inverse);
- private static native void native_mapPoints(long native_object,
- float[] dst, int dstIndex, float[] src, int srcIndex,
- int ptCount, boolean isPts);
- private static native boolean native_mapRect(long native_object,
- RectF dst, RectF src);
- private static native float native_mapRadius(long native_object,
- float radius);
- private static native void native_getValues(long native_object,
- float[] values);
- private static native void native_setValues(long native_object,
- float[] values);
- private static native boolean native_equals(long native_a, long native_b);
- private static native void finalizer(long native_instance);
+ // ------------------ Regular JNI ------------------------
+
+ private static native long nCreate(long nSrc_or_zero);
+ private static native long nGetNativeFinalizer();
+
+
+ // ------------------ Fast JNI ------------------------
+
+ @FastNative
+ private static native boolean nSetRectToRect(long nObject,
+ RectF src, RectF dst, int stf);
+ @FastNative
+ private static native boolean nSetPolyToPoly(long nObject,
+ float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount);
+ @FastNative
+ private static native void nMapPoints(long nObject,
+ float[] dst, int dstIndex, float[] src, int srcIndex,
+ int ptCount, boolean isPts);
+ @FastNative
+ private static native boolean nMapRect(long nObject, RectF dst, RectF src);
+ @FastNative
+ private static native void nGetValues(long nObject, float[] values);
+ @FastNative
+ private static native void nSetValues(long nObject, float[] values);
+
+
+ // ------------------ Critical JNI ------------------------
+
+ @CriticalNative
+ private static native boolean nIsIdentity(long nObject);
+ @CriticalNative
+ private static native boolean nIsAffine(long nObject);
+ @CriticalNative
+ private static native boolean nRectStaysRect(long nObject);
+ @CriticalNative
+ private static native void nReset(long nObject);
+ @CriticalNative
+ private static native void nSet(long nObject, long nOther);
+ @CriticalNative
+ private static native void nSetTranslate(long nObject, float dx, float dy);
+ @CriticalNative
+ private static native void nSetScale(long nObject, float sx, float sy, float px, float py);
+ @CriticalNative
+ private static native void nSetScale(long nObject, float sx, float sy);
+ @CriticalNative
+ private static native void nSetRotate(long nObject, float degrees, float px, float py);
+ @CriticalNative
+ private static native void nSetRotate(long nObject, float degrees);
+ @CriticalNative
+ private static native void nSetSinCos(long nObject, float sinValue, float cosValue,
+ float px, float py);
+ @CriticalNative
+ private static native void nSetSinCos(long nObject, float sinValue, float cosValue);
+ @CriticalNative
+ private static native void nSetSkew(long nObject, float kx, float ky, float px, float py);
+ @CriticalNative
+ private static native void nSetSkew(long nObject, float kx, float ky);
+ @CriticalNative
+ private static native void nSetConcat(long nObject, long nA, long nB);
+ @CriticalNative
+ private static native void nPreTranslate(long nObject, float dx, float dy);
+ @CriticalNative
+ private static native void nPreScale(long nObject, float sx, float sy, float px, float py);
+ @CriticalNative
+ private static native void nPreScale(long nObject, float sx, float sy);
+ @CriticalNative
+ private static native void nPreRotate(long nObject, float degrees, float px, float py);
+ @CriticalNative
+ private static native void nPreRotate(long nObject, float degrees);
+ @CriticalNative
+ private static native void nPreSkew(long nObject, float kx, float ky, float px, float py);
+ @CriticalNative
+ private static native void nPreSkew(long nObject, float kx, float ky);
+ @CriticalNative
+ private static native void nPreConcat(long nObject, long nOther_matrix);
+ @CriticalNative
+ private static native void nPostTranslate(long nObject, float dx, float dy);
+ @CriticalNative
+ private static native void nPostScale(long nObject, float sx, float sy, float px, float py);
+ @CriticalNative
+ private static native void nPostScale(long nObject, float sx, float sy);
+ @CriticalNative
+ private static native void nPostRotate(long nObject, float degrees, float px, float py);
+ @CriticalNative
+ private static native void nPostRotate(long nObject, float degrees);
+ @CriticalNative
+ private static native void nPostSkew(long nObject, float kx, float ky, float px, float py);
+ @CriticalNative
+ private static native void nPostSkew(long nObject, float kx, float ky);
+ @CriticalNative
+ private static native void nPostConcat(long nObject, long nOther_matrix);
+ @CriticalNative
+ private static native boolean nInvert(long nObject, long nInverse);
+ @CriticalNative
+ private static native float nMapRadius(long nObject, float radius);
+ @CriticalNative
+ private static native boolean nEquals(long nA, long nB);
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 4abe50f..98d45dc 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -27,6 +27,9 @@
import com.android.internal.annotations.GuardedBy;
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
import java.util.HashMap;
import java.util.Locale;
@@ -604,8 +607,6 @@
return nGetFlags(mNativePaint);
}
- private native int nGetFlags(long paintPtr);
-
/**
* Set the paint's flags. Use the Flag enum to specific flag values.
*
@@ -615,8 +616,6 @@
nSetFlags(mNativePaint, flags);
}
- private native void nSetFlags(long paintPtr, int flags);
-
/**
* Return the paint's hinting mode. Returns either
* {@link #HINTING_OFF} or {@link #HINTING_ON}.
@@ -625,8 +624,6 @@
return nGetHinting(mNativePaint);
}
- private native int nGetHinting(long paintPtr);
-
/**
* Set the paint's hinting mode. May be either
* {@link #HINTING_OFF} or {@link #HINTING_ON}.
@@ -635,8 +632,6 @@
nSetHinting(mNativePaint, mode);
}
- private native void nSetHinting(long paintPtr, int mode);
-
/**
* Helper for getFlags(), returning true if ANTI_ALIAS_FLAG bit is set
* AntiAliasing smooths out the edges of what is being drawn, but is has
@@ -661,8 +656,6 @@
nSetAntiAlias(mNativePaint, aa);
}
- private native void nSetAntiAlias(long paintPtr, boolean aa);
-
/**
* Helper for getFlags(), returning true if DITHER_FLAG bit is set
* Dithering affects how colors that are higher precision than the device
@@ -691,8 +684,6 @@
nSetDither(mNativePaint, dither);
}
- private native void nSetDither(long paintPtr, boolean dither);
-
/**
* Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set
*
@@ -712,8 +703,6 @@
nSetLinearText(mNativePaint, linearText);
}
- private native void nSetLinearText(long paintPtr, boolean linearText);
-
/**
* Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set
*
@@ -733,8 +722,6 @@
nSetSubpixelText(mNativePaint, subpixelText);
}
- private native void nSetSubpixelText(long paintPtr, boolean subpixelText);
-
/**
* Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
*
@@ -754,8 +741,6 @@
nSetUnderlineText(mNativePaint, underlineText);
}
- private native void nSetUnderlineText(long paintPtr, boolean underlineText);
-
/**
* Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set
*
@@ -775,8 +760,6 @@
nSetStrikeThruText(mNativePaint, strikeThruText);
}
- private native void nSetStrikeThruText(long paintPtr, boolean strikeThruText);
-
/**
* Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set
*
@@ -796,8 +779,6 @@
nSetFakeBoldText(mNativePaint, fakeBoldText);
}
- private native void nSetFakeBoldText(long paintPtr, boolean fakeBoldText);
-
/**
* Whether or not the bitmap filter is activated.
* Filtering affects the sampling of bitmaps when they are transformed.
@@ -823,8 +804,6 @@
nSetFilterBitmap(mNativePaint, filter);
}
- private native void nSetFilterBitmap(long paintPtr, boolean filter);
-
/**
* Return the paint's style, used for controlling how primitives'
* geometries are interpreted (except for drawBitmap, which always assumes
@@ -860,8 +839,6 @@
return nGetColor(mNativePaint);
}
- private native int nGetColor(long paintPtr);
-
/**
* Set the paint's color. Note that the color is an int containing alpha
* as well as r,g,b. This 32bit value is not premultiplied, meaning that
@@ -874,8 +851,6 @@
nSetColor(mNativePaint, color);
}
- private native void nSetColor(long paintPtr, @ColorInt int color);
-
/**
* Helper to getColor() that just returns the color's alpha value. This is
* the same as calling getColor() >>> 24. It always returns a value between
@@ -887,8 +862,6 @@
return nGetAlpha(mNativePaint);
}
- private native int nGetAlpha(long paintPtr);
-
/**
* Helper to setColor(), that only assigns the color's alpha value,
* leaving its r,g,b values unchanged. Results are undefined if the alpha
@@ -900,8 +873,6 @@
nSetAlpha(mNativePaint, a);
}
- private native void nSetAlpha(long paintPtr, int a);
-
/**
* Helper to setColor(), that takes a,r,g,b and constructs the color int
*
@@ -927,8 +898,6 @@
return nGetStrokeWidth(mNativePaint);
}
- private native float nGetStrokeWidth(long paintPtr);
-
/**
* Set the width for stroking.
* Pass 0 to stroke in hairline mode.
@@ -941,8 +910,6 @@
nSetStrokeWidth(mNativePaint, width);
}
- private native void nSetStrokeWidth(long paintPtr, float width);
-
/**
* Return the paint's stroke miter value. Used to control the behavior
* of miter joins when the joins angle is sharp.
@@ -954,8 +921,6 @@
return nGetStrokeMiter(mNativePaint);
}
- private native float nGetStrokeMiter(long paintPtr);
-
/**
* Set the paint's stroke miter value. This is used to control the behavior
* of miter joins when the joins angle is sharp. This value must be >= 0.
@@ -967,8 +932,6 @@
nSetStrokeMiter(mNativePaint, miter);
}
- private native void nSetStrokeMiter(long paintPtr, float miter);
-
/**
* Return the paint's Cap, controlling how the start and end of stroked
* lines and paths are treated.
@@ -1387,8 +1350,6 @@
return nIsElegantTextHeight(mNativePaint);
}
- private native boolean nIsElegantTextHeight(long paintPtr);
-
/**
* Set the paint's elegant height metrics flag. This setting selects font
* variants that have not been compacted to fit Latin-based vertical
@@ -1400,8 +1361,6 @@
nSetElegantTextHeight(mNativePaint, elegant);
}
- private native void nSetElegantTextHeight(long paintPtr, boolean elegant);
-
/**
* Return the paint's text size.
*
@@ -1411,8 +1370,6 @@
return nGetTextSize(mNativePaint);
}
- private native float nGetTextSize(long paintPtr);
-
/**
* Set the paint's text size. This value must be > 0
*
@@ -1422,8 +1379,6 @@
nSetTextSize(mNativePaint, textSize);
}
- private native void nSetTextSize(long paintPtr, float textSize);
-
/**
* Return the paint's horizontal scale factor for text. The default value
* is 1.0.
@@ -1434,8 +1389,6 @@
return nGetTextScaleX(mNativePaint);
}
- private native float nGetTextScaleX(long paintPtr);
-
/**
* Set the paint's horizontal scale factor for text. The default value
* is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
@@ -1447,8 +1400,6 @@
nSetTextScaleX(mNativePaint, scaleX);
}
- private native void nSetTextScaleX(long paintPtr, float scaleX);
-
/**
* Return the paint's horizontal skew factor for text. The default value
* is 0.
@@ -1459,8 +1410,6 @@
return nGetTextSkewX(mNativePaint);
}
- private native float nGetTextSkewX(long paintPtr);
-
/**
* Set the paint's horizontal skew factor for text. The default value
* is 0. For approximating oblique text, use values around -0.25.
@@ -1471,8 +1420,6 @@
nSetTextSkewX(mNativePaint, skewX);
}
- private native void nSetTextSkewX(long paintPtr, float skewX);
-
/**
* Return the paint's letter-spacing for text. The default value
* is 0.
@@ -1565,8 +1512,6 @@
return nAscent(mNativePaint, mNativeTypeface);
}
- private native float nAscent(long paintPtr, long typefacePtr);
-
/**
* Return the distance below (positive) the baseline (descent) based on the
* current typeface and text size.
@@ -1578,8 +1523,6 @@
return nDescent(mNativePaint, mNativeTypeface);
}
- private native float nDescent(long paintPtr, long typefacePtr);
-
/**
* Class that describes the various metrics for a font at a given text size.
* Remember, Y values increase going down, so those values will be positive,
@@ -1624,9 +1567,6 @@
return nGetFontMetrics(mNativePaint, mNativeTypeface, metrics);
}
- private native float nGetFontMetrics(long paintPtr,
- long typefacePtr, FontMetrics metrics);
-
/**
* Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
* with it, returning the object.
@@ -1686,9 +1626,6 @@
return nGetFontMetricsInt(mNativePaint, mNativeTypeface, fmi);
}
- private native int nGetFontMetricsInt(long paintPtr,
- long typefacePtr, FontMetricsInt fmi);
-
public FontMetricsInt getFontMetricsInt() {
FontMetricsInt fm = new FontMetricsInt();
getFontMetricsInt(fm);
@@ -1860,10 +1797,6 @@
return res;
}
- private static native int nBreakText(long nObject, long nTypeface,
- char[] text, int index, int count,
- float maxWidth, int bidiFlags, float[] measuredWidth);
-
/**
* Measure the text, stopping early if the measured width exceeds maxWidth.
* Return the number of chars that were measured, and if measuredWidth is
@@ -1952,10 +1885,6 @@
return res;
}
- private static native int nBreakText(long nObject, long nTypeface,
- String text, boolean measureForwards,
- float maxWidth, int bidiFlags, float[] measuredWidth);
-
/**
* Return the advance widths for the characters in the string.
*
@@ -2679,73 +2608,34 @@
return result;
}
+ // regular JNI
+ private static native long nGetNativeFinalizer();
private static native long nInit();
private static native long nInitWithPaint(long paint);
- private static native void nReset(long paintPtr);
- private static native void nSet(long paintPtrDest, long paintPtrSrc);
- private static native int nGetStyle(long paintPtr);
- private static native void nSetStyle(long paintPtr, int style);
- private static native int nGetStrokeCap(long paintPtr);
- private static native void nSetStrokeCap(long paintPtr, int cap);
- private static native int nGetStrokeJoin(long paintPtr);
- private static native void nSetStrokeJoin(long paintPtr,
- int join);
- private static native boolean nGetFillPath(long paintPtr,
- long src, long dst);
- private static native long nSetShader(long paintPtr, long shader);
- private static native long nSetColorFilter(long paintPtr,
- long filter);
- private static native void nSetXfermode(long paintPtr, int xfermode);
- private static native long nSetPathEffect(long paintPtr,
- long effect);
- private static native long nSetMaskFilter(long paintPtr,
- long maskfilter);
- private static native long nSetTypeface(long paintPtr,
- long typeface);
- private static native long nSetRasterizer(long paintPtr,
- long rasterizer);
-
- private static native int nGetTextAlign(long paintPtr);
- private static native void nSetTextAlign(long paintPtr,
- int align);
-
- private static native int nSetTextLocales(long paintPtr, String locales);
- private static native void nSetTextLocalesByMinikinLangListId(long paintPtr,
- int mMinikinLangListId);
-
+ private static native int nBreakText(long nObject, long nTypeface,
+ char[] text, int index, int count,
+ float maxWidth, int bidiFlags, float[] measuredWidth);
+ private static native int nBreakText(long nObject, long nTypeface,
+ String text, boolean measureForwards,
+ float maxWidth, int bidiFlags, float[] measuredWidth);
private static native float nGetTextAdvances(long paintPtr, long typefacePtr,
char[] text, int index, int count, int contextIndex, int contextCount,
int bidiFlags, float[] advances, int advancesIndex);
private static native float nGetTextAdvances(long paintPtr, long typefacePtr,
String text, int start, int end, int contextStart, int contextEnd,
int bidiFlags, float[] advances, int advancesIndex);
-
private native int nGetTextRunCursor(long paintPtr, char[] text,
int contextStart, int contextLength, int dir, int offset, int cursorOpt);
private native int nGetTextRunCursor(long paintPtr, String text,
int contextStart, int contextEnd, int dir, int offset, int cursorOpt);
-
private static native void nGetTextPath(long paintPtr, long typefacePtr,
int bidiFlags, char[] text, int index, int count, float x, float y, long path);
private static native void nGetTextPath(long paintPtr, long typefacePtr,
int bidiFlags, String text, int start, int end, float x, float y, long path);
private static native void nGetStringBounds(long nativePaint, long typefacePtr,
- String text, int start, int end, int bidiFlags, Rect bounds);
+ String text, int start, int end, int bidiFlags, Rect bounds);
private static native void nGetCharArrayBounds(long nativePaint, long typefacePtr,
- char[] text, int index, int count, int bidiFlags, Rect bounds);
- private static native long nGetNativeFinalizer();
-
- private static native void nSetShadowLayer(long paintPtr,
- float radius, float dx, float dy, int color);
- private static native boolean nHasShadowLayer(long paintPtr);
-
- private static native float nGetLetterSpacing(long paintPtr);
- private static native void nSetLetterSpacing(long paintPtr,
- float letterSpacing);
- private static native void nSetFontFeatureSettings(long paintPtr,
- String settings);
- private static native int nGetHyphenEdit(long paintPtr);
- private static native void nSetHyphenEdit(long paintPtr, int hyphen);
+ char[] text, int index, int count, int bidiFlags, Rect bounds);
private static native boolean nHasGlyph(long paintPtr, long typefacePtr,
int bidiFlags, String string);
private static native float nGetRunAdvance(long paintPtr, long typefacePtr,
@@ -2754,4 +2644,134 @@
private static native int nGetOffsetForAdvance(long paintPtr,
long typefacePtr, char[] text, int start, int end, int contextStart, int contextEnd,
boolean isRtl, float advance);
+
+
+ // ---------------- @FastNative ------------------------
+
+ @FastNative
+ private static native int nSetTextLocales(long paintPtr, String locales);
+ @FastNative
+ private static native void nSetFontFeatureSettings(long paintPtr, String settings);
+ @FastNative
+ private static native float nGetFontMetrics(long paintPtr,
+ long typefacePtr, FontMetrics metrics);
+ @FastNative
+ private static native int nGetFontMetricsInt(long paintPtr,
+ long typefacePtr, FontMetricsInt fmi);
+
+
+ // ---------------- @CriticalNative ------------------------
+
+ @CriticalNative
+ private static native void nReset(long paintPtr);
+ @CriticalNative
+ private static native void nSet(long paintPtrDest, long paintPtrSrc);
+ @CriticalNative
+ private static native int nGetStyle(long paintPtr);
+ @CriticalNative
+ private static native void nSetStyle(long paintPtr, int style);
+ @CriticalNative
+ private static native int nGetStrokeCap(long paintPtr);
+ @CriticalNative
+ private static native void nSetStrokeCap(long paintPtr, int cap);
+ @CriticalNative
+ private static native int nGetStrokeJoin(long paintPtr);
+ @CriticalNative
+ private static native void nSetStrokeJoin(long paintPtr, int join);
+ @CriticalNative
+ private static native boolean nGetFillPath(long paintPtr, long src, long dst);
+ @CriticalNative
+ private static native long nSetShader(long paintPtr, long shader);
+ @CriticalNative
+ private static native long nSetColorFilter(long paintPtr, long filter);
+ @CriticalNative
+ private static native void nSetXfermode(long paintPtr, int xfermode);
+ @CriticalNative
+ private static native long nSetPathEffect(long paintPtr, long effect);
+ @CriticalNative
+ private static native long nSetMaskFilter(long paintPtr, long maskfilter);
+ @CriticalNative
+ private static native long nSetTypeface(long paintPtr, long typeface);
+ @CriticalNative
+ private static native long nSetRasterizer(long paintPtr, long rasterizer);
+ @CriticalNative
+ private static native int nGetTextAlign(long paintPtr);
+ @CriticalNative
+ private static native void nSetTextAlign(long paintPtr, int align);
+ @CriticalNative
+ private static native void nSetTextLocalesByMinikinLangListId(long paintPtr,
+ int mMinikinLangListId);
+ @CriticalNative
+ private static native void nSetShadowLayer(long paintPtr,
+ float radius, float dx, float dy, int color);
+ @CriticalNative
+ private static native boolean nHasShadowLayer(long paintPtr);
+ @CriticalNative
+ private static native float nGetLetterSpacing(long paintPtr);
+ @CriticalNative
+ private static native void nSetLetterSpacing(long paintPtr, float letterSpacing);
+ @CriticalNative
+ private static native int nGetHyphenEdit(long paintPtr);
+ @CriticalNative
+ private static native void nSetHyphenEdit(long paintPtr, int hyphen);
+ @CriticalNative
+ private static native void nSetStrokeMiter(long paintPtr, float miter);
+ @CriticalNative
+ private static native float nGetStrokeMiter(long paintPtr);
+ @CriticalNative
+ private static native void nSetStrokeWidth(long paintPtr, float width);
+ @CriticalNative
+ private static native float nGetStrokeWidth(long paintPtr);
+ @CriticalNative
+ private static native void nSetAlpha(long paintPtr, int a);
+ @CriticalNative
+ private static native void nSetDither(long paintPtr, boolean dither);
+ @CriticalNative
+ private static native int nGetFlags(long paintPtr);
+ @CriticalNative
+ private static native void nSetFlags(long paintPtr, int flags);
+ @CriticalNative
+ private static native int nGetHinting(long paintPtr);
+ @CriticalNative
+ private static native void nSetHinting(long paintPtr, int mode);
+ @CriticalNative
+ private static native void nSetAntiAlias(long paintPtr, boolean aa);
+ @CriticalNative
+ private static native void nSetLinearText(long paintPtr, boolean linearText);
+ @CriticalNative
+ private static native void nSetSubpixelText(long paintPtr, boolean subpixelText);
+ @CriticalNative
+ private static native void nSetUnderlineText(long paintPtr, boolean underlineText);
+ @CriticalNative
+ private static native void nSetFakeBoldText(long paintPtr, boolean fakeBoldText);
+ @CriticalNative
+ private static native void nSetFilterBitmap(long paintPtr, boolean filter);
+ @CriticalNative
+ private static native int nGetColor(long paintPtr);
+ @CriticalNative
+ private static native void nSetColor(long paintPtr, @ColorInt int color);
+ @CriticalNative
+ private static native int nGetAlpha(long paintPtr);
+ @CriticalNative
+ private static native void nSetStrikeThruText(long paintPtr, boolean strikeThruText);
+ @CriticalNative
+ private static native boolean nIsElegantTextHeight(long paintPtr);
+ @CriticalNative
+ private static native void nSetElegantTextHeight(long paintPtr, boolean elegant);
+ @CriticalNative
+ private static native float nGetTextSize(long paintPtr);
+ @CriticalNative
+ private static native float nGetTextScaleX(long paintPtr);
+ @CriticalNative
+ private static native void nSetTextScaleX(long paintPtr, float scaleX);
+ @CriticalNative
+ private static native float nGetTextSkewX(long paintPtr);
+ @CriticalNative
+ private static native void nSetTextSkewX(long paintPtr, float skewX);
+ @CriticalNative
+ private static native float nAscent(long paintPtr, long typefacePtr);
+ @CriticalNative
+ private static native float nDescent(long paintPtr, long typefacePtr);
+ @CriticalNative
+ private static native void nSetTextSize(long paintPtr, float textSize);
}
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index dcca431..40a2833 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -57,6 +57,9 @@
import com.android.internal.R;
import com.android.internal.util.VirtualRefBasePtr;
+
+import dalvik.annotation.optimization.FastNative;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -455,7 +458,11 @@
int eventType = parser.getEventType();
float pathErrorScale = 1;
- while (eventType != XmlPullParser.END_DOCUMENT) {
+ final int innerDepth = parser.getDepth() + 1;
+
+ // Parse everything until the end of the animated-vector element.
+ while (eventType != XmlPullParser.END_DOCUMENT
+ && (parser.getDepth() >= innerDepth || eventType != XmlPullParser.END_TAG)) {
if (eventType == XmlPullParser.START_TAG) {
final String tagName = parser.getName();
if (ANIMATED_VECTOR.equals(tagName)) {
@@ -1719,22 +1726,30 @@
private static native void nAddAnimator(long setPtr, long propertyValuesHolder,
long nativeInterpolator, long startDelay, long duration, int repeatCount,
int repeatMode);
-
- private static native long nCreateGroupPropertyHolder(long nativePtr, int propertyId,
- float startValue, float endValue);
-
- private static native long nCreatePathDataPropertyHolder(long nativePtr, long startValuePtr,
- long endValuePtr);
- private static native long nCreatePathColorPropertyHolder(long nativePtr, int propertyId,
- int startValue, int endValue);
- private static native long nCreatePathPropertyHolder(long nativePtr, int propertyId,
- float startValue, float endValue);
- private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
- float endValue);
private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length);
private static native void nSetPropertyHolderData(long nativePtr, int[] data, int length);
private static native void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
private static native void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
+
+ // ------------- @FastNative -------------------
+
+ @FastNative
+ private static native long nCreateGroupPropertyHolder(long nativePtr, int propertyId,
+ float startValue, float endValue);
+ @FastNative
+ private static native long nCreatePathDataPropertyHolder(long nativePtr, long startValuePtr,
+ long endValuePtr);
+ @FastNative
+ private static native long nCreatePathColorPropertyHolder(long nativePtr, int propertyId,
+ int startValue, int endValue);
+ @FastNative
+ private static native long nCreatePathPropertyHolder(long nativePtr, int propertyId,
+ float startValue, float endValue);
+ @FastNative
+ private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
+ float endValue);
+ @FastNative
private static native void nEnd(long animatorSetPtr);
+ @FastNative
private static native void nReset(long animatorSetPtr);
}
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 9d8ede0..6deeb0d 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -49,7 +49,6 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
-import java.util.Collection;
/**
* A Drawable that wraps a bitmap and can be tiled, stretched, or aligned. You can create a
@@ -463,31 +462,14 @@
return isAutoMirrored() && getLayoutDirection() == LayoutDirection.RTL;
}
- private void updateMirrorMatrix(float dx) {
- if (mMirrorMatrix == null) {
- mMirrorMatrix = new Matrix();
- }
- mMirrorMatrix.setTranslate(dx, 0);
- mMirrorMatrix.preScale(-1.0f, 1.0f);
- }
-
@Override
protected void onBoundsChange(Rect bounds) {
mDstRectAndInsetsDirty = true;
+ final Bitmap bitmap = mBitmapState.mBitmap;
final Shader shader = mBitmapState.mPaint.getShader();
- if (shader != null) {
- if (needMirroring()) {
- updateMirrorMatrix(bounds.right - bounds.left);
- shader.setLocalMatrix(mMirrorMatrix);
- mBitmapState.mPaint.setShader(shader);
- } else {
- if (mMirrorMatrix != null) {
- mMirrorMatrix = null;
- shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
- mBitmapState.mPaint.setShader(shader);
- }
- }
+ if (bitmap != null && shader != null) {
+ updateShaderMatrix(bitmap, mBitmapState.mPaint, shader, needMirroring());
}
}
@@ -548,19 +530,7 @@
canvas.restore();
}
} else {
- if (needMirroring) {
- // Mirror the bitmap
- updateMirrorMatrix(mDstRect.right - mDstRect.left);
- shader.setLocalMatrix(mMirrorMatrix);
- paint.setShader(shader);
- } else {
- if (mMirrorMatrix != null) {
- mMirrorMatrix = null;
- shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
- paint.setShader(shader);
- }
- }
-
+ updateShaderMatrix(bitmap, paint, shader, needMirroring);
canvas.drawRect(mDstRect, paint);
}
@@ -573,6 +543,51 @@
}
}
+ /**
+ * Updates the {@code paint}'s shader matrix to be consistent with the
+ * destination size and layout direction.
+ *
+ * @param bitmap the bitmap to be drawn
+ * @param paint the paint used to draw the bitmap
+ * @param shader the shader to set on the paint
+ * @param needMirroring whether the bitmap should be mirrored
+ */
+ private void updateShaderMatrix(@NonNull Bitmap bitmap, @NonNull Paint paint,
+ @NonNull Shader shader, boolean needMirroring) {
+ final int sourceDensity = bitmap.getDensity();
+ final int targetDensity = mTargetDensity;
+ final boolean needScaling = sourceDensity != 0 && sourceDensity != targetDensity;
+ if (needScaling || needMirroring) {
+ final Matrix matrix = getOrCreateMirrorMatrix();
+ matrix.reset();
+
+ if (needMirroring) {
+ final int dx = mDstRect.right - mDstRect.left;
+ matrix.setTranslate(dx, 0);
+ matrix.setScale(-1, 1);
+ }
+
+ if (needScaling) {
+ final float densityScale = targetDensity / (float) sourceDensity;
+ matrix.postScale(densityScale, densityScale);
+ }
+
+ shader.setLocalMatrix(matrix);
+ } else {
+ mMirrorMatrix = null;
+ shader.setLocalMatrix(Matrix.IDENTITY_MATRIX);
+ }
+
+ paint.setShader(shader);
+ }
+
+ private Matrix getOrCreateMirrorMatrix() {
+ if (mMirrorMatrix == null) {
+ mMirrorMatrix = new Matrix();
+ }
+ return mMirrorMatrix;
+ }
+
private void updateDstRectAndInsetsIfDirty() {
if (mDstRectAndInsetsDirty) {
if (mBitmapState.mTileModeX == null && mBitmapState.mTileModeY == null) {
@@ -941,14 +956,6 @@
}
@Override
- public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
- if (isAtlasable(mBitmap) && atlasList.add(mBitmap)) {
- return mBitmap.getWidth() * mBitmap.getHeight();
- }
- return 0;
- }
-
- @Override
public Drawable newDrawable() {
return new BitmapDrawable(this, null);
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index af20f8a..6ddc2d7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -58,7 +58,6 @@
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.Arrays;
-import java.util.Collection;
/**
* A Drawable is a general abstraction for "something that can be drawn." Most
@@ -109,6 +108,9 @@
* <li> <b>Nine Patch</b>: an extension to the PNG format allows it to
* specify information about how to stretch it and place things inside of
* it.
+ * <li><b>Vector</b>: a drawable defined in an XML file as a set of points,
+ * lines, and curves along with its associated color information. This type
+ * of drawable can be scaled without loss of display quality.
* <li> <b>Shape</b>: contains simple drawing commands instead of a raw
* bitmap, allowing it to resize better in some cases.
* <li> <b>Layers</b>: a compound drawable, which draws multiple underlying
@@ -1364,19 +1366,6 @@
public abstract @Config int getChangingConfigurations();
/**
- * @return Total pixel count
- * @hide
- */
- public int addAtlasableBitmaps(@NonNull Collection<Bitmap> atlasList) {
- return 0;
- }
-
- /** @hide */
- protected final boolean isAtlasable(@Nullable Bitmap bitmap) {
- return bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888;
- }
-
- /**
* Return whether this constant state can have a theme applied.
*/
public boolean canApplyTheme() {
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index c7a3c75..abdc2b9 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -21,7 +21,6 @@
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Insets;
@@ -35,8 +34,6 @@
import android.util.SparseArray;
import android.view.View;
-import java.util.Collection;
-
/**
* A helper class that contains several {@link Drawable}s and selects which one to use.
*
@@ -1194,19 +1191,6 @@
return true;
}
- /** @hide */
- @Override
- public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
- final int N = mNumChildren;
- int pixelCount = 0;
- for (int i = 0; i < N; i++) {
- final ConstantState state = getChild(i).getConstantState();
- if (state != null) {
- pixelCount += state.addAtlasableBitmaps(atlasList);
- }
- }
- return pixelCount;
- }
}
protected void setConstantState(DrawableContainerState state) {
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 5abfc54..5887939 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -28,7 +28,6 @@
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Insets;
@@ -41,7 +40,6 @@
import android.view.View;
import java.io.IOException;
-import java.util.Collection;
/**
* Drawable container with only one child element.
@@ -508,15 +506,6 @@
}
@Override
- public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
- final Drawable.ConstantState state = mDrawableState;
- if (state != null) {
- return state.addAtlasableBitmaps(atlasList);
- }
- return 0;
- }
-
- @Override
public Drawable newDrawable() {
return newDrawable(null);
}
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index c30c4c2..e09fea5 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -23,7 +23,6 @@
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
-import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Outline;
@@ -42,7 +41,6 @@
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
-import java.util.Collection;
/**
* A Drawable that manages an array of other Drawables. These are drawn in array
@@ -2128,22 +2126,6 @@
mHaveIsStateful = false;
}
- @Override
- public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
- final ChildDrawable[] array = mChildren;
- final int N = mNum;
- int pixelCount = 0;
- for (int i = 0; i < N; i++) {
- final Drawable dr = array[i].mDrawable;
- if (dr != null) {
- final ConstantState state = dr.getConstantState();
- if (state != null) {
- pixelCount += state.addAtlasableBitmaps(atlasList);
- }
- }
- }
- return pixelCount;
- }
}
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index d962385..c7183d9 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -49,7 +49,6 @@
import java.io.IOException;
import java.io.InputStream;
-import java.util.Collection;
/**
*
@@ -633,15 +632,6 @@
}
@Override
- public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
- final Bitmap bitmap = mNinePatch.getBitmap();
- if (isAtlasable(bitmap) && atlasList.add(bitmap)) {
- return bitmap.getWidth() * bitmap.getHeight();
- }
- return 0;
- }
-
- @Override
public Drawable newDrawable() {
return new NinePatchDrawable(this, null);
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 9ff6965..e83104d 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -55,6 +55,7 @@
import java.util.HashMap;
import java.util.Stack;
+import dalvik.annotation.optimization.FastNative;
import dalvik.system.VMRuntime;
/**
@@ -76,27 +77,36 @@
* <dl>
* <dt><code>android:name</code></dt>
* <dd>Defines the name of this vector drawable.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:width</code></dt>
* <dd>Used to define the intrinsic width of the drawable.
* This support all the dimension units, normally specified with dp.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:height</code></dt>
* <dd>Used to define the intrinsic height the drawable.
* This support all the dimension units, normally specified with dp.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:viewportWidth</code></dt>
* <dd>Used to define the width of the viewport space. Viewport is basically
* the virtual canvas where the paths are drawn on.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:viewportHeight</code></dt>
* <dd>Used to define the height of the viewport space. Viewport is basically
* the virtual canvas where the paths are drawn on.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:tint</code></dt>
* <dd>The color to apply to the drawable as a tint. By default, no tint is applied.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:tintMode</code></dt>
* <dd>The Porter-Duff blending mode for the tint color. The default value is src_in.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:autoMirrored</code></dt>
* <dd>Indicates if the drawable needs to be mirrored when its layout direction is
* RTL (right-to-left).</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:alpha</code></dt>
* <dd>The opacity of this drawable.</dd>
+ * <dd>Animatable : Yes.</dd>
* </dl></dd>
* </dl>
*
@@ -108,24 +118,32 @@
* <dl>
* <dt><code>android:name</code></dt>
* <dd>Defines the name of the group.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:rotation</code></dt>
* <dd>The degrees of rotation of the group.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:pivotX</code></dt>
* <dd>The X coordinate of the pivot for the scale and rotation of the group.
* This is defined in the viewport space.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:pivotY</code></dt>
* <dd>The Y coordinate of the pivot for the scale and rotation of the group.
* This is defined in the viewport space.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:scaleX</code></dt>
* <dd>The amount of scale on the X Coordinate.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:scaleY</code></dt>
* <dd>The amount of scale on the Y coordinate.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:translateX</code></dt>
* <dd>The amount of translation on the X coordinate.
* This is defined in the viewport space.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:translateY</code></dt>
* <dd>The amount of translation on the Y coordinate.
* This is defined in the viewport space.</dd>
+ * <dd>Animatable : Yes.</dd>
* </dl></dd>
* </dl>
*
@@ -135,45 +153,60 @@
* <dl>
* <dt><code>android:name</code></dt>
* <dd>Defines the name of the path.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:pathData</code></dt>
* <dd>Defines path data using exactly same format as "d" attribute
* in the SVG's path data. This is defined in the viewport space.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:fillColor</code></dt>
* <dd>Specifies the color used to fill the path. May be a color or, for SDK 24+, a color state list
* or a gradient color (See {@link android.R.styleable#GradientColor}
* and {@link android.R.styleable#GradientColorItem}).
* If this property is animated, any value set by the animation will override the original value.
* No path fill is drawn if this property is not specified.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:strokeColor</code></dt>
* <dd>Specifies the color used to draw the path outline. May be a color or, for SDK 24+, a color
* state list or a gradient color (See {@link android.R.styleable#GradientColor}
* and {@link android.R.styleable#GradientColorItem}).
* If this property is animated, any value set by the animation will override the original value.
* No path outline is drawn if this property is not specified.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:strokeWidth</code></dt>
* <dd>The width a path stroke.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:strokeAlpha</code></dt>
* <dd>The opacity of a path stroke.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:fillAlpha</code></dt>
* <dd>The opacity to fill the path with.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:trimPathStart</code></dt>
* <dd>The fraction of the path to trim from the start, in the range from 0 to 1.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:trimPathEnd</code></dt>
* <dd>The fraction of the path to trim from the end, in the range from 0 to 1.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:trimPathOffset</code></dt>
* <dd>Shift trim region (allows showed region to include the start and end), in the range
* from 0 to 1.</dd>
+ * <dd>Animatable : Yes.</dd>
* <dt><code>android:strokeLineCap</code></dt>
* <dd>Sets the linecap for a stroked path: butt, round, square.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:strokeLineJoin</code></dt>
* <dd>Sets the lineJoin for a stroked path: miter,round,bevel.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:strokeMiterLimit</code></dt>
* <dd>Sets the Miter limit for a stroked path.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:fillType</code></dt>
* <dd>Sets the fillType for a path. The types can be either "evenOdd" or "nonZero". They behave the
* same as SVG's "fill-rule" properties. For more details, see
* <a href="https://www.w3.org/TR/SVG/painting.html#FillRuleProperty">FillRuleProperty</a></dd>
+ * <dd>Animatable : No.</dd>
* </dl></dd>
+ *
* </dl>
*
* <dl>
@@ -183,9 +216,11 @@
* <dl>
* <dt><code>android:name</code></dt>
* <dd>Defines the name of the clip path.</dd>
+ * <dd>Animatable : No.</dd>
* <dt><code>android:pathData</code></dt>
* <dd>Defines clip path using the same format as "d" attribute
* in the SVG's path data.</dd>
+ * <dd>Animatable : Yes.</dd>
* </dl></dd>
* </dl>
* <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
@@ -710,7 +745,11 @@
groupStack.push(state.mRootGroup);
int eventType = parser.getEventType();
- while (eventType != XmlPullParser.END_DOCUMENT) {
+ final int innerDepth = parser.getDepth() + 1;
+
+ // Parse everything until the end of the vector element.
+ while (eventType != XmlPullParser.END_DOCUMENT
+ && (parser.getDepth() >= innerDepth || eventType != XmlPullParser.END_TAG)) {
if (eventType == XmlPullParser.START_TAG) {
final String tagName = parser.getName();
final VGroup currentGroup = groupStack.peek();
@@ -2112,41 +2151,61 @@
abstract Property getProperty(String propertyName);
}
- private static native long nCreateTree(long rootGroupPtr);
- private static native long nCreateTreeFromCopy(long treeToCopy, long rootGroupPtr);
- private static native void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
- float viewportHeight);
- private static native boolean nSetRootAlpha(long rendererPtr, float alpha);
- private static native float nGetRootAlpha(long rendererPtr);
- private static native void nSetAllowCaching(long rendererPtr, boolean allowCaching);
-
private static native int nDraw(long rendererPtr, long canvasWrapperPtr,
long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache);
- private static native long nCreateFullPath();
- private static native long nCreateFullPath(long nativeFullPathPtr);
private static native boolean nGetFullPathProperties(long pathPtr, byte[] properties,
int length);
+ private static native void nSetName(long nodePtr, String name);
+ private static native boolean nGetGroupProperties(long groupPtr, float[] properties,
+ int length);
+ private static native void nSetPathString(long pathPtr, String pathString, int length);
+ // ------------- @FastNative ------------------
+
+ @FastNative
+ private static native long nCreateTree(long rootGroupPtr);
+ @FastNative
+ private static native long nCreateTreeFromCopy(long treeToCopy, long rootGroupPtr);
+ @FastNative
+ private static native void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
+ float viewportHeight);
+ @FastNative
+ private static native boolean nSetRootAlpha(long rendererPtr, float alpha);
+ @FastNative
+ private static native float nGetRootAlpha(long rendererPtr);
+ @FastNative
+ private static native void nSetAllowCaching(long rendererPtr, boolean allowCaching);
+
+ @FastNative
+ private static native long nCreateFullPath();
+ @FastNative
+ private static native long nCreateFullPath(long nativeFullPathPtr);
+
+ @FastNative
private static native void nUpdateFullPathProperties(long pathPtr, float strokeWidth,
int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
int strokeLineJoin, int fillType);
+ @FastNative
private static native void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr);
+ @FastNative
private static native void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr);
+ @FastNative
private static native long nCreateClipPath();
+ @FastNative
private static native long nCreateClipPath(long clipPathPtr);
+ @FastNative
private static native long nCreateGroup();
+ @FastNative
private static native long nCreateGroup(long groupPtr);
- private static native void nSetName(long nodePtr, String name);
- private static native boolean nGetGroupProperties(long groupPtr, float[] properties,
- int length);
+ @FastNative
private static native void nUpdateGroupProperties(long groupPtr, float rotate, float pivotX,
float pivotY, float scaleX, float scaleY, float translateX, float translateY);
+ @FastNative
private static native void nAddChild(long groupPtr, long nodePtr);
- private static native void nSetPathString(long pathPtr, String pathString, int length);
/**
* The setters and getters below for paths and groups are here temporarily, and will be
@@ -2155,37 +2214,68 @@
* for VD during animation, and these setters and getters will be obsolete.
*/
// Setters and getters during animation.
+ @FastNative
private static native float nGetRotation(long groupPtr);
+ @FastNative
private static native void nSetRotation(long groupPtr, float rotation);
+ @FastNative
private static native float nGetPivotX(long groupPtr);
+ @FastNative
private static native void nSetPivotX(long groupPtr, float pivotX);
+ @FastNative
private static native float nGetPivotY(long groupPtr);
+ @FastNative
private static native void nSetPivotY(long groupPtr, float pivotY);
+ @FastNative
private static native float nGetScaleX(long groupPtr);
+ @FastNative
private static native void nSetScaleX(long groupPtr, float scaleX);
+ @FastNative
private static native float nGetScaleY(long groupPtr);
+ @FastNative
private static native void nSetScaleY(long groupPtr, float scaleY);
+ @FastNative
private static native float nGetTranslateX(long groupPtr);
+ @FastNative
private static native void nSetTranslateX(long groupPtr, float translateX);
+ @FastNative
private static native float nGetTranslateY(long groupPtr);
+ @FastNative
private static native void nSetTranslateY(long groupPtr, float translateY);
// Setters and getters for VPath during animation.
+ @FastNative
private static native void nSetPathData(long pathPtr, long pathDataPtr);
+ @FastNative
private static native float nGetStrokeWidth(long pathPtr);
+ @FastNative
private static native void nSetStrokeWidth(long pathPtr, float width);
+ @FastNative
private static native int nGetStrokeColor(long pathPtr);
+ @FastNative
private static native void nSetStrokeColor(long pathPtr, int strokeColor);
+ @FastNative
private static native float nGetStrokeAlpha(long pathPtr);
+ @FastNative
private static native void nSetStrokeAlpha(long pathPtr, float alpha);
+ @FastNative
private static native int nGetFillColor(long pathPtr);
+ @FastNative
private static native void nSetFillColor(long pathPtr, int fillColor);
+ @FastNative
private static native float nGetFillAlpha(long pathPtr);
+ @FastNative
private static native void nSetFillAlpha(long pathPtr, float fillAlpha);
+ @FastNative
private static native float nGetTrimPathStart(long pathPtr);
+ @FastNative
private static native void nSetTrimPathStart(long pathPtr, float trimPathStart);
+ @FastNative
private static native float nGetTrimPathEnd(long pathPtr);
+ @FastNative
private static native void nSetTrimPathEnd(long pathPtr, float trimPathEnd);
+ @FastNative
private static native float nGetTrimPathOffset(long pathPtr);
+ @FastNative
private static native void nSetTrimPathOffset(long pathPtr, float trimPathOffset);
}
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 0b22802..3b5cdce 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -59,10 +59,7 @@
* single instance may be shared across multiple threads, and a single
* thread may have more than one instance (the latter is discouraged).
*
- * The purpose of the AssetManager is to create Asset objects. To do
- * this efficiently it may cache information about the locations of
- * files it has seen. This can be controlled with the "cacheMode"
- * argument.
+ * The purpose of the AssetManager is to create Asset objects.
*
* The asset hierarchy may be examined like a filesystem, using
* AssetDir objects to peruse a single directory.
@@ -73,24 +70,16 @@
static const char* IDMAP_BIN;
static const char* OVERLAY_DIR;
/*
- * If OVERLAY_SUBDIR_PROPERTY is set, search for runtime resource overlay
- * APKs in OVERLAY_SUBDIR/<value of OVERLAY_SUBDIR_PROPERTY>/ rather than in
+ * If OVERLAY_SKU_DIR_PROPERTY is set, search for runtime resource overlay
+ * APKs in OVERLAY_DIR/<value of OVERLAY_SKU_DIR_PROPERTY> rather than in
* OVERLAY_DIR.
*/
- static const char* OVERLAY_SUBDIR;
- static const char* OVERLAY_SUBDIR_PROPERTY;
+ static const char* OVERLAY_SKU_DIR_PROPERTY;
static const char* TARGET_PACKAGE_NAME;
static const char* TARGET_APK_PATH;
static const char* IDMAP_DIR;
- typedef enum CacheMode {
- CACHE_UNKNOWN = 0,
- CACHE_OFF, // don't try to cache file locations
- CACHE_DEFER, // construct cache as pieces are needed
- //CACHE_SCAN, // scan full(!) asset hierarchy at init() time
- } CacheMode;
-
- AssetManager(CacheMode cacheMode = CACHE_OFF);
+ AssetManager();
virtual ~AssetManager(void);
static int32_t getGlobalCount();
@@ -127,23 +116,16 @@
int32_t nextAssetPath(const int32_t cookie) const;
/*
- * Return an asset path in the manager. 'which' must be between 0 and
- * countAssetPaths().
+ * Return an asset path in the manager. 'cookie' must be a non-negative value
+ * previously returned from addAssetPath() or nextAssetPath().
*/
String8 getAssetPath(const int32_t cookie) const;
/*
- * Set the current locale and vendor. The locale can change during
- * the lifetime of an AssetManager if the user updates the device's
- * language setting. The vendor is less likely to change.
- *
- * Pass in NULL to indicate no preference.
- */
- void setLocale(const char* locale);
- void setVendor(const char* vendor);
-
- /*
- * Choose screen orientation for resources values returned.
+ * Sets various device configuration parameters, like screen orientation, layout,
+ * size, locale, etc.
+ * The optional 'locale' string takes precedence over the locale within 'config'
+ * and must be in bcp47 format.
*/
void setConfiguration(const ResTable_config& config, const char* locale = NULL);
@@ -154,9 +136,6 @@
/*
* Open an asset.
*
- * This will search through locale-specific and vendor-specific
- * directories and packages to find the file.
- *
* The object returned does not depend on the AssetManager. It should
* be freed by calling Asset::close().
*/
@@ -166,9 +145,8 @@
* Open a non-asset file as an asset.
*
* This is for opening files that are included in an asset package
- * but aren't assets. These sit outside the usual "locale/vendor"
- * path hierarchy, and will not be seen by "AssetDir" or included
- * in our filename cache.
+ * but aren't assets. These sit outside the usual "assets/"
+ * path hierarchy, and will not be seen by "AssetDir".
*/
Asset* openNonAsset(const char* fileName, AccessMode mode, int32_t* outCookie = NULL);
@@ -181,11 +159,6 @@
/*
* Open a directory within the asset hierarchy.
*
- * The contents of the directory are an amalgam of vendor-specific,
- * locale-specific, and generic assets stored loosely or in asset
- * packages. Depending on the cache setting and previous accesses,
- * this call may incur significant disk overhead.
- *
* To open the top-level directory, pass in "".
*/
AssetDir* openDir(const char* dirName);
@@ -193,11 +166,6 @@
/*
* Open a directory within a particular path of the asset manager.
*
- * The contents of the directory are an amalgam of vendor-specific,
- * locale-specific, and generic assets stored loosely or in asset
- * packages. Depending on the cache setting and previous accesses,
- * this call may incur significant disk overhead.
- *
* To open the top-level directory, pass in "".
*/
AssetDir* openNonAssetDir(const int32_t cookie, const char* dirName);
@@ -216,13 +184,6 @@
const ResTable& getResources(bool required = true) const;
/*
- * Discard cached filename information. This only needs to be called
- * if somebody has updated the set of "loose" files, and we want to
- * discard our cached notion of what's where.
- */
- void purge(void) { purgeFileNameCacheLocked(); }
-
- /*
* Return true if the files this AssetManager references are all
* up-to-date (have not been changed since it was created). If false
* is returned, you will need to create a new AssetManager to get
@@ -254,14 +215,8 @@
bool isSystemAsset;
};
- Asset* openInPathLocked(const char* fileName, AccessMode mode,
- const asset_path& path);
Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
const asset_path& path);
- Asset* openInLocaleVendorLocked(const char* fileName, AccessMode mode,
- const asset_path& path, const char* locale, const char* vendor);
- String8 createPathNameLocked(const asset_path& path, const char* locale,
- const char* vendor);
String8 createPathNameLocked(const asset_path& path, const char* rootDir);
String8 createZipSourceNameLocked(const String8& zipFileName,
const String8& dirName, const String8& fileName);
@@ -279,15 +234,6 @@
void mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
const SortedVector<AssetDir::FileInfo>* pContents);
- void loadFileNameCacheLocked(void);
- void fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
- const char* dirName);
- bool fncScanAndMergeDirLocked(
- SortedVector<AssetDir::FileInfo>* pMergedInfo,
- const asset_path& path, const char* locale, const char* vendor,
- const char* dirName);
- void purgeFileNameCacheLocked(void);
-
const ResTable* getResTable(bool required = true) const;
void setLocaleLocked(const char* locale);
void updateResourceParamsLocked() const;
@@ -344,8 +290,8 @@
*/
class ZipSet {
public:
- ZipSet(void);
- ~ZipSet(void);
+ ZipSet() = default;
+ ~ZipSet();
/*
* Return a ZipFileRO structure for a ZipFileRO with the specified
@@ -382,23 +328,9 @@
Vector<asset_path> mAssetPaths;
char* mLocale;
- char* mVendor;
mutable ResTable* mResources;
ResTable_config* mConfig;
-
- /*
- * Cached data for "loose" files. This lets us avoid poking at the
- * filesystem when searching for loose assets. Each entry is the
- * "extended partial" path, e.g. "default/default/foo/bar.txt". The
- * full set of files is present, including ".EXCLUDE" entries.
- *
- * We do not cache directory names. We don't retain the ".gz",
- * because to our clients "foo" and "foo.gz" both look like "foo".
- */
- CacheMode mCacheMode; // is the cache enabled?
- bool mCacheValid; // clear when locale or vendor changes
- SortedVector<AssetDir::FileInfo> mCache;
};
}; // namespace android
diff --git a/include/androidfw/AttributeResolution.h b/include/androidfw/AttributeResolution.h
new file mode 100644
index 0000000..2f60a1d
--- /dev/null
+++ b/include/androidfw/AttributeResolution.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROIDFW_ATTRIBUTERESOLUTION_H
+#define ANDROIDFW_ATTRIBUTERESOLUTION_H
+
+#include <androidfw/ResourceTypes.h>
+
+namespace android {
+
+// These are all variations of the same method. They each perform the exact same operation,
+// but on various data sources. I *think* they are re-written to avoid an extra branch
+// in the inner loop, but after one branch miss (some pointer != null), the branch predictor should
+// predict the rest of the iterations' branch correctly.
+// TODO(adamlesinski): Run performance tests against these methods and a new, single method
+// that uses all the sources and branches to the right ones within the inner loop.
+
+bool resolveAttrs(ResTable::Theme* theme,
+ uint32_t defStyleAttr,
+ uint32_t defStyleRes,
+ uint32_t* srcValues, size_t srcValuesLength,
+ uint32_t* attrs, size_t attrsLength,
+ uint32_t* outValues,
+ uint32_t* outIndices);
+
+bool applyStyle(ResTable::Theme* theme, ResXMLParser* xmlParser,
+ uint32_t defStyleAttr,
+ uint32_t defStyleRes,
+ uint32_t* attrs, size_t attrsLength,
+ uint32_t* outValues,
+ uint32_t* outIndices);
+
+bool retrieveAttributes(const ResTable* res, ResXMLParser* xmlParser,
+ uint32_t* attrs, size_t attrsLength,
+ uint32_t* outValues,
+ uint32_t* outIndices);
+
+} // namespace android
+
+#endif /* ANDROIDFW_ATTRIBUTERESOLUTION_H */
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 70e4b6f..00d786a 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -626,6 +626,16 @@
}
}
+ /**
+ * Notify keystore that the device went off-body.
+ */
+ public void onDeviceOffBody() {
+ try {
+ mBinder.onDeviceOffBody();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ }
+ }
/**
* Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index 6bbfcd2..7d7d42c7 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -21,6 +21,7 @@
Asset.cpp \
AssetDir.cpp \
AssetManager.cpp \
+ AttributeResolution.cpp \
LocaleData.cpp \
misc.cpp \
ObbFile.cpp \
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index fe78cef..371bc9a 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -35,6 +35,9 @@
#include <utils/threads.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
+#ifndef _WIN32
+#include <sys/file.h>
+#endif
#include <assert.h>
#include <dirent.h>
@@ -56,12 +59,6 @@
static const bool kIsDebug = false;
-/*
- * Names for default app, locale, and vendor. We might want to change
- * these to be an actual locale, e.g. always use en-US as the default.
- */
-static const char* kDefaultLocale = "default";
-static const char* kDefaultVendor = "default";
static const char* kAssetsRoot = "assets";
static const char* kAppZipName = NULL; //"classes.jar";
static const char* kSystemAssets = "framework/framework-res.apk";
@@ -76,75 +73,70 @@
const char* AssetManager::RESOURCES_FILENAME = "resources.arsc";
const char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
const char* AssetManager::OVERLAY_DIR = "/vendor/overlay";
+const char* AssetManager::OVERLAY_SKU_DIR_PROPERTY = "ro.boot.vendor.overlay.sku";
const char* AssetManager::TARGET_PACKAGE_NAME = "android";
const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
-const char* AssetManager::OVERLAY_SUBDIR = "/system/vendor/overlay-subdir";
-const char* AssetManager::OVERLAY_SUBDIR_PROPERTY = "ro.boot.vendor.overlay.subdir";
const char* AssetManager::IDMAP_DIR = "/data/resource-cache";
namespace {
- String8 idmapPathForPackagePath(const String8& pkgPath)
- {
- const char* root = getenv("ANDROID_DATA");
- LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
- String8 path(root);
- path.appendPath(kResourceCache);
- char buf[256]; // 256 chars should be enough for anyone...
- strncpy(buf, pkgPath.string(), 255);
- buf[255] = '\0';
- char* filename = buf;
- while (*filename && *filename == '/') {
- ++filename;
- }
- char* p = filename;
- while (*p) {
- if (*p == '/') {
- *p = '@';
- }
- ++p;
- }
- path.appendPath(filename);
- path.append("@idmap");
+String8 idmapPathForPackagePath(const String8& pkgPath) {
+ const char* root = getenv("ANDROID_DATA");
+ LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
+ String8 path(root);
+ path.appendPath(kResourceCache);
- return path;
+ char buf[256]; // 256 chars should be enough for anyone...
+ strncpy(buf, pkgPath.string(), 255);
+ buf[255] = '\0';
+ char* filename = buf;
+ while (*filename && *filename == '/') {
+ ++filename;
}
-
- /*
- * Like strdup(), but uses C++ "new" operator instead of malloc.
- */
- static char* strdupNew(const char* str)
- {
- char* newStr;
- int len;
-
- if (str == NULL)
- return NULL;
-
- len = strlen(str);
- newStr = new char[len+1];
- memcpy(newStr, str, len+1);
-
- return newStr;
+ char* p = filename;
+ while (*p) {
+ if (*p == '/') {
+ *p = '@';
+ }
+ ++p;
}
+ path.appendPath(filename);
+ path.append("@idmap");
+
+ return path;
}
/*
+ * Like strdup(), but uses C++ "new" operator instead of malloc.
+ */
+static char* strdupNew(const char* str) {
+ char* newStr;
+ int len;
+
+ if (str == NULL)
+ return NULL;
+
+ len = strlen(str);
+ newStr = new char[len+1];
+ memcpy(newStr, str, len+1);
+
+ return newStr;
+}
+
+} // namespace
+
+/*
* ===========================================================================
* AssetManager
* ===========================================================================
*/
-int32_t AssetManager::getGlobalCount()
-{
+int32_t AssetManager::getGlobalCount() {
return gCount;
}
-AssetManager::AssetManager(CacheMode cacheMode)
- : mLocale(NULL), mVendor(NULL),
- mResources(NULL), mConfig(new ResTable_config),
- mCacheMode(cacheMode), mCacheValid(false)
-{
+AssetManager::AssetManager() :
+ mLocale(NULL), mResources(NULL), mConfig(new ResTable_config) {
int count = android_atomic_inc(&gCount) + 1;
if (kIsDebug) {
ALOGI("Creating AssetManager %p #%d\n", this, count);
@@ -152,8 +144,7 @@
memset(mConfig, 0, sizeof(ResTable_config));
}
-AssetManager::~AssetManager(void)
-{
+AssetManager::~AssetManager() {
int count = android_atomic_dec(&gCount);
if (kIsDebug) {
ALOGI("Destroying AssetManager in %p #%d\n", this, count);
@@ -164,12 +155,10 @@
// don't have a String class yet, so make sure we clean up
delete[] mLocale;
- delete[] mVendor;
}
bool AssetManager::addAssetPath(
- const String8& path, int32_t* cookie, bool appAsLib, bool isSystemAsset)
-{
+ const String8& path, int32_t* cookie, bool appAsLib, bool isSystemAsset) {
AutoMutex _l(mLock);
asset_path ap;
@@ -344,25 +333,9 @@
return String8();
}
-/*
- * Set the current locale. Use NULL to indicate no locale.
- *
- * Close and reopen Zip archives as appropriate, and reset cached
- * information in the locale-specific sections of the tree.
- */
-void AssetManager::setLocale(const char* locale)
-{
- AutoMutex _l(mLock);
- setLocaleLocked(locale);
-}
-
-
void AssetManager::setLocaleLocked(const char* locale)
{
if (mLocale != NULL) {
- /* previously set, purge cached data */
- purgeFileNameCacheLocked();
- //mZipSet.purgeLocale();
delete[] mLocale;
}
@@ -370,25 +343,6 @@
updateResourceParamsLocked();
}
-/*
- * Set the current vendor. Use NULL to indicate no vendor.
- *
- * Close and reopen Zip archives as appropriate, and reset cached
- * information in the vendor-specific sections of the tree.
- */
-void AssetManager::setVendor(const char* vendor)
-{
- AutoMutex _l(mLock);
-
- if (mVendor != NULL) {
- /* previously set, purge cached data */
- purgeFileNameCacheLocked();
- //mZipSet.purgeVendor();
- delete[] mVendor;
- }
- mVendor = strdupNew(vendor);
-}
-
void AssetManager::setConfiguration(const ResTable_config& config, const char* locale)
{
AutoMutex _l(mLock);
@@ -413,23 +367,11 @@
/*
* Open an asset.
*
- * The data could be;
- * - In a file on disk (assetBase + fileName).
- * - In a compressed file on disk (assetBase + fileName.gz).
- * - In a Zip archive, uncompressed or compressed.
+ * The data could be in any asset path. Each asset path could be:
+ * - A directory on disk.
+ * - A Zip archive, uncompressed or compressed.
*
- * It can be in a number of different directories and Zip archives.
- * The search order is:
- * - [appname]
- * - locale + vendor
- * - "default" + vendor
- * - locale + "default"
- * - "default + "default"
- * - "common"
- * - (same as above)
- *
- * To find a particular file, we have to try up to eight paths with
- * all three forms of data.
+ * If the file is in a directory, it could have a .gz suffix, meaning it is compressed.
*
* We should probably reject requests for "illegal" filenames, e.g. those
* with illegal characters or "../" backward relative paths.
@@ -440,10 +382,6 @@
LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
-
- if (mCacheMode != CACHE_OFF && !mCacheValid)
- loadFileNameCacheLocked();
-
String8 assetName(kAssetsRoot);
assetName.appendPath(fileName);
@@ -468,8 +406,7 @@
/*
* Open a non-asset file as if it were an asset.
*
- * The "fileName" is the partial path starting from the application
- * name.
+ * The "fileName" is the partial path starting from the application name.
*/
Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode, int32_t* outCookie)
{
@@ -477,10 +414,6 @@
LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
-
- if (mCacheMode != CACHE_OFF && !mCacheValid)
- loadFileNameCacheLocked();
-
/*
* For each top-level asset path, search for the asset.
*/
@@ -508,9 +441,6 @@
LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
- if (mCacheMode != CACHE_OFF && !mCacheValid)
- loadFileNameCacheLocked();
-
if (which < mAssetPaths.size()) {
ALOGV("Looking for non-asset '%s' in '%s'\n", fileName,
mAssetPaths.itemAt(which).path.string());
@@ -542,10 +472,11 @@
pAsset = open(fileName, Asset::ACCESS_STREAMING);
delete pAsset;
- if (pAsset == NULL)
+ if (pAsset == NULL) {
return kFileTypeNonexistent;
- else
+ } else {
return kFileTypeRegular;
+ }
}
bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) const {
@@ -660,10 +591,6 @@
LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
}
- if (mCacheMode != CACHE_OFF && !mCacheValid) {
- const_cast<AssetManager*>(this)->loadFileNameCacheLocked();
- }
-
mResources = new ResTable();
updateResourceParamsLocked();
@@ -723,6 +650,12 @@
return;
}
+#ifndef _WIN32
+ if (TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_SH)) != 0) {
+ fclose(fin);
+ return;
+ }
+#endif
char buf[1024];
while (fgets(buf, sizeof(buf), fin)) {
// format of each line:
@@ -753,6 +686,10 @@
const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
}
}
+
+#ifndef _WIN32
+ TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_UN));
+#endif
fclose(fin);
}
@@ -834,158 +771,6 @@
}
/*
- * Open an asset, searching for it in the directory hierarchy for the
- * specified app.
- *
- * Pass in a NULL values for "appName" if the common app directory should
- * be used.
- */
-Asset* AssetManager::openInPathLocked(const char* fileName, AccessMode mode,
- const asset_path& ap)
-{
- Asset* pAsset = NULL;
-
- /*
- * Try various combinations of locale and vendor.
- */
- if (mLocale != NULL && mVendor != NULL)
- pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, mVendor);
- if (pAsset == NULL && mVendor != NULL)
- pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, mVendor);
- if (pAsset == NULL && mLocale != NULL)
- pAsset = openInLocaleVendorLocked(fileName, mode, ap, mLocale, NULL);
- if (pAsset == NULL)
- pAsset = openInLocaleVendorLocked(fileName, mode, ap, NULL, NULL);
-
- return pAsset;
-}
-
-/*
- * Open an asset, searching for it in the directory hierarchy for the
- * specified locale and vendor.
- *
- * We also search in "app.jar".
- *
- * Pass in NULL values for "appName", "locale", and "vendor" if the
- * defaults should be used.
- */
-Asset* AssetManager::openInLocaleVendorLocked(const char* fileName, AccessMode mode,
- const asset_path& ap, const char* locale, const char* vendor)
-{
- Asset* pAsset = NULL;
-
- if (ap.type == kFileTypeDirectory) {
- if (mCacheMode == CACHE_OFF) {
- /* look at the filesystem on disk */
- String8 path(createPathNameLocked(ap, locale, vendor));
- path.appendPath(fileName);
-
- String8 excludeName(path);
- excludeName.append(kExcludeExtension);
- if (::getFileType(excludeName.string()) != kFileTypeNonexistent) {
- /* say no more */
- //printf("+++ excluding '%s'\n", (const char*) excludeName);
- return kExcludedAsset;
- }
-
- pAsset = openAssetFromFileLocked(path, mode);
-
- if (pAsset == NULL) {
- /* try again, this time with ".gz" */
- path.append(".gz");
- pAsset = openAssetFromFileLocked(path, mode);
- }
-
- if (pAsset != NULL)
- pAsset->setAssetSource(path);
- } else {
- /* find in cache */
- String8 path(createPathNameLocked(ap, locale, vendor));
- path.appendPath(fileName);
-
- AssetDir::FileInfo tmpInfo;
- bool found = false;
-
- String8 excludeName(path);
- excludeName.append(kExcludeExtension);
-
- if (mCache.indexOf(excludeName) != NAME_NOT_FOUND) {
- /* go no farther */
- //printf("+++ Excluding '%s'\n", (const char*) excludeName);
- return kExcludedAsset;
- }
-
- /*
- * File compression extensions (".gz") don't get stored in the
- * name cache, so we have to try both here.
- */
- if (mCache.indexOf(path) != NAME_NOT_FOUND) {
- found = true;
- pAsset = openAssetFromFileLocked(path, mode);
- if (pAsset == NULL) {
- /* try again, this time with ".gz" */
- path.append(".gz");
- pAsset = openAssetFromFileLocked(path, mode);
- }
- }
-
- if (pAsset != NULL)
- pAsset->setAssetSource(path);
-
- /*
- * Don't continue the search into the Zip files. Our cached info
- * said it was a file on disk; to be consistent with openDir()
- * we want to return the loose asset. If the cached file gets
- * removed, we fail.
- *
- * The alternative is to update our cache when files get deleted,
- * or make some sort of "best effort" promise, but for now I'm
- * taking the hard line.
- */
- if (found) {
- if (pAsset == NULL)
- ALOGD("Expected file not found: '%s'\n", path.string());
- return pAsset;
- }
- }
- }
-
- /*
- * Either it wasn't found on disk or on the cached view of the disk.
- * Dig through the currently-opened set of Zip files. If caching
- * is disabled, the Zip file may get reopened.
- */
- if (pAsset == NULL && ap.type == kFileTypeRegular) {
- String8 path;
-
- path.appendPath((locale != NULL) ? locale : kDefaultLocale);
- path.appendPath((vendor != NULL) ? vendor : kDefaultVendor);
- path.appendPath(fileName);
-
- /* check the appropriate Zip file */
- ZipFileRO* pZip = getZipFileLocked(ap);
- if (pZip != NULL) {
- //printf("GOT zip, checking '%s'\n", (const char*) path);
- ZipEntryRO entry = pZip->findEntryByName(path.string());
- if (entry != NULL) {
- //printf("FOUND in Zip file for %s/%s-%s\n",
- // appName, locale, vendor);
- pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
- pZip->releaseEntry(entry);
- }
- }
-
- if (pAsset != NULL) {
- /* create a "source" name, for debug/display */
- pAsset->setAssetSource(createZipSourceNameLocked(ZipSet::getPathName(ap.path.string()),
- String8(""), String8(fileName)));
- }
- }
-
- return pAsset;
-}
-
-/*
* Create a "source name" for a file from a Zip archive.
*/
String8 AssetManager::createZipSourceNameLocked(const String8& zipFileName,
@@ -1002,18 +787,6 @@
}
/*
- * Create a path to a loose asset (asset-base/app/locale/vendor).
- */
-String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* locale,
- const char* vendor)
-{
- String8 path(ap.path);
- path.appendPath((locale != NULL) ? locale : kDefaultLocale);
- path.appendPath((vendor != NULL) ? vendor : kDefaultVendor);
- return path;
-}
-
-/*
* Create a path to a loose asset (asset-base/app/rootDir).
*/
String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* rootDir)
@@ -1026,15 +799,6 @@
/*
* Return a pointer to one of our open Zip archives. Returns NULL if no
* matching Zip file exists.
- *
- * Right now we have 2 possible Zip files (1 each in app/"common").
- *
- * If caching is set to CACHE_OFF, to get the expected behavior we
- * need to reopen the Zip file on every request. That would be silly
- * and expensive, so instead we just check the file modification date.
- *
- * Pass in NULL values for "appName", "locale", and "vendor" if the
- * generics should be used.
*/
ZipFileRO* AssetManager::getZipFileLocked(const asset_path& ap)
{
@@ -1119,14 +883,10 @@
return pAsset;
}
-
-
/*
* Open a directory in the asset namespace.
*
- * An "asset directory" is simply the combination of all files in all
- * locations, with ".gz" stripped for loose files. With app, locale, and
- * vendor defined, we have 8 directories and 2 Zip archives to scan.
+ * An "asset directory" is simply the combination of all asset paths' "assets/" directories.
*
* Pass in "" for the root dir.
*/
@@ -1142,9 +902,6 @@
//printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase);
- if (mCacheMode != CACHE_OFF && !mCacheValid)
- loadFileNameCacheLocked();
-
pDir = new AssetDir;
/*
@@ -1187,9 +944,7 @@
/*
* Open a directory in the non-asset namespace.
*
- * An "asset directory" is simply the combination of all files in all
- * locations, with ".gz" stripped for loose files. With app, locale, and
- * vendor defined, we have 8 directories and 2 Zip archives to scan.
+ * An "asset directory" is simply the combination of all asset paths' "assets/" directories.
*
* Pass in "" for the root dir.
*/
@@ -1205,9 +960,6 @@
//printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase);
- if (mCacheMode != CACHE_OFF && !mCacheValid)
- loadFileNameCacheLocked();
-
pDir = new AssetDir;
pMergedInfo = new SortedVector<AssetDir::FileInfo>;
@@ -1248,74 +1000,17 @@
bool AssetManager::scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
const asset_path& ap, const char* rootDir, const char* dirName)
{
- SortedVector<AssetDir::FileInfo>* pContents;
- String8 path;
-
assert(pMergedInfo != NULL);
- //printf("scanAndMergeDir: %s %s %s %s\n", appName, locale, vendor,dirName);
+ //printf("scanAndMergeDir: %s %s %s\n", ap.path.string(), rootDir, dirName);
- if (mCacheValid) {
- int i, start, count;
+ String8 path = createPathNameLocked(ap, rootDir);
+ if (dirName[0] != '\0')
+ path.appendPath(dirName);
- pContents = new SortedVector<AssetDir::FileInfo>;
-
- /*
- * Get the basic partial path and find it in the cache. That's
- * the start point for the search.
- */
- path = createPathNameLocked(ap, rootDir);
- if (dirName[0] != '\0')
- path.appendPath(dirName);
-
- start = mCache.indexOf(path);
- if (start == NAME_NOT_FOUND) {
- //printf("+++ not found in cache: dir '%s'\n", (const char*) path);
- delete pContents;
- return false;
- }
-
- /*
- * The match string looks like "common/default/default/foo/bar/".
- * The '/' on the end ensures that we don't match on the directory
- * itself or on ".../foo/barfy/".
- */
- path.append("/");
-
- count = mCache.size();
-
- /*
- * Pick out the stuff in the current dir by examining the pathname.
- * It needs to match the partial pathname prefix, and not have a '/'
- * (fssep) anywhere after the prefix.
- */
- for (i = start+1; i < count; i++) {
- if (mCache[i].getFileName().length() > path.length() &&
- strncmp(mCache[i].getFileName().string(), path.string(), path.length()) == 0)
- {
- const char* name = mCache[i].getFileName().string();
- // XXX THIS IS BROKEN! Looks like we need to store the full
- // path prefix separately from the file path.
- if (strchr(name + path.length(), '/') == NULL) {
- /* grab it, reducing path to just the filename component */
- AssetDir::FileInfo tmp = mCache[i];
- tmp.setFileName(tmp.getFileName().getPathLeaf());
- pContents->add(tmp);
- }
- } else {
- /* no longer in the dir or its subdirs */
- break;
- }
-
- }
- } else {
- path = createPathNameLocked(ap, rootDir);
- if (dirName[0] != '\0')
- path.appendPath(dirName);
- pContents = scanDirLocked(path);
- if (pContents == NULL)
- return false;
- }
+ SortedVector<AssetDir::FileInfo>* pContents = scanDirLocked(path);
+ if (pContents == NULL)
+ return false;
// if we wanted to do an incremental cache fill, we would do it here
@@ -1642,153 +1337,6 @@
#endif
}
-
-/*
- * Load all files into the file name cache. We want to do this across
- * all combinations of { appname, locale, vendor }, performing a recursive
- * directory traversal.
- *
- * This is not the most efficient data structure. Also, gathering the
- * information as we needed it (file-by-file or directory-by-directory)
- * would be faster. However, on the actual device, 99% of the files will
- * live in Zip archives, so this list will be very small. The trouble
- * is that we have to check the "loose" files first, so it's important
- * that we don't beat the filesystem silly looking for files that aren't
- * there.
- *
- * Note on thread safety: this is the only function that causes updates
- * to mCache, and anybody who tries to use it will call here if !mCacheValid,
- * so we need to employ a mutex here.
- */
-void AssetManager::loadFileNameCacheLocked(void)
-{
- assert(!mCacheValid);
- assert(mCache.size() == 0);
-
-#ifdef DO_TIMINGS // need to link against -lrt for this now
- DurationTimer timer;
- timer.start();
-#endif
-
- fncScanLocked(&mCache, "");
-
-#ifdef DO_TIMINGS
- timer.stop();
- ALOGD("Cache scan took %.3fms\n",
- timer.durationUsecs() / 1000.0);
-#endif
-
-#if 0
- int i;
- printf("CACHED FILE LIST (%d entries):\n", mCache.size());
- for (i = 0; i < (int) mCache.size(); i++) {
- printf(" %d: (%d) '%s'\n", i,
- mCache.itemAt(i).getFileType(),
- (const char*) mCache.itemAt(i).getFileName());
- }
-#endif
-
- mCacheValid = true;
-}
-
-/*
- * Scan up to 8 versions of the specified directory.
- */
-void AssetManager::fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
- const char* dirName)
-{
- size_t i = mAssetPaths.size();
- while (i > 0) {
- i--;
- const asset_path& ap = mAssetPaths.itemAt(i);
- fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, NULL, dirName);
- if (mLocale != NULL)
- fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, NULL, dirName);
- if (mVendor != NULL)
- fncScanAndMergeDirLocked(pMergedInfo, ap, NULL, mVendor, dirName);
- if (mLocale != NULL && mVendor != NULL)
- fncScanAndMergeDirLocked(pMergedInfo, ap, mLocale, mVendor, dirName);
- }
-}
-
-/*
- * Recursively scan this directory and all subdirs.
- *
- * This is similar to scanAndMergeDir, but we don't remove the .EXCLUDE
- * files, and we prepend the extended partial path to the filenames.
- */
-bool AssetManager::fncScanAndMergeDirLocked(
- SortedVector<AssetDir::FileInfo>* pMergedInfo,
- const asset_path& ap, const char* locale, const char* vendor,
- const char* dirName)
-{
- SortedVector<AssetDir::FileInfo>* pContents;
- String8 partialPath;
- String8 fullPath;
-
- // XXX This is broken -- the filename cache needs to hold the base
- // asset path separately from its filename.
-
- partialPath = createPathNameLocked(ap, locale, vendor);
- if (dirName[0] != '\0') {
- partialPath.appendPath(dirName);
- }
-
- fullPath = partialPath;
- pContents = scanDirLocked(fullPath);
- if (pContents == NULL) {
- return false; // directory did not exist
- }
-
- /*
- * Scan all subdirectories of the current dir, merging what we find
- * into "pMergedInfo".
- */
- for (int i = 0; i < (int) pContents->size(); i++) {
- if (pContents->itemAt(i).getFileType() == kFileTypeDirectory) {
- String8 subdir(dirName);
- subdir.appendPath(pContents->itemAt(i).getFileName());
-
- fncScanAndMergeDirLocked(pMergedInfo, ap, locale, vendor, subdir.string());
- }
- }
-
- /*
- * To be consistent, we want entries for the root directory. If
- * we're the root, add one now.
- */
- if (dirName[0] == '\0') {
- AssetDir::FileInfo tmpInfo;
-
- tmpInfo.set(String8(""), kFileTypeDirectory);
- tmpInfo.setSourceName(createPathNameLocked(ap, locale, vendor));
- pContents->add(tmpInfo);
- }
-
- /*
- * We want to prepend the extended partial path to every entry in
- * "pContents". It's the same value for each entry, so this will
- * not change the sorting order of the vector contents.
- */
- for (int i = 0; i < (int) pContents->size(); i++) {
- const AssetDir::FileInfo& info = pContents->itemAt(i);
- pContents->editItemAt(i).setFileName(partialPath.appendPathCopy(info.getFileName()));
- }
-
- mergeInfoLocked(pMergedInfo, pContents);
- delete pContents;
- return true;
-}
-
-/*
- * Trash the cache.
- */
-void AssetManager::purgeFileNameCacheLocked(void)
-{
- mCacheValid = false;
- mCache.clear();
-}
-
/*
* ===========================================================================
* AssetManager::SharedZip
@@ -1838,6 +1386,7 @@
Asset* AssetManager::SharedZip::getResourceTableAsset()
{
+ AutoMutex _l(gLock);
ALOGV("Getting from SharedZip %p resource asset %p\n", this, mResourceTableAsset);
return mResourceTableAsset;
}
@@ -1847,10 +1396,10 @@
{
AutoMutex _l(gLock);
if (mResourceTableAsset == NULL) {
- mResourceTableAsset = asset;
// This is not thread safe the first time it is called, so
// do it here with the global lock held.
asset->getBuffer(true);
+ mResourceTableAsset = asset;
return asset;
}
}
@@ -1921,13 +1470,6 @@
*/
/*
- * Constructor.
- */
-AssetManager::ZipSet::ZipSet(void)
-{
-}
-
-/*
* Destructor. Close any open archives.
*/
AssetManager::ZipSet::~ZipSet(void)
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
new file mode 100644
index 0000000..ad428a4
--- /dev/null
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "androidfw/AttributeFinder.h"
+#include "androidfw/AttributeResolution.h"
+#include "androidfw/ResourceTypes.h"
+
+#include <android/log.h>
+#include <cstdint>
+
+constexpr bool kDebugStyles = false;
+
+namespace android {
+
+enum {
+ STYLE_NUM_ENTRIES = 6,
+ STYLE_TYPE = 0,
+ STYLE_DATA = 1,
+ STYLE_ASSET_COOKIE = 2,
+ STYLE_RESOURCE_ID = 3,
+ STYLE_CHANGING_CONFIGURATIONS = 4,
+ STYLE_DENSITY = 5
+};
+
+class XmlAttributeFinder : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
+public:
+ explicit XmlAttributeFinder(const ResXMLParser* parser) :
+ BackTrackingAttributeFinder(0, parser != NULL ? parser->getAttributeCount() : 0),
+ mParser(parser) {
+ }
+
+ inline uint32_t getAttribute(size_t index) const {
+ return mParser->getAttributeNameResID(index);
+ }
+
+private:
+ const ResXMLParser* mParser;
+};
+
+class BagAttributeFinder :
+ public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
+public:
+ BagAttributeFinder(const ResTable::bag_entry* start, const ResTable::bag_entry* end) :
+ BackTrackingAttributeFinder(start, end) {}
+
+ inline uint32_t getAttribute(const ResTable::bag_entry* entry) const {
+ return entry->map.name.ident;
+ }
+};
+
+bool resolveAttrs(ResTable::Theme* theme,
+ uint32_t defStyleAttr,
+ uint32_t defStyleRes,
+ uint32_t* srcValues, size_t srcValuesLength,
+ uint32_t* attrs, size_t attrsLength,
+ uint32_t* outValues,
+ uint32_t* outIndices) {
+ if (kDebugStyles) {
+ ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x "
+ "defStyleRes=0x%x", theme, defStyleAttr, defStyleRes);
+ }
+
+ const ResTable& res = theme->getResTable();
+ ResTable_config config;
+ Res_value value;
+
+ int indicesIdx = 0;
+
+ // Load default style from attribute, if specified...
+ uint32_t defStyleBagTypeSetFlags = 0;
+ if (defStyleAttr != 0) {
+ Res_value value;
+ if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
+ if (value.dataType == Res_value::TYPE_REFERENCE) {
+ defStyleRes = value.data;
+ }
+ }
+ }
+
+ // Now lock down the resource object and start pulling stuff from it.
+ res.lock();
+
+ // Retrieve the default style bag, if requested.
+ const ResTable::bag_entry* defStyleStart = NULL;
+ uint32_t defStyleTypeSetFlags = 0;
+ ssize_t bagOff = defStyleRes != 0
+ ? res.getBagLocked(defStyleRes, &defStyleStart, &defStyleTypeSetFlags) : -1;
+ defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
+ const ResTable::bag_entry* const defStyleEnd = defStyleStart + (bagOff >= 0 ? bagOff : 0);
+ BagAttributeFinder defStyleAttrFinder(defStyleStart, defStyleEnd);
+
+ // Now iterate through all of the attributes that the client has requested,
+ // filling in each with whatever data we can find.
+ ssize_t block = 0;
+ uint32_t typeSetFlags;
+ for (size_t ii=0; ii<attrsLength; ii++) {
+ const uint32_t curIdent = attrs[ii];
+
+ if (kDebugStyles) {
+ ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
+ }
+
+ // Try to find a value for this attribute... we prioritize values
+ // coming from, first XML attributes, then XML style, then default
+ // style, and finally the theme.
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = Res_value::DATA_NULL_UNDEFINED;
+ typeSetFlags = 0;
+ config.density = 0;
+
+ // Retrieve the current input value if available.
+ if (srcValuesLength > 0 && srcValues[ii] != 0) {
+ block = -1;
+ value.dataType = Res_value::TYPE_ATTRIBUTE;
+ value.data = srcValues[ii];
+ if (kDebugStyles) {
+ ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
+ }
+ }
+
+ if (value.dataType == Res_value::TYPE_NULL) {
+ const ResTable::bag_entry* const defStyleEntry = defStyleAttrFinder.find(curIdent);
+ if (defStyleEntry != defStyleEnd) {
+ block = defStyleEntry->stringBlock;
+ typeSetFlags = defStyleTypeSetFlags;
+ value = defStyleEntry->map.value;
+ if (kDebugStyles) {
+ ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
+ }
+ }
+ }
+
+ uint32_t resid = 0;
+ if (value.dataType != Res_value::TYPE_NULL) {
+ // Take care of resolving the found resource to its final value.
+ ssize_t newBlock = theme->resolveAttributeReference(&value, block,
+ &resid, &typeSetFlags, &config);
+ if (newBlock >= 0) block = newBlock;
+ if (kDebugStyles) {
+ ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
+ }
+ } else {
+ // If we still don't have a value for this attribute, try to find
+ // it in the theme!
+ ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
+ if (newBlock >= 0) {
+ if (kDebugStyles) {
+ ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+ }
+ newBlock = res.resolveReference(&value, block, &resid,
+ &typeSetFlags, &config);
+ if (newBlock >= 0) block = newBlock;
+ if (kDebugStyles) {
+ ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+ }
+ }
+ }
+
+ // Deal with the special @null value -- it turns back to TYPE_NULL.
+ if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
+ if (kDebugStyles) {
+ ALOGI("-> Setting to @null!");
+ }
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = Res_value::DATA_NULL_UNDEFINED;
+ block = -1;
+ }
+
+ if (kDebugStyles) {
+ ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType,
+ value.data);
+ }
+
+ // Write the final value back to Java.
+ outValues[STYLE_TYPE] = value.dataType;
+ outValues[STYLE_DATA] = value.data;
+ outValues[STYLE_ASSET_COOKIE] = block != -1
+ ? static_cast<uint32_t>(res.getTableCookie(block)) : static_cast<uint32_t>(-1);
+ outValues[STYLE_RESOURCE_ID] = resid;
+ outValues[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+ outValues[STYLE_DENSITY] = config.density;
+
+ if (outIndices != NULL && value.dataType != Res_value::TYPE_NULL) {
+ indicesIdx++;
+ outIndices[indicesIdx] = ii;
+ }
+
+ outValues += STYLE_NUM_ENTRIES;
+ }
+
+ res.unlock();
+
+ if (outIndices != NULL) {
+ outIndices[0] = indicesIdx;
+ }
+ return true;
+}
+
+bool applyStyle(ResTable::Theme* theme, ResXMLParser* xmlParser,
+ uint32_t defStyleAttr,
+ uint32_t defStyleRes,
+ uint32_t* attrs, size_t attrsLength,
+ uint32_t* outValues,
+ uint32_t* outIndices) {
+ if (kDebugStyles) {
+ ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p",
+ theme, defStyleAttr, defStyleRes, xmlParser);
+ }
+
+ const ResTable& res = theme->getResTable();
+ ResTable_config config;
+ Res_value value;
+
+ int indicesIdx = 0;
+
+ // Load default style from attribute, if specified...
+ uint32_t defStyleBagTypeSetFlags = 0;
+ if (defStyleAttr != 0) {
+ Res_value value;
+ if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
+ if (value.dataType == Res_value::TYPE_REFERENCE) {
+ defStyleRes = value.data;
+ }
+ }
+ }
+
+ // Retrieve the style class associated with the current XML tag.
+ int style = 0;
+ uint32_t styleBagTypeSetFlags = 0;
+ if (xmlParser != NULL) {
+ ssize_t idx = xmlParser->indexOfStyle();
+ if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
+ if (value.dataType == value.TYPE_ATTRIBUTE) {
+ if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
+ value.dataType = Res_value::TYPE_NULL;
+ }
+ }
+ if (value.dataType == value.TYPE_REFERENCE) {
+ style = value.data;
+ }
+ }
+ }
+
+ // Now lock down the resource object and start pulling stuff from it.
+ res.lock();
+
+ // Retrieve the default style bag, if requested.
+ const ResTable::bag_entry* defStyleAttrStart = NULL;
+ uint32_t defStyleTypeSetFlags = 0;
+ ssize_t bagOff = defStyleRes != 0
+ ? res.getBagLocked(defStyleRes, &defStyleAttrStart, &defStyleTypeSetFlags) : -1;
+ defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
+ const ResTable::bag_entry* const defStyleAttrEnd = defStyleAttrStart + (bagOff >= 0 ? bagOff : 0);
+ BagAttributeFinder defStyleAttrFinder(defStyleAttrStart, defStyleAttrEnd);
+
+ // Retrieve the style class bag, if requested.
+ const ResTable::bag_entry* styleAttrStart = NULL;
+ uint32_t styleTypeSetFlags = 0;
+ bagOff = style != 0 ? res.getBagLocked(style, &styleAttrStart, &styleTypeSetFlags) : -1;
+ styleTypeSetFlags |= styleBagTypeSetFlags;
+ const ResTable::bag_entry* const styleAttrEnd = styleAttrStart + (bagOff >= 0 ? bagOff : 0);
+ BagAttributeFinder styleAttrFinder(styleAttrStart, styleAttrEnd);
+
+ // Retrieve the XML attributes, if requested.
+ static const ssize_t kXmlBlock = 0x10000000;
+ XmlAttributeFinder xmlAttrFinder(xmlParser);
+ const size_t xmlAttrEnd = xmlParser != NULL ? xmlParser->getAttributeCount() : 0;
+
+ // Now iterate through all of the attributes that the client has requested,
+ // filling in each with whatever data we can find.
+ ssize_t block = 0;
+ uint32_t typeSetFlags;
+ for (size_t ii = 0; ii < attrsLength; ii++) {
+ const uint32_t curIdent = attrs[ii];
+
+ if (kDebugStyles) {
+ ALOGI("RETRIEVING ATTR 0x%08x...", curIdent);
+ }
+
+ // Try to find a value for this attribute... we prioritize values
+ // coming from, first XML attributes, then XML style, then default
+ // style, and finally the theme.
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = Res_value::DATA_NULL_UNDEFINED;
+ typeSetFlags = 0;
+ config.density = 0;
+
+ // Walk through the xml attributes looking for the requested attribute.
+ const size_t xmlAttrIdx = xmlAttrFinder.find(curIdent);
+ if (xmlAttrIdx != xmlAttrEnd) {
+ // We found the attribute we were looking for.
+ block = kXmlBlock;
+ xmlParser->getAttributeValue(xmlAttrIdx, &value);
+ if (kDebugStyles) {
+ ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
+ }
+ }
+
+ if (value.dataType == Res_value::TYPE_NULL) {
+ // Walk through the style class values looking for the requested attribute.
+ const ResTable::bag_entry* const styleAttrEntry = styleAttrFinder.find(curIdent);
+ if (styleAttrEntry != styleAttrEnd) {
+ // We found the attribute we were looking for.
+ block = styleAttrEntry->stringBlock;
+ typeSetFlags = styleTypeSetFlags;
+ value = styleAttrEntry->map.value;
+ if (kDebugStyles) {
+ ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
+ }
+ }
+ }
+
+ if (value.dataType == Res_value::TYPE_NULL) {
+ // Walk through the default style values looking for the requested attribute.
+ const ResTable::bag_entry* const defStyleAttrEntry = defStyleAttrFinder.find(curIdent);
+ if (defStyleAttrEntry != defStyleAttrEnd) {
+ // We found the attribute we were looking for.
+ block = defStyleAttrEntry->stringBlock;
+ typeSetFlags = styleTypeSetFlags;
+ value = defStyleAttrEntry->map.value;
+ if (kDebugStyles) {
+ ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
+ }
+ }
+ }
+
+ uint32_t resid = 0;
+ if (value.dataType != Res_value::TYPE_NULL) {
+ // Take care of resolving the found resource to its final value.
+ ssize_t newBlock = theme->resolveAttributeReference(&value, block,
+ &resid, &typeSetFlags, &config);
+ if (newBlock >= 0) {
+ block = newBlock;
+ }
+
+ if (kDebugStyles) {
+ ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
+ }
+ } else {
+ // If we still don't have a value for this attribute, try to find
+ // it in the theme!
+ ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
+ if (newBlock >= 0) {
+ if (kDebugStyles) {
+ ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+ }
+ newBlock = res.resolveReference(&value, block, &resid,
+ &typeSetFlags, &config);
+
+ if (newBlock >= 0) {
+ block = newBlock;
+ }
+
+ if (kDebugStyles) {
+ ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+ }
+ }
+ }
+
+ // Deal with the special @null value -- it turns back to TYPE_NULL.
+ if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
+ if (kDebugStyles) {
+ ALOGI("-> Setting to @null!");
+ }
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = Res_value::DATA_NULL_UNDEFINED;
+ block = kXmlBlock;
+ }
+
+ if (kDebugStyles) {
+ ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", curIdent, value.dataType, value.data);
+ }
+
+ // Write the final value back to Java.
+ outValues[STYLE_TYPE] = value.dataType;
+ outValues[STYLE_DATA] = value.data;
+ outValues[STYLE_ASSET_COOKIE] = block != kXmlBlock ?
+ static_cast<uint32_t>(res.getTableCookie(block)) : static_cast<uint32_t>(-1);
+ outValues[STYLE_RESOURCE_ID] = resid;
+ outValues[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+ outValues[STYLE_DENSITY] = config.density;
+
+ if (outIndices != NULL && value.dataType != Res_value::TYPE_NULL) {
+ indicesIdx++;
+ outIndices[indicesIdx] = ii;
+ }
+
+ outValues += STYLE_NUM_ENTRIES;
+ }
+
+ res.unlock();
+
+ if (outIndices != NULL) {
+ outIndices[0] = indicesIdx;
+ }
+ return true;
+}
+
+bool retrieveAttributes(const ResTable* res, ResXMLParser* xmlParser,
+ uint32_t* attrs, size_t attrsLength,
+ uint32_t* outValues,
+ uint32_t* outIndices) {
+ ResTable_config config;
+ Res_value value;
+
+ int indicesIdx = 0;
+
+ // Now lock down the resource object and start pulling stuff from it.
+ res->lock();
+
+ // Retrieve the XML attributes, if requested.
+ const size_t NX = xmlParser->getAttributeCount();
+ size_t ix=0;
+ uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
+
+ static const ssize_t kXmlBlock = 0x10000000;
+
+ // Now iterate through all of the attributes that the client has requested,
+ // filling in each with whatever data we can find.
+ ssize_t block = 0;
+ uint32_t typeSetFlags;
+ for (size_t ii=0; ii<attrsLength; ii++) {
+ const uint32_t curIdent = attrs[ii];
+
+ // Try to find a value for this attribute...
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = Res_value::DATA_NULL_UNDEFINED;
+ typeSetFlags = 0;
+ config.density = 0;
+
+ // Skip through XML attributes until the end or the next possible match.
+ while (ix < NX && curIdent > curXmlAttr) {
+ ix++;
+ curXmlAttr = xmlParser->getAttributeNameResID(ix);
+ }
+ // Retrieve the current XML attribute if it matches, and step to next.
+ if (ix < NX && curIdent == curXmlAttr) {
+ block = kXmlBlock;
+ xmlParser->getAttributeValue(ix, &value);
+ ix++;
+ curXmlAttr = xmlParser->getAttributeNameResID(ix);
+ }
+
+ //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
+ uint32_t resid = 0;
+ if (value.dataType != Res_value::TYPE_NULL) {
+ // Take care of resolving the found resource to its final value.
+ //printf("Resolving attribute reference\n");
+ ssize_t newBlock = res->resolveReference(&value, block, &resid,
+ &typeSetFlags, &config);
+ if (newBlock >= 0) block = newBlock;
+ }
+
+ // Deal with the special @null value -- it turns back to TYPE_NULL.
+ if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
+ value.dataType = Res_value::TYPE_NULL;
+ value.data = Res_value::DATA_NULL_UNDEFINED;
+ }
+
+ //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
+
+ // Write the final value back to Java.
+ outValues[STYLE_TYPE] = value.dataType;
+ outValues[STYLE_DATA] = value.data;
+ outValues[STYLE_ASSET_COOKIE] = block != kXmlBlock
+ ? static_cast<uint32_t>(res->getTableCookie(block)) : static_cast<uint32_t>(-1);
+ outValues[STYLE_RESOURCE_ID] = resid;
+ outValues[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+ outValues[STYLE_DENSITY] = config.density;
+
+ if (outIndices != NULL && value.dataType != Res_value::TYPE_NULL) {
+ indicesIdx++;
+ outIndices[indicesIdx] = ii;
+ }
+
+ outValues += STYLE_NUM_ENTRIES;
+ }
+
+ res->unlock();
+
+ if (outIndices != NULL) {
+ outIndices[0] = indicesIdx;
+ }
+ return true;
+}
+
+} // namespace android
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 81a1831..1282846 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-BUGREPORT_FONT_CACHE_USAGE := true
+BUGREPORT_FONT_CACHE_USAGE := false
# Enables fine-grained GLES error checking
# If set to true, every GLES call is wrapped & error checked
@@ -16,6 +16,7 @@
hwui/MinikinSkia.cpp \
hwui/MinikinUtils.cpp \
hwui/PaintImpl.cpp \
+ hwui/PixelRef.cpp \
hwui/Typeface.cpp \
renderstate/Blend.cpp \
renderstate/MeshState.cpp \
@@ -45,7 +46,6 @@
AnimationContext.cpp \
Animator.cpp \
AnimatorManager.cpp \
- AssetAtlas.cpp \
BakedOpDispatcher.cpp \
BakedOpRenderer.cpp \
BakedOpState.cpp \
@@ -56,7 +56,6 @@
DeferredLayerUpdater.cpp \
DeviceInfo.cpp \
DisplayList.cpp \
- Dither.cpp \
Extensions.cpp \
FboCache.cpp \
FontRenderer.cpp \
@@ -95,6 +94,7 @@
ShadowTessellator.cpp \
SkiaCanvas.cpp \
SkiaCanvasProxy.cpp \
+ SkiaDisplayList.cpp \
SkiaShader.cpp \
Snapshot.cpp \
SpotShadow.cpp \
@@ -130,6 +130,14 @@
hwui_cflags += -DUSE_HWC2
endif
+# TODO: Linear blending should be enabled by default, but we are
+# TODO: making it an opt-in while it's a work in progress
+# TODO: The final test should be:
+# TODO: ifneq ($(TARGET_ENABLE_LINEAR_BLENDING),false)
+ifeq ($(TARGET_ENABLE_LINEAR_BLENDING),true)
+ hwui_cflags += -DANDROID_ENABLE_LINEAR_BLENDING
+endif
+
# GCC false-positives on this warning, and since we -Werror that's
# a problem
hwui_cflags += -Wno-free-nonheap-object
@@ -143,7 +151,6 @@
hwui_cflags += -DBUGREPORT_FONT_CACHE_USAGE
endif
-
ifndef HWUI_COMPILE_SYMBOLS
hwui_cflags += -fvisibility=hidden
endif
@@ -280,6 +287,7 @@
tests/unit/RenderNodeTests.cpp \
tests/unit/RenderPropertiesTests.cpp \
tests/unit/SkiaBehaviorTests.cpp \
+ tests/unit/SkiaDisplayListTests.cpp \
tests/unit/SkiaCanvasTests.cpp \
tests/unit/SnapshotTests.cpp \
tests/unit/StringUtilsTests.cpp \
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
deleted file mode 100644
index e2e70372..0000000
--- a/libs/hwui/AssetAtlas.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You 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.
- */
-
-#include "AssetAtlas.h"
-#include "Caches.h"
-#include "Image.h"
-
-#include <GLES2/gl2ext.h>
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Lifecycle
-///////////////////////////////////////////////////////////////////////////////
-
-void AssetAtlas::init(const sp<GraphicBuffer>& buffer, int64_t* map, int count) {
- if (mImage) {
- return;
- }
-
- ATRACE_NAME("AssetAtlas::init");
-
- mImage = new Image(buffer);
- if (mImage->getTexture()) {
- if (!mTexture) {
- Caches& caches = Caches::getInstance();
- mTexture = new Texture(caches);
- mTexture->wrap(mImage->getTexture(),
- buffer->getWidth(), buffer->getHeight(), GL_RGBA);
- createEntries(caches, map, count);
- }
- } else {
- ALOGW("Could not create atlas image");
- terminate();
- }
-}
-
-void AssetAtlas::terminate() {
- delete mImage;
- mImage = nullptr;
- delete mTexture;
- mTexture = nullptr;
- mEntries.clear();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Entries
-///////////////////////////////////////////////////////////////////////////////
-
-AssetAtlas::Entry* AssetAtlas::getEntry(const SkPixelRef* pixelRef) const {
- auto result = mEntries.find(pixelRef);
- return result != mEntries.end() ? result->second.get() : nullptr;
-}
-
-Texture* AssetAtlas::getEntryTexture(const SkPixelRef* pixelRef) const {
- auto result = mEntries.find(pixelRef);
- return result != mEntries.end() ? result->second->texture : nullptr;
-}
-
-/**
- * Delegates changes to wrapping and filtering to the base atlas texture
- * instead of applying the changes to the virtual textures.
- */
-struct DelegateTexture: public Texture {
- DelegateTexture(Caches& caches, Texture* delegate)
- : Texture(caches), mDelegate(delegate) { }
-
- virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
- bool force = false, GLenum renderTarget = GL_TEXTURE_2D) override {
- mDelegate->setWrapST(wrapS, wrapT, bindTexture, force, renderTarget);
- }
-
- virtual void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false,
- bool force = false, GLenum renderTarget = GL_TEXTURE_2D) override {
- mDelegate->setFilterMinMag(min, mag, bindTexture, force, renderTarget);
- }
-
-private:
- Texture* const mDelegate;
-}; // struct DelegateTexture
-
-void AssetAtlas::createEntries(Caches& caches, int64_t* map, int count) {
- const float width = float(mTexture->width());
- const float height = float(mTexture->height());
-
- for (int i = 0; i < count; ) {
- SkPixelRef* pixelRef = reinterpret_cast<SkPixelRef*>(map[i++]);
- // NOTE: We're converting from 64 bit signed values to 32 bit
- // signed values. This is guaranteed to be safe because the "x"
- // and "y" coordinate values are guaranteed to be representable
- // with 32 bits. The array is 64 bits wide so that it can carry
- // pointers on 64 bit architectures.
- const int x = static_cast<int>(map[i++]);
- const int y = static_cast<int>(map[i++]);
-
- // Bitmaps should never be null, we're just extra paranoid
- if (!pixelRef) continue;
-
- const UvMapper mapper(
- x / width, (x + pixelRef->info().width()) / width,
- y / height, (y + pixelRef->info().height()) / height);
-
- Texture* texture = new DelegateTexture(caches, mTexture);
- texture->blend = !SkAlphaTypeIsOpaque(pixelRef->info().alphaType());
- texture->wrap(mTexture->id(), pixelRef->info().width(),
- pixelRef->info().height(), mTexture->format());
-
- std::unique_ptr<Entry> entry(new Entry(pixelRef, texture, mapper, *this));
- texture->uvMapper = &entry->uvMapper;
-
- mEntries.emplace(entry->pixelRef, std::move(entry));
- }
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/AssetAtlas.h b/libs/hwui/AssetAtlas.h
deleted file mode 100644
index b32e518..0000000
--- a/libs/hwui/AssetAtlas.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You 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.
- */
-
-#ifndef ANDROID_HWUI_ASSET_ATLAS_H
-#define ANDROID_HWUI_ASSET_ATLAS_H
-
-#include "Texture.h"
-#include "UvMapper.h"
-
-#include <cutils/compiler.h>
-#include <GLES2/gl2.h>
-#include <ui/GraphicBuffer.h>
-#include <SkBitmap.h>
-
-#include <memory>
-#include <unordered_map>
-
-namespace android {
-namespace uirenderer {
-
-class Caches;
-class Image;
-
-/**
- * An asset atlas holds a collection of framework bitmaps in a single OpenGL
- * texture. Each bitmap is associated with a location, defined in pixels,
- * inside the atlas. The atlas is generated by the framework and bound as
- * an external texture using the EGLImageKHR extension.
- */
-class AssetAtlas {
-public:
- /**
- * Entry representing the texture and uvMapper of a PixelRef in the
- * atlas
- */
- class Entry {
- public:
- /*
- * A "virtual texture" object that represents the texture
- * this entry belongs to. This texture should never be
- * modified.
- */
- Texture* texture;
-
- /**
- * Maps texture coordinates in the [0..1] range into the
- * correct range to sample this entry from the atlas.
- */
- const UvMapper uvMapper;
-
- /**
- * Unique identifier used to merge bitmaps and 9-patches stored
- * in the atlas.
- */
- const void* getMergeId() const {
- return texture->blend ? &atlas.mBlendKey : &atlas.mOpaqueKey;
- }
-
- ~Entry() {
- delete texture;
- }
-
- private:
- /**
- * The pixel ref that generated this atlas entry.
- */
- SkPixelRef* pixelRef;
-
- /**
- * Atlas this entry belongs to.
- */
- const AssetAtlas& atlas;
-
- Entry(SkPixelRef* pixelRef, Texture* texture, const UvMapper& mapper,
- const AssetAtlas& atlas)
- : texture(texture)
- , uvMapper(mapper)
- , pixelRef(pixelRef)
- , atlas(atlas) {
- }
-
- friend class AssetAtlas;
- };
-
- AssetAtlas(): mTexture(nullptr), mImage(nullptr),
- mBlendKey(true), mOpaqueKey(false) { }
- ~AssetAtlas() { terminate(); }
-
- /**
- * Initializes the atlas with the specified buffer and
- * map. The buffer is a gralloc'd texture that will be
- * used as an EGLImage. The map is a list of SkBitmap*
- * and their (x, y) positions
- *
- * This method returns immediately if the atlas is already
- * initialized. To re-initialize the atlas, you must
- * first call terminate().
- */
- ANDROID_API void init(const sp<GraphicBuffer>& buffer, int64_t* map, int count);
-
- /**
- * Destroys the atlas texture. This object can be
- * re-initialized after calling this method.
- *
- * After calling this method, the width, height
- * and texture are set to 0.
- */
- void terminate();
-
- /**
- * Returns the width of this atlas in pixels.
- * Can return 0 if the atlas is not initialized.
- */
- uint32_t getWidth() const {
- return mTexture ? mTexture->width() : 0;
- }
-
- /**
- * Returns the height of this atlas in pixels.
- * Can return 0 if the atlas is not initialized.
- */
- uint32_t getHeight() const {
- return mTexture ? mTexture->height() : 0;
- }
-
- /**
- * Returns the OpenGL name of the texture backing this atlas.
- * Can return 0 if the atlas is not initialized.
- */
- GLuint getTexture() const {
- return mTexture ? mTexture->id() : 0;
- }
-
- /**
- * Returns the entry in the atlas associated with the specified
- * pixelRef. If the pixelRef is not in the atlas, return NULL.
- */
- Entry* getEntry(const SkPixelRef* pixelRef) const;
-
- /**
- * Returns the texture for the atlas entry associated with the
- * specified pixelRef. If the pixelRef is not in the atlas, return NULL.
- */
- Texture* getEntryTexture(const SkPixelRef* pixelRef) const;
-
-private:
- void createEntries(Caches& caches, int64_t* map, int count);
-
- Texture* mTexture;
- Image* mImage;
-
- const bool mBlendKey;
- const bool mOpaqueKey;
-
- std::unordered_map<const SkPixelRef*, std::unique_ptr<Entry>> mEntries;
-}; // class AssetAtlas
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_ASSET_ATLAS_H
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 8b3f172..6995039 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -35,11 +35,11 @@
namespace android {
namespace uirenderer {
-static void storeTexturedRect(TextureVertex* vertices, const Rect& bounds, const Rect& texCoord) {
- vertices[0] = { bounds.left, bounds.top, texCoord.left, texCoord.top };
- vertices[1] = { bounds.right, bounds.top, texCoord.right, texCoord.top };
- vertices[2] = { bounds.left, bounds.bottom, texCoord.left, texCoord.bottom };
- vertices[3] = { bounds.right, bounds.bottom, texCoord.right, texCoord.bottom };
+static void storeTexturedRect(TextureVertex* vertices, const Rect& bounds) {
+ vertices[0] = { bounds.left, bounds.top, 0, 0 };
+ vertices[1] = { bounds.right, bounds.top, 1, 0 };
+ vertices[2] = { bounds.left, bounds.bottom, 0, 1 };
+ vertices[3] = { bounds.right, bounds.bottom, 1, 1 };
}
void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer,
@@ -48,16 +48,11 @@
const BakedOpState& firstState = *(opList.states[0]);
const SkBitmap* bitmap = (static_cast<const BitmapOp*>(opList.states[0]->op))->bitmap;
- AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry(bitmap->pixelRef());
- Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(bitmap);
+ Texture* texture = renderer.caches().textureCache.get(bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
TextureVertex vertices[opList.count * 4];
- Rect texCoords(0, 0, 1, 1);
- if (entry) {
- entry->uvMapper.map(texCoords);
- }
for (size_t i = 0; i < opList.count; i++) {
const BakedOpState& state = *(opList.states[i]);
TextureVertex* rectVerts = &vertices[i * 4];
@@ -69,7 +64,7 @@
// pure translate, so snap (same behavior as onBitmapOp)
opBounds.snapToPixelBoundaries();
}
- storeTexturedRect(rectVerts, opBounds, texCoords);
+ storeTexturedRect(rectVerts, opBounds);
renderer.dirtyRenderTarget(opBounds);
}
@@ -92,8 +87,6 @@
const MergedBakedOpList& opList) {
const PatchOp& firstOp = *(static_cast<const PatchOp*>(opList.states[0]->op));
const BakedOpState& firstState = *(opList.states[0]);
- AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry(
- firstOp.bitmap->pixelRef());
// Batches will usually contain a small number of items so it's
// worth performing a first iteration to count the exact number
@@ -105,7 +98,7 @@
// TODO: cache mesh lookups
const Patch* opMesh = renderer.caches().patchCache.get(
- entry, op.bitmap->width(), op.bitmap->height(),
+ op.bitmap->width(), op.bitmap->height(),
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
totalVertices += opMesh->verticesCount;
}
@@ -126,7 +119,7 @@
// TODO: cache mesh lookups
const Patch* opMesh = renderer.caches().patchCache.get(
- entry, op.bitmap->width(), op.bitmap->height(),
+ op.bitmap->width(), op.bitmap->height(),
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
@@ -172,7 +165,7 @@
}
- Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(firstOp.bitmap);
+ Texture* texture = renderer.caches().textureCache.get(firstOp.bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -442,7 +435,12 @@
}
void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op, const BakedOpState& state) {
- const static UvMapper defaultUvMapper;
+ Texture* texture = renderer.caches().textureCache.get(op.bitmap);
+ if (!texture) {
+ return;
+ }
+ const AutoTexture autoCleanup(texture);
+
const uint32_t elementCount = op.meshWidth * op.meshHeight * 6;
std::unique_ptr<ColorTextureVertex[]> mesh(new ColorTextureVertex[elementCount]);
@@ -457,9 +455,6 @@
colors = tempColors.get();
}
- Texture* texture = renderer.renderState().assetAtlas().getEntryTexture(op.bitmap->pixelRef());
- const UvMapper& mapper(texture && texture->uvMapper ? *texture->uvMapper : defaultUvMapper);
-
for (int32_t y = 0; y < op.meshHeight; y++) {
for (int32_t x = 0; x < op.meshWidth; x++) {
uint32_t i = (y * (op.meshWidth + 1) + x) * 2;
@@ -469,8 +464,6 @@
float v1 = float(y) / op.meshHeight;
float v2 = float(y + 1) / op.meshHeight;
- mapper.map(u1, v1, u2, v2);
-
int ax = i + (op.meshWidth + 1) * 2;
int ay = ax + 1;
int bx = i;
@@ -491,14 +484,6 @@
}
}
- if (!texture) {
- texture = renderer.caches().textureCache.get(op.bitmap);
- if (!texture) {
- return;
- }
- }
- const AutoTexture autoCleanup(texture);
-
/*
* TODO: handle alpha_8 textures correctly by applying paint color, but *not*
* shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
@@ -599,12 +584,11 @@
}
// TODO: avoid redoing the below work each frame:
- AssetAtlas::Entry* entry = renderer.renderState().assetAtlas().getEntry(op.bitmap->pixelRef());
const Patch* mesh = renderer.caches().patchCache.get(
- entry, op.bitmap->width(), op.bitmap->height(),
+ op.bitmap->width(), op.bitmap->height(),
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
- Texture* texture = entry ? entry->texture : renderer.caches().textureCache.get(op.bitmap);
+ Texture* texture = renderer.caches().textureCache.get(op.bitmap);
if (CC_LIKELY(texture)) {
const AutoTexture autoCleanup(texture);
Glop glop;
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 6db345a..ac7a600 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -182,11 +182,7 @@
}
Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
- Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap->pixelRef());
- if (!texture) {
- return mCaches.textureCache.get(bitmap);
- }
- return texture;
+ return mCaches.textureCache.get(bitmap);
}
void BakedOpRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 741cdcc..b463e45 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -53,7 +53,6 @@
: gradientCache(mExtensions)
, patchCache(renderState)
, programCache(mExtensions)
- , dither(*this)
, mRenderState(&renderState)
, mInitialized(false) {
INIT_LOGD("Creating OpenGL renderer caches");
@@ -238,7 +237,6 @@
gradientCache.clear();
fontRenderer.clear();
fboCache.clear();
- dither.clear();
// fall through
case FlushMode::Moderate:
fontRenderer.flush();
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 344ee71..7c2e78c 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -16,8 +16,6 @@
#pragma once
-#include "AssetAtlas.h"
-#include "Dither.h"
#include "Extensions.h"
#include "FboCache.h"
#include "GammaFontRenderer.h"
@@ -130,6 +128,15 @@
TextureVertex* getRegionMesh();
/**
+ * Returns the GL RGBA internal format to use for the current device
+ * If the device supports linear blending and needSRGB is true,
+ * this function returns GL_SRGB8_ALPHA8, otherwise it returns GL_RGBA
+ */
+ constexpr GLint rgbaInternalFormat(bool needSRGB = true) const {
+ return extensions().hasSRGB() && needSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA;
+ }
+
+ /**
* Displays the memory usage of each cache and the total sum.
*/
void dumpMemoryUsage();
@@ -157,8 +164,6 @@
TaskManager tasks;
- Dither dither;
-
bool gpuPixelBuffersEnabled;
// Debug methods
@@ -169,7 +174,7 @@
void setProgram(const ProgramDescription& description);
void setProgram(Program* program);
- Extensions& extensions() { return mExtensions; }
+ const Extensions& extensions() const { return mExtensions; }
Program& program() { return *mProgram; }
PixelBufferState& pixelBufferState() { return *mPixelBufferState; }
TextureState& textureState() { return *mTextureState; }
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index ca9e2bd..6e7d11f 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -19,10 +19,12 @@
#include <utils/Trace.h>
+#include "DamageAccumulator.h"
#include "Debug.h"
#include "DisplayList.h"
#include "RecordedOp.h"
#include "RenderNode.h"
+#include "VectorDrawable.h"
namespace android {
namespace uirenderer {
@@ -86,5 +88,46 @@
return index;
}
+void DisplayList::syncContents() {
+ for (auto& iter : functors) {
+ (*iter.functor)(DrawGlInfo::kModeSync, nullptr);
+ }
+ for (auto& vectorDrawable : vectorDrawables) {
+ vectorDrawable->syncProperties();
+ }
+}
+
+void DisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) {
+ for (auto&& child : children) {
+ updateFn(child->renderNode);
+ }
+}
+
+bool DisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeInfo&, bool)> childFn) {
+ TextureCache& cache = Caches::getInstance().textureCache;
+ for (auto&& bitmapResource : bitmapResources) {
+ void* ownerToken = &info.canvasContext;
+ info.prepareTextures = cache.prefetchAndMarkInUse(ownerToken, bitmapResource);
+ }
+ for (auto&& op : children) {
+ RenderNode* childNode = op->renderNode;
+ info.damageAccumulator->pushTransform(&op->localMatrix);
+ bool childFunctorsNeedLayer = functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
+ childFn(childNode, info, childFunctorsNeedLayer);
+ info.damageAccumulator->popTransform();
+ }
+
+ bool isDirty = false;
+ for (auto& vectorDrawable : vectorDrawables) {
+ // If any vector drawable in the display list needs update, damage the node.
+ if (vectorDrawable->isDirty()) {
+ isDirty = true;
+ }
+ vectorDrawable->setPropertyChangeWillBeConsumed(true);
+ }
+ return isDirty;
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index c5d8767..06b0891 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -17,6 +17,7 @@
#pragma once
#include <SkCamera.h>
+#include <SkDrawable.h>
#include <SkMatrix.h>
#include <private/hwui/DrawGlInfo.h>
@@ -36,6 +37,7 @@
#include "GlFunctorLifecycleListener.h"
#include "Matrix.h"
#include "RenderProperties.h"
+#include "TreeInfo.h"
#include <vector>
@@ -89,7 +91,7 @@
};
DisplayList();
- ~DisplayList();
+ virtual ~DisplayList();
// index of DisplayListOp restore, after which projected descendants should be drawn
int projectionReceiveIndex;
@@ -100,8 +102,6 @@
const LsaVector<NodeOpType*>& getChildren() const { return children; }
const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
- const LsaVector<FunctorContainer>& getFunctors() const { return functors; }
- const LsaVector<VectorDrawableRoot*>& getVectorDrawables() const { return vectorDrawables; }
size_t addChild(NodeOpType* childOp);
@@ -113,15 +113,26 @@
size_t getUsedSize() {
return allocator.usedSize();
}
- bool isEmpty() {
- return ops.empty();
+
+ virtual bool isEmpty() const { return ops.empty(); }
+ virtual bool hasFunctor() const { return !functors.empty(); }
+ virtual bool hasVectorDrawables() const { return !vectorDrawables.empty(); }
+ virtual bool isSkiaDL() const { return false; }
+ virtual bool reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) {
+ return false;
}
-private:
+ virtual void syncContents();
+ virtual void updateChildren(std::function<void(RenderNode*)> updateFn);
+ virtual bool prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeInfo&, bool)> childFn);
+
+protected:
// allocator into which all ops and LsaVector arrays allocated
LinearAllocator allocator;
LinearStdAllocator<void*> stdAllocator;
+private:
LsaVector<Chunk> chunks;
LsaVector<BaseOpType*> ops;
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
deleted file mode 100644
index ec2013e..0000000
--- a/libs/hwui/Dither.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#include "Caches.h"
-#include "Dither.h"
-
-namespace android {
-namespace uirenderer {
-
-///////////////////////////////////////////////////////////////////////////////
-// Lifecycle
-///////////////////////////////////////////////////////////////////////////////
-
-Dither::Dither(Caches& caches)
- : mCaches(caches)
- , mInitialized(false)
- , mDitherTexture(0) {
-}
-
-void Dither::bindDitherTexture() {
- if (!mInitialized) {
- glGenTextures(1, &mDitherTexture);
- mCaches.textureState().bindTexture(mDitherTexture);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
- if (mCaches.extensions().hasFloatTextures()) {
- // We use a R16F texture, let's remap the alpha channel to the
- // red channel to avoid changing the shader sampling code on GL ES 3.0+
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
-
- float dither = 1.0f / (255.0f * DITHER_KERNEL_SIZE * DITHER_KERNEL_SIZE);
- const GLfloat pattern[] = {
- 0 * dither, 8 * dither, 2 * dither, 10 * dither,
- 12 * dither, 4 * dither, 14 * dither, 6 * dither,
- 3 * dither, 11 * dither, 1 * dither, 9 * dither,
- 15 * dither, 7 * dither, 13 * dither, 5 * dither
- };
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0,
- GL_RED, GL_FLOAT, &pattern);
- } else {
- const uint8_t pattern[] = {
- 0, 8, 2, 10,
- 12, 4, 14, 6,
- 3, 11, 1, 9,
- 15, 7, 13, 5
- };
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, DITHER_KERNEL_SIZE, 0,
- GL_ALPHA, GL_UNSIGNED_BYTE, &pattern);
- }
-
- mInitialized = true;
- } else {
- mCaches.textureState().bindTexture(mDitherTexture);
- }
-}
-
-void Dither::clear() {
- if (mInitialized) {
- mCaches.textureState().deleteTexture(mDitherTexture);
- mInitialized = false;
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Program management
-///////////////////////////////////////////////////////////////////////////////
-
-void Dither::setupProgram(Program& program, GLuint* textureUnit) {
- GLuint textureSlot = (*textureUnit)++;
- mCaches.textureState().activateTexture(textureSlot);
-
- bindDitherTexture();
-
- glUniform1i(program.getUniform("ditherSampler"), textureSlot);
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h
deleted file mode 100644
index 6af3e83..0000000
--- a/libs/hwui/Dither.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef ANDROID_HWUI_DITHER_H
-#define ANDROID_HWUI_DITHER_H
-
-#include <GLES3/gl3.h>
-
-namespace android {
-namespace uirenderer {
-
-class Caches;
-class Extensions;
-class Program;
-
-// Must be a power of two
-#define DITHER_KERNEL_SIZE 4
-// These must not use the .0f notation as they are used from GLSL
-#define DITHER_KERNEL_SIZE_INV (1.0 / 4.0)
-#define DITHER_KERNEL_SIZE_INV_SQUARE (1.0 / 16.0)
-
-/**
- * Handles dithering for programs.
- */
-class Dither {
-public:
- explicit Dither(Caches& caches);
-
- void clear();
- void setupProgram(Program& program, GLuint* textureUnit);
-
-private:
- void bindDitherTexture();
-
- Caches& mCaches;
- bool mInitialized;
- GLuint mDitherTexture;
-};
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif // ANDROID_HWUI_DITHER_H
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 02caaa4..1d67579 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -22,6 +22,7 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+
#include <utils/Log.h>
namespace android {
@@ -45,6 +46,19 @@
mHas4BitStencil = extensions.has("GL_OES_stencil4");
mHasUnpackSubImage = extensions.has("GL_EXT_unpack_subimage");
+#ifdef ANDROID_ENABLE_LINEAR_BLENDING
+ mHasSRGB = mVersionMajor >= 3 || extensions.has("GL_EXT_sRGB");
+ mHasSRGBWriteControl = extensions.has("GL_EXT_sRGB_write_control");
+
+ // If linear blending is enabled, the device must have (ES3.0 or EXT_sRGB)
+ // and EXT_sRGB_write_control
+ LOG_ALWAYS_FATAL_IF(!mHasSRGB, "Linear blending requires ES 3.0 or EXT_sRGB");
+ LOG_ALWAYS_FATAL_IF(!mHasSRGBWriteControl, "Linear blending requires EXT_sRGB_write_control");
+#else
+ mHasSRGB = false;
+ mHasSRGBWriteControl = false;
+#endif
+
const char* version = (const char*) glGetString(GL_VERSION);
// Section 6.1.5 of the OpenGL ES specification indicates the GL version
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 67cc747..2c38507 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -43,6 +43,8 @@
inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; }
inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; }
inline bool hasFloatTextures() const { return mVersionMajor >= 3; }
+ inline bool hasSRGB() const { return mHasSRGB; }
+ inline bool hasSRGBWriteControl() const { return hasSRGB() && mHasSRGBWriteControl; }
inline int getMajorGlVersion() const { return mVersionMajor; }
inline int getMinorGlVersion() const { return mVersionMinor; }
@@ -55,6 +57,8 @@
bool mHas1BitStencil;
bool mHas4BitStencil;
bool mHasUnpackSubImage;
+ bool mHasSRGB;
+ bool mHasSRGBWriteControl;
int mVersionMajor;
int mVersionMinor;
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
index 9a39ec2..9df7338 100644
--- a/libs/hwui/FloatColor.h
+++ b/libs/hwui/FloatColor.h
@@ -16,6 +16,7 @@
#ifndef FLOATCOLOR_H
#define FLOATCOLOR_H
+#include "utils/Color.h"
#include "utils/Macros.h"
#include "utils/MathUtils.h"
@@ -25,11 +26,25 @@
namespace uirenderer {
struct FloatColor {
+ // "color" is a gamma-encoded sRGB color
+ // After calling this method, the color is stored as a pre-multiplied linear color
+ // if linear blending is enabled. Otherwise, the color is stored as a pre-multiplied
+ // gamma-encoded sRGB color
void set(uint32_t color) {
a = ((color >> 24) & 0xff) / 255.0f;
- r = a * ((color >> 16) & 0xff) / 255.0f;
- g = a * ((color >> 8) & 0xff) / 255.0f;
- b = a * ((color ) & 0xff) / 255.0f;
+ r = a * EOCF(((color >> 16) & 0xff) / 255.0f);
+ g = a * EOCF(((color >> 8) & 0xff) / 255.0f);
+ b = a * EOCF(((color ) & 0xff) / 255.0f);
+ }
+
+ // "color" is a gamma-encoded sRGB color
+ // After calling this method, the color is stored as a pre-multiplied linear color
+ // if linear blending is enabled.
+ void setSRGB(uint32_t color) {
+ a = ((color >> 24) & 0xff) / 255.0f;
+ r = a * EOCF_sRGB(((color >> 16) & 0xff) / 255.0f);
+ g = a * EOCF_sRGB(((color >> 8) & 0xff) / 255.0f);
+ b = a * EOCF_sRGB(((color ) & 0xff) / 255.0f);
}
bool isNotBlack() {
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 9b60dfc..effc65e 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -60,11 +60,17 @@
}
int transformFlags = pureTranslate
? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
+#ifdef ANDROID_ENABLE_LINEAR_BLENDING
+ bool gammaCorrection = true;
+#else
+ bool gammaCorrection = false;
+#endif
Glop glop;
GlopBuilder(renderer->renderState(), renderer->caches(), &glop)
.setRoundRectClipState(bakedState->roundRectClipState)
.setMeshTexturedIndexedQuads(texture.mesh(), texture.meshElementCount())
.setFillTexturePaint(texture.getTexture(), textureFillFlags, paint, bakedState->alpha)
+ .setGammaCorrection(gammaCorrection)
.setTransform(bakedState->computedState.transform, transformFlags)
.setModelViewIdentityEmptyBounds()
.build();
@@ -287,24 +293,23 @@
// Copy the glyph image, taking the mask format into account
switch (format) {
case SkMask::kA8_Format: {
- uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
- TEXTURE_BORDER_SIZE;
// write leading border line
memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
// write glyph data
if (mGammaTable) {
- for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
+ for (uint32_t cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
row = cacheY * cacheWidth;
cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
- for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
+ for (uint32_t cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
uint8_t tempCol = bitmapBuffer[bY + bX];
cacheBuffer[row + cacheX] = mGammaTable[tempCol];
}
cacheBuffer[row + endX + TEXTURE_BORDER_SIZE - 1] = 0;
}
} else {
- for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
+ for (uint32_t cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY += srcStride) {
row = cacheY * cacheWidth;
memcpy(&cacheBuffer[row + startX], &bitmapBuffer[bY], glyph.fWidth);
cacheBuffer[row + startX - TEXTURE_BORDER_SIZE] = 0;
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index be4fdac..17ad0e3 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -612,7 +612,6 @@
&& op.bitmap->colorType() != kAlpha_8_SkColorType
&& hasMergeableClip(*bakedState)) {
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID());
- // TODO: AssetAtlas in mergeId
currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId);
} else {
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
@@ -687,7 +686,6 @@
&& PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode
&& hasMergeableClip(*bakedState)) {
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID());
- // TODO: AssetAtlas in mergeId
// Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together
currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::MergedPatch, mergeId);
diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
index 96cac86..8aff0a2 100644
--- a/libs/hwui/GammaFontRenderer.cpp
+++ b/libs/hwui/GammaFontRenderer.cpp
@@ -24,12 +24,13 @@
GammaFontRenderer::GammaFontRenderer() {
INIT_LOGD("Creating lookup gamma font renderer");
+#ifndef ANDROID_ENABLE_LINEAR_BLENDING
// Compute the gamma tables
const float gamma = 1.0f / Properties::textGamma;
-
for (uint32_t i = 0; i <= 255; i++) {
mGammaTable[i] = uint8_t((float)::floor(pow(i / 255.0f, gamma) * 255.0f + 0.5f));
}
+#endif
}
void GammaFontRenderer::endPrecaching() {
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index bd27a1a..c9cf69b 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -18,11 +18,6 @@
#define ANDROID_HWUI_GAMMA_FONT_RENDERER_H
#include "FontRenderer.h"
-#include "Program.h"
-
-#include <SkPaint.h>
-
-#include <utils/String8.h>
namespace android {
namespace uirenderer {
@@ -43,7 +38,11 @@
FontRenderer& getFontRenderer() {
if (!mRenderer) {
- mRenderer.reset(new FontRenderer(&mGammaTable[0]));
+ const uint8_t* table = nullptr;
+#ifndef ANDROID_ENABLE_LINEAR_BLENDING
+ table = &mGammaTable[0];
+#endif
+ mRenderer.reset(new FontRenderer(table));
}
return *mRenderer;
}
@@ -64,7 +63,9 @@
private:
std::unique_ptr<FontRenderer> mRenderer;
+#ifndef ANDROID_ENABLE_LINEAR_BLENDING
uint8_t mGammaTable[256];
+#endif
};
}; // namespace uirenderer
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 1091736..65922f6 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -223,16 +223,16 @@
SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage,
const SkShader* shader, const SkColorFilter* colorFilter) {
if (mode != SkXfermode::kClear_Mode) {
- float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
if (!shader) {
- float colorScale = alpha / 255.0f;
- mOutGlop->fill.color = {
- colorScale * SkColorGetR(color),
- colorScale * SkColorGetG(color),
- colorScale * SkColorGetB(color),
- alpha
- };
+ FloatColor c;
+ c.set(color);
+ c.r *= alphaScale;
+ c.g *= alphaScale;
+ c.b *= alphaScale;
+ c.a *= alphaScale;
+ mOutGlop->fill.color = c;
} else {
+ float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
mOutGlop->fill.color = { 1, 1, 1, alpha };
}
} else {
@@ -276,15 +276,7 @@
if (colorFilter->asColorMode(&color, &mode)) {
mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Blend;
mDescription.colorMode = mode;
-
- const float alpha = SkColorGetA(color) / 255.0f;
- float colorScale = alpha / 255.0f;
- mOutGlop->fill.filter.color = {
- colorScale * SkColorGetR(color),
- colorScale * SkColorGetG(color),
- colorScale * SkColorGetB(color),
- alpha,
- };
+ mOutGlop->fill.filter.color.set(color);
} else if (colorFilter->asColorMatrix(srcColorMatrix)) {
mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Matrix;
@@ -297,10 +289,10 @@
// Skia uses the range [0..255] for the addition vector, but we need
// the [0..1] range to apply the vector in GLSL
float* colorVector = mOutGlop->fill.filter.matrix.vector;
- colorVector[0] = srcColorMatrix[4] / 255.0f;
- colorVector[1] = srcColorMatrix[9] / 255.0f;
- colorVector[2] = srcColorMatrix[14] / 255.0f;
- colorVector[3] = srcColorMatrix[19] / 255.0f;
+ colorVector[0] = EOCF(srcColorMatrix[4] / 255.0f);
+ colorVector[1] = EOCF(srcColorMatrix[9] / 255.0f);
+ colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f);
+ colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear
} else {
LOG_ALWAYS_FATAL("unsupported ColorFilter");
}
@@ -481,6 +473,13 @@
return *this;
}
+GlopBuilder& GlopBuilder::setGammaCorrection(bool enabled) {
+ REQUIRE_STAGES(kFillStage);
+
+ mDescription.hasGammaCorrection = enabled;
+ return *this;
+}
+
////////////////////////////////////////////////////////////////////////////////
// Transform
////////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 1152461..1f3b53a 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -105,6 +105,8 @@
GlopBuilder& setRoundRectClipState(const RoundRectClipState* roundRectClipState);
+ GlopBuilder& setGammaCorrection(bool enabled);
+
void build();
static void dump(const Glop& glop);
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index c8f5e94..0972ac1 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -67,7 +67,8 @@
, mSize(0)
, mMaxSize(Properties::gradientCacheSize)
, mUseFloatTexture(extensions.hasFloatTextures())
- , mHasNpot(extensions.hasNPot()){
+ , mHasNpot(extensions.hasNPot())
+ , mHasSRGB(extensions.hasSRGB()) {
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
mCache.setOnEntryRemovedListener(this);
@@ -176,71 +177,56 @@
size_t GradientCache::bytesPerPixel() const {
// We use 4 channels (RGBA)
+ return 4 * (mUseFloatTexture ? /* fp16 */ 2 : sizeof(uint8_t));
+}
+
+size_t GradientCache::sourceBytesPerPixel() const {
+ // We use 4 channels (RGBA) and upload from floats (not half floats)
return 4 * (mUseFloatTexture ? sizeof(float) : sizeof(uint8_t));
}
-void GradientCache::splitToBytes(uint32_t inColor, GradientColor& outColor) const {
- outColor.r = (inColor >> 16) & 0xff;
- outColor.g = (inColor >> 8) & 0xff;
- outColor.b = (inColor >> 0) & 0xff;
- outColor.a = (inColor >> 24) & 0xff;
-}
-
-void GradientCache::splitToFloats(uint32_t inColor, GradientColor& outColor) const {
- outColor.r = ((inColor >> 16) & 0xff) / 255.0f;
- outColor.g = ((inColor >> 8) & 0xff) / 255.0f;
- outColor.b = ((inColor >> 0) & 0xff) / 255.0f;
- outColor.a = ((inColor >> 24) & 0xff) / 255.0f;
-}
-
-void GradientCache::mixBytes(GradientColor& start, GradientColor& end, float amount,
- uint8_t*& dst) const {
+void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end,
+ float amount, uint8_t*& dst) const {
float oppAmount = 1.0f - amount;
- const float alpha = start.a * oppAmount + end.a * amount;
- const float a = alpha / 255.0f;
-
- *dst++ = uint8_t(a * (start.r * oppAmount + end.r * amount));
- *dst++ = uint8_t(a * (start.g * oppAmount + end.g * amount));
- *dst++ = uint8_t(a * (start.b * oppAmount + end.b * amount));
- *dst++ = uint8_t(alpha);
+ *dst++ = uint8_t(OECF_sRGB(start.r * oppAmount + end.r * amount) * 255.0f);
+ *dst++ = uint8_t(OECF_sRGB(start.g * oppAmount + end.g * amount) * 255.0f);
+ *dst++ = uint8_t(OECF_sRGB(start.b * oppAmount + end.b * amount) * 255.0f);
+ *dst++ = uint8_t( (start.a * oppAmount + end.a * amount) * 255.0f);
}
-void GradientCache::mixFloats(GradientColor& start, GradientColor& end, float amount,
- uint8_t*& dst) const {
+void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end,
+ float amount, uint8_t*& dst) const {
float oppAmount = 1.0f - amount;
- const float a = start.a * oppAmount + end.a * amount;
-
float* d = (float*) dst;
- *d++ = a * (start.r * oppAmount + end.r * amount);
- *d++ = a * (start.g * oppAmount + end.g * amount);
- *d++ = a * (start.b * oppAmount + end.b * amount);
- *d++ = a;
-
+#ifdef ANDROID_ENABLE_LINEAR_BLENDING
+ *d++ = start.r * oppAmount + end.r * amount;
+ *d++ = start.g * oppAmount + end.g * amount;
+ *d++ = start.b * oppAmount + end.b * amount;
+#else
+ *d++ = OECF_sRGB(start.r * oppAmount + end.r * amount);
+ *d++ = OECF_sRGB(start.g * oppAmount + end.g * amount);
+ *d++ = OECF_sRGB(start.b * oppAmount + end.b * amount);
+#endif
+ *d++ = start.a * oppAmount + end.a * amount;
dst += 4 * sizeof(float);
}
void GradientCache::generateTexture(uint32_t* colors, float* positions,
const uint32_t width, const uint32_t height, Texture* texture) {
- const GLsizei rowBytes = width * bytesPerPixel();
+ const GLsizei rowBytes = width * sourceBytesPerPixel();
uint8_t pixels[rowBytes * height];
- static ChannelSplitter gSplitters[] = {
- &android::uirenderer::GradientCache::splitToBytes,
- &android::uirenderer::GradientCache::splitToFloats,
- };
- ChannelSplitter split = gSplitters[mUseFloatTexture];
-
static ChannelMixer gMixers[] = {
- &android::uirenderer::GradientCache::mixBytes,
- &android::uirenderer::GradientCache::mixFloats,
+ &android::uirenderer::GradientCache::mixBytes, // colors are stored gamma-encoded
+ &android::uirenderer::GradientCache::mixFloats, // colors are stored in linear
};
ChannelMixer mix = gMixers[mUseFloatTexture];
- GradientColor start;
- (this->*split)(colors[0], start);
+ FloatColor start;
+ start.setSRGB(colors[0]);
- GradientColor end;
- (this->*split)(colors[1], end);
+ FloatColor end;
+ end.setSRGB(colors[1]);
int currentPos = 1;
float startPos = positions[0];
@@ -255,7 +241,7 @@
currentPos++;
- (this->*split)(colors[currentPos], end);
+ end.setSRGB(colors[currentPos]);
distance = positions[currentPos] - startPos;
}
@@ -266,10 +252,10 @@
memcpy(pixels + rowBytes, pixels, rowBytes);
if (mUseFloatTexture) {
- // We have to use GL_RGBA16F because GL_RGBA32F does not support filtering
texture->upload(GL_RGBA16F, width, height, GL_RGBA, GL_FLOAT, pixels);
} else {
- texture->upload(GL_RGBA, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ GLint internalFormat = mHasSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA;
+ texture->upload(internalFormat, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
}
texture->setFilter(GL_LINEAR);
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index 49be19a..5e35435 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -26,6 +26,8 @@
#include <utils/LruCache.h>
#include <utils/Mutex.h>
+#include "FloatColor.h"
+
namespace android {
namespace uirenderer {
@@ -150,25 +152,15 @@
void getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info);
size_t bytesPerPixel() const;
+ size_t sourceBytesPerPixel() const;
- struct GradientColor {
- float r;
- float g;
- float b;
- float a;
- };
-
- typedef void (GradientCache::*ChannelSplitter)(uint32_t inColor,
- GradientColor& outColor) const;
-
- void splitToBytes(uint32_t inColor, GradientColor& outColor) const;
- void splitToFloats(uint32_t inColor, GradientColor& outColor) const;
-
- typedef void (GradientCache::*ChannelMixer)(GradientColor& start, GradientColor& end,
+ typedef void (GradientCache::*ChannelMixer)(const FloatColor& start, const FloatColor& end,
float amount, uint8_t*& dst) const;
- void mixBytes(GradientColor& start, GradientColor& end, float amount, uint8_t*& dst) const;
- void mixFloats(GradientColor& start, GradientColor& end, float amount, uint8_t*& dst) const;
+ void mixBytes(const FloatColor& start, const FloatColor& end,
+ float amount, uint8_t*& dst) const;
+ void mixFloats(const FloatColor& start, const FloatColor& end,
+ float amount, uint8_t*& dst) const;
LruCache<GradientCacheEntry, Texture*> mCache;
@@ -178,6 +170,7 @@
GLint mMaxTextureSize;
bool mUseFloatTexture;
bool mHasNpot;
+ bool mHasSRGB;
mutable Mutex mLock;
}; // class GradientCache
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index c688a96..01650ef 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -75,7 +75,7 @@
}
void setSize(uint32_t width, uint32_t height) {
- texture.updateSize(width, height, texture.format());
+ texture.updateSize(width, height, texture.internalFormat(), texture.format());
}
inline void setBlend(bool blend) {
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index a6c281d..52c62cc 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -225,17 +225,15 @@
static const UvMapper sIdentity;
-const Patch* PatchCache::get(const AssetAtlas::Entry* entry,
- const uint32_t bitmapWidth, const uint32_t bitmapHeight,
+const Patch* PatchCache::get( const uint32_t bitmapWidth, const uint32_t bitmapHeight,
const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
const PatchDescription description(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, patch);
const Patch* mesh = mCache.get(description);
if (!mesh) {
- const UvMapper& mapper = entry ? entry->uvMapper : sIdentity;
Patch* newMesh = new Patch(bitmapWidth, bitmapHeight,
- pixelWidth, pixelHeight, mapper, patch);
+ pixelWidth, pixelHeight, sIdentity, patch);
if (newMesh->vertices) {
setupMesh(newMesh);
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index 6e6a730..0624c35 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -22,7 +22,6 @@
#include <androidfw/ResourceTypes.h>
-#include "AssetAtlas.h"
#include "Debug.h"
#include "utils/Pair.h"
@@ -54,8 +53,7 @@
explicit PatchCache(RenderState& renderState);
~PatchCache();
- const Patch* get(const AssetAtlas::Entry* entry,
- const uint32_t bitmapWidth, const uint32_t bitmapHeight,
+ const Patch* get(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch);
void clear();
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index eb606cb..e69ea79 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -182,8 +182,7 @@
PathCache::PathCache()
: mCache(LruCache<PathDescription, PathTexture*>::kUnlimitedCapacity)
, mSize(0)
- , mMaxSize(Properties::pathCacheSize)
- , mTexNum(0) {
+ , mMaxSize(Properties::pathCacheSize) {
mCache.setOnEntryRemovedListener(this);
GLint maxTextureSize;
@@ -239,7 +238,6 @@
"the cache in an inconsistent state", size);
}
mSize -= size;
- mTexNum--;
}
PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
@@ -264,7 +262,14 @@
}
void PathCache::trim() {
- while (mSize > mMaxSize || mTexNum > DEFAULT_PATH_TEXTURE_CAP) {
+ // 25 is just an arbitrary lower bound to ensure we aren't in weird edge cases
+ // of things like a cap of 0 or 1 as that's going to break things.
+ // It does not represent a reasonable minimum value
+ static_assert(DEFAULT_PATH_TEXTURE_CAP > 25, "Path cache texture cap is too small");
+
+ while (mSize > mMaxSize || mCache.size() > DEFAULT_PATH_TEXTURE_CAP) {
+ LOG_ALWAYS_FATAL_IF(!mCache.size(), "Inconsistent mSize! Ran out of items to remove!"
+ " mSize = %u, mMaxSize = %u", mSize, mMaxSize);
mCache.removeOldest();
}
}
@@ -312,7 +317,6 @@
ATRACE_NAME("Upload Path Texture");
texture->upload(bitmap);
texture->setFilter(GL_LINEAR);
- mTexNum++;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index b45a2c5..18bcc56 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -281,12 +281,6 @@
bool mDebugEnabled;
- /**
- * Driver allocated 4k/8k/16k memory for small path cache,
- * limit the number of PathTexture in case occupy too much memory in hardware.
- */
- uint32_t mTexNum;
-
sp<PathProcessor> mProcessor;
std::vector<uint32_t> mGarbage;
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index e5200a5..f5beb62 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -85,6 +85,8 @@
#define PROGRAM_HAS_DEBUG_HIGHLIGHT 42
#define PROGRAM_HAS_ROUND_RECT_CLIP 43
+#define PROGRAM_HAS_GAMMA_CORRECTION 44
+
///////////////////////////////////////////////////////////////////////////////
// Types
///////////////////////////////////////////////////////////////////////////////
@@ -158,6 +160,8 @@
bool hasDebugHighlight;
bool hasRoundRectClip;
+ bool hasGammaCorrection;
+
/**
* Resets this description. All fields are reset back to the default
* values they hold after building a new instance.
@@ -196,6 +200,8 @@
hasDebugHighlight = false;
hasRoundRectClip = false;
+
+ hasGammaCorrection = false;
}
/**
@@ -262,6 +268,7 @@
if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS;
if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT;
if (hasRoundRectClip) key |= programid(0x1) << PROGRAM_HAS_ROUND_RECT_CLIP;
+ if (hasGammaCorrection) key |= programid(0x1) << PROGRAM_HAS_GAMMA_CORRECTION;
return key;
}
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 59225e1..4ef6b85 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -17,8 +17,8 @@
#include <utils/String8.h>
#include "Caches.h"
-#include "Dither.h"
#include "ProgramCache.h"
+#include "Properties.h"
namespace android {
namespace uirenderer {
@@ -69,22 +69,16 @@
"varying highp vec2 outBitmapTexCoords;\n";
const char* gVS_Header_Varyings_HasGradient[6] = {
// Linear
- "varying highp vec2 linear;\n"
- "varying vec2 ditherTexCoords;\n",
- "varying float linear;\n"
- "varying vec2 ditherTexCoords;\n",
+ "varying highp vec2 linear;\n",
+ "varying float linear;\n",
// Circular
- "varying highp vec2 circular;\n"
- "varying vec2 ditherTexCoords;\n",
- "varying highp vec2 circular;\n"
- "varying vec2 ditherTexCoords;\n",
+ "varying highp vec2 circular;\n",
+ "varying highp vec2 circular;\n",
// Sweep
- "varying highp vec2 sweep;\n"
- "varying vec2 ditherTexCoords;\n",
- "varying highp vec2 sweep;\n"
- "varying vec2 ditherTexCoords;\n",
+ "varying highp vec2 sweep;\n",
+ "varying highp vec2 sweep;\n",
};
const char* gVS_Header_Varyings_HasRoundRectClip =
"varying highp vec2 roundRectPos;\n";
@@ -98,22 +92,16 @@
" outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
const char* gVS_Main_OutGradient[6] = {
// Linear
- " linear = vec2((screenSpace * position).x, 0.5);\n"
- " ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
- " linear = (screenSpace * position).x;\n"
- " ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
+ " linear = vec2((screenSpace * position).x, 0.5);\n",
+ " linear = (screenSpace * position).x;\n",
// Circular
- " circular = (screenSpace * position).xy;\n"
- " ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
- " circular = (screenSpace * position).xy;\n"
- " ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
+ " circular = (screenSpace * position).xy;\n",
+ " circular = (screenSpace * position).xy;\n",
// Sweep
+ " sweep = (screenSpace * position).xy;\n",
" sweep = (screenSpace * position).xy;\n"
- " ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
- " sweep = (screenSpace * position).xy;\n"
- " ditherTexCoords = (transform * position).xy * " STR(DITHER_KERNEL_SIZE_INV) ";\n",
};
const char* gVS_Main_OutBitmapTexCoords =
" outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
@@ -147,12 +135,11 @@
"uniform sampler2D baseSampler;\n";
const char* gFS_Uniforms_ExternalTextureSampler =
"uniform samplerExternalOES baseSampler;\n";
-const char* gFS_Uniforms_Dither =
- "uniform sampler2D ditherSampler;";
const char* gFS_Uniforms_GradientSampler[2] = {
- "%s\n"
+ "uniform vec2 screenSize;\n"
"uniform sampler2D gradientSampler;\n",
- "%s\n"
+
+ "uniform vec2 screenSize;\n"
"uniform vec4 startColor;\n"
"uniform vec4 endColor;\n"
};
@@ -172,18 +159,57 @@
"uniform vec4 roundRectInnerRectLTRB;\n"
"uniform float roundRectRadius;\n";
+// Dithering must be done in the quantization space
+// When we are writing to an sRGB framebuffer, we must do the following:
+// EOCF(OECF(color) + dither)
+// We approximate the transfer functions with gamma 2.0 to avoid branches and pow()
+// The dithering pattern is generated with a triangle noise generator in the range [-0.0,1.0]
+// TODO: Handle linear fp16 render targets
+const char* gFS_Gradient_Functions =
+ "\nfloat triangleNoise(const highp vec2 n) {\n"
+ " highp vec2 p = fract(n * vec2(5.3987, 5.4421));\n"
+ " p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));\n"
+ " highp float xy = p.x * p.y;\n"
+ " return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;\n"
+ "}\n";
+const char* gFS_Gradient_Preamble[2] = {
+ // Linear framebuffer
+ "\nvec4 dither(const vec4 color) {\n"
+ " return vec4(color.rgb + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0), color.a);"
+ "}\n"
+ "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
+ " return pow(mix(a, b, v), vec4(vec3(1.0 / 2.2), 1.0));"
+ "}\n",
+ // sRGB framebuffer
+ "\nvec4 dither(const vec4 color) {\n"
+ " vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);\n"
+ " return vec4(dithered * dithered, color.a);\n"
+ "}\n"
+ "\nvec4 gammaMix(const vec4 a, const vec4 b, float v) {\n"
+ " return mix(a, b, v);"
+ "}\n"
+};
+
+// Uses luminance coefficients from Rec.709 to choose the appropriate gamma
+// The gamma() function assumes that bright text will be displayed on a dark
+// background and that dark text will be displayed on bright background
+// The gamma coefficient is chosen to thicken or thin the text accordingly
+// The dot product used to compute the luminance could be approximated with
+// a simple max(color.r, color.g, color.b)
+const char* gFS_Gamma_Preamble =
+ "\n#define GAMMA (%.2f)\n"
+ "#define GAMMA_INV (%.2f)\n"
+ "\nfloat gamma(float a, const vec3 color) {\n"
+ " float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));\n"
+ " return pow(a, luminance < 0.5 ? GAMMA_INV : GAMMA);\n"
+ "}\n";
+
const char* gFS_Main =
"\nvoid main(void) {\n"
- " lowp vec4 fragColor;\n";
+ " vec4 fragColor;\n";
-const char* gFS_Main_Dither[2] = {
- // ES 2.0
- "texture2D(ditherSampler, ditherTexCoords).a * " STR(DITHER_KERNEL_SIZE_INV_SQUARE),
- // ES 3.0
- "texture2D(ditherSampler, ditherTexCoords).a"
-};
-const char* gFS_Main_AddDitherToGradient =
- " gradientColor += %s;\n";
+const char* gFS_Main_AddDither =
+ " fragColor = dither(fragColor);\n";
// Fast cases
const char* gFS_Fast_SingleColor =
@@ -202,24 +228,32 @@
"\nvoid main(void) {\n"
" gl_FragColor = texture2D(baseSampler, outTexCoords);\n"
"}\n\n";
+const char* gFS_Fast_SingleA8Texture_ApplyGamma =
+ "\nvoid main(void) {\n"
+ " gl_FragColor = vec4(0.0, 0.0, 0.0, pow(texture2D(baseSampler, outTexCoords).a, GAMMA));\n"
+ "}\n\n";
const char* gFS_Fast_SingleModulateA8Texture =
"\nvoid main(void) {\n"
" gl_FragColor = color * texture2D(baseSampler, outTexCoords).a;\n"
"}\n\n";
+const char* gFS_Fast_SingleModulateA8Texture_ApplyGamma =
+ "\nvoid main(void) {\n"
+ " gl_FragColor = color * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n"
+ "}\n\n";
const char* gFS_Fast_SingleGradient[2] = {
"\nvoid main(void) {\n"
- " gl_FragColor = %s + texture2D(gradientSampler, linear);\n"
+ " gl_FragColor = dither(texture2D(gradientSampler, linear));\n"
"}\n\n",
"\nvoid main(void) {\n"
- " gl_FragColor = %s + mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
+ " gl_FragColor = dither(gammaMix(startColor, endColor, clamp(linear, 0.0, 1.0)));\n"
"}\n\n",
};
const char* gFS_Fast_SingleModulateGradient[2] = {
"\nvoid main(void) {\n"
- " gl_FragColor = %s + color.a * texture2D(gradientSampler, linear);\n"
+ " gl_FragColor = dither(color.a * texture2D(gradientSampler, linear));\n"
"}\n\n",
"\nvoid main(void) {\n"
- " gl_FragColor = %s + color.a * mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n"
+ " gl_FragColor = dither(color.a * gammaMix(startColor, endColor, clamp(linear, 0.0, 1.0)));\n"
"}\n\n"
};
@@ -239,29 +273,31 @@
// Modulate
" fragColor = color * texture2D(baseSampler, outTexCoords);\n"
};
-const char* gFS_Main_FetchA8Texture[2] = {
+const char* gFS_Main_FetchA8Texture[4] = {
// Don't modulate
" fragColor = texture2D(baseSampler, outTexCoords);\n",
+ " fragColor = texture2D(baseSampler, outTexCoords);\n",
// Modulate
" fragColor = color * texture2D(baseSampler, outTexCoords).a;\n",
+ " fragColor = color * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n",
};
const char* gFS_Main_FetchGradient[6] = {
// Linear
" vec4 gradientColor = texture2D(gradientSampler, linear);\n",
- " vec4 gradientColor = mix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
+ " vec4 gradientColor = gammaMix(startColor, endColor, clamp(linear, 0.0, 1.0));\n",
// Circular
" vec4 gradientColor = texture2D(gradientSampler, vec2(length(circular), 0.5));\n",
- " vec4 gradientColor = mix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
+ " vec4 gradientColor = gammaMix(startColor, endColor, clamp(length(circular), 0.0, 1.0));\n",
// Sweep
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
" vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
- " vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
+ " vec4 gradientColor = gammaMix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
};
const char* gFS_Main_FetchBitmap =
" vec4 bitmapColor = texture2D(bitmapSampler, outBitmapTexCoords);\n";
@@ -271,29 +307,38 @@
" fragColor = blendShaders(gradientColor, bitmapColor)";
const char* gFS_Main_BlendShadersGB =
" fragColor = blendShaders(bitmapColor, gradientColor)";
-const char* gFS_Main_BlendShaders_Modulate[3] = {
+const char* gFS_Main_BlendShaders_Modulate[6] = {
// Don't modulate
";\n",
+ ";\n",
// Modulate
" * color.a;\n",
+ " * color.a;\n",
// Modulate with alpha 8 texture
" * texture2D(baseSampler, outTexCoords).a;\n",
+ " * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n",
};
-const char* gFS_Main_GradientShader_Modulate[3] = {
+const char* gFS_Main_GradientShader_Modulate[6] = {
// Don't modulate
" fragColor = gradientColor;\n",
+ " fragColor = gradientColor;\n",
// Modulate
" fragColor = gradientColor * color.a;\n",
+ " fragColor = gradientColor * color.a;\n",
// Modulate with alpha 8 texture
" fragColor = gradientColor * texture2D(baseSampler, outTexCoords).a;\n",
+ " fragColor = gradientColor * gamma(texture2D(baseSampler, outTexCoords).a, gradientColor.rgb);\n",
};
-const char* gFS_Main_BitmapShader_Modulate[3] = {
+const char* gFS_Main_BitmapShader_Modulate[6] = {
// Don't modulate
" fragColor = bitmapColor;\n",
+ " fragColor = bitmapColor;\n",
// Modulate
" fragColor = bitmapColor * color.a;\n",
+ " fragColor = bitmapColor * color.a;\n",
// Modulate with alpha 8 texture
" fragColor = bitmapColor * texture2D(baseSampler, outTexCoords).a;\n",
+ " fragColor = bitmapColor * gamma(texture2D(baseSampler, outTexCoords).a, bitmapColor.rgb);\n",
};
const char* gFS_Main_FragColor =
" gl_FragColor = fragColor;\n";
@@ -385,7 +430,8 @@
///////////////////////////////////////////////////////////////////////////////
ProgramCache::ProgramCache(Extensions& extensions)
- : mHasES3(extensions.getMajorGlVersion() >= 3) {
+ : mHasES3(extensions.getMajorGlVersion() >= 3)
+ , mHasSRGB(extensions.hasSRGB()) {
}
ProgramCache::~ProgramCache() {
@@ -518,6 +564,7 @@
static bool shaderOp(const ProgramDescription& description, String8& shader,
const int modulateOp, const char** snippets) {
int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
+ op = op * 2 + description.hasGammaCorrection;
shader.append(snippets[op]);
return description.hasAlpha8Texture;
}
@@ -570,13 +617,16 @@
shader.append(gFS_Uniforms_ExternalTextureSampler);
}
if (description.hasGradient) {
- shader.appendFormat(gFS_Uniforms_GradientSampler[description.isSimpleGradient],
- gFS_Uniforms_Dither);
+ shader.append(gFS_Uniforms_GradientSampler[description.isSimpleGradient]);
}
if (description.hasRoundRectClip) {
shader.append(gFS_Uniforms_HasRoundRectClip);
}
+ if (description.hasGammaCorrection) {
+ shader.appendFormat(gFS_Gamma_Preamble, Properties::textGamma, 1.0f / Properties::textGamma);
+ }
+
// Optimization for common cases
if (!description.hasVertexAlpha
&& !blendFramebuffer
@@ -607,18 +657,26 @@
fast = true;
} else if (singleA8Texture) {
if (!description.modulate) {
- shader.append(gFS_Fast_SingleA8Texture);
+ if (description.hasGammaCorrection) {
+ shader.append(gFS_Fast_SingleA8Texture_ApplyGamma);
+ } else {
+ shader.append(gFS_Fast_SingleA8Texture);
+ }
} else {
- shader.append(gFS_Fast_SingleModulateA8Texture);
+ if (description.hasGammaCorrection) {
+ shader.append(gFS_Fast_SingleModulateA8Texture_ApplyGamma);
+ } else {
+ shader.append(gFS_Fast_SingleModulateA8Texture);
+ }
}
fast = true;
} else if (singleGradient) {
+ shader.append(gFS_Gradient_Functions);
+ shader.append(gFS_Gradient_Preamble[mHasSRGB]);
if (!description.modulate) {
- shader.appendFormat(gFS_Fast_SingleGradient[description.isSimpleGradient],
- gFS_Main_Dither[mHasES3]);
+ shader.append(gFS_Fast_SingleGradient[description.isSimpleGradient]);
} else {
- shader.appendFormat(gFS_Fast_SingleModulateGradient[description.isSimpleGradient],
- gFS_Main_Dither[mHasES3]);
+ shader.append(gFS_Fast_SingleModulateGradient[description.isSimpleGradient]);
}
fast = true;
}
@@ -652,6 +710,10 @@
if (description.isBitmapNpot) {
generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
}
+ if (description.hasGradient) {
+ shader.append(gFS_Gradient_Functions);
+ shader.append(gFS_Gradient_Preamble[mHasSRGB]);
+ }
// Begin the shader
shader.append(gFS_Main); {
@@ -659,7 +721,8 @@
if (description.hasTexture || description.hasExternalTexture) {
if (description.hasAlpha8Texture) {
if (!description.hasGradient && !description.hasBitmap) {
- shader.append(gFS_Main_FetchA8Texture[modulateOp]);
+ shader.append(
+ gFS_Main_FetchA8Texture[modulateOp * 2 + description.hasGammaCorrection]);
}
} else {
shader.append(gFS_Main_FetchTexture[modulateOp]);
@@ -671,7 +734,6 @@
}
if (description.hasGradient) {
shader.append(gFS_Main_FetchGradient[gradientIndex(description)]);
- shader.appendFormat(gFS_Main_AddDitherToGradient, gFS_Main_Dither[mHasES3]);
}
if (description.hasBitmap) {
if (!description.isBitmapNpot) {
@@ -715,6 +777,10 @@
}
}
+ if (description.hasGradient) {
+ shader.append(gFS_Main_AddDither);
+ }
+
// Output the fragment
if (!blendFramebuffer) {
shader.append(gFS_Main_FragColor);
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index 9ac885b..292ecdf 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -59,6 +59,7 @@
std::map<programid, std::unique_ptr<Program>> mCache;
const bool mHasES3;
+ const bool mHasSRGB;
}; // class ProgramCache
}; // namespace uirenderer
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 93b2e15..848161e 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -214,7 +214,7 @@
property_get(PROPERTY_DEFAULT_RENDERER, prop, "opengl");
if (!strcmp(prop, "skiagl") ) {
sRenderPipelineType = RenderPipelineType::SkiaGL;
- } else if (!strcmp(prop, "skiavulkan") ) {
+ } else if (!strcmp(prop, "skiavk") ) {
sRenderPipelineType = RenderPipelineType::SkiaVulkan;
} else { //"opengl"
sRenderPipelineType = RenderPipelineType::OpenGL;
@@ -222,5 +222,11 @@
return sRenderPipelineType;
}
+bool Properties::isSkiaEnabled() {
+ auto renderType = getRenderPipelineType();
+ return RenderPipelineType::SkiaGL == renderType
+ || RenderPipelineType::SkiaVulkan == renderType;
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index eedc9e7..b4a3118 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -203,7 +203,7 @@
#define PROPERTY_TEXT_LARGE_CACHE_WIDTH "ro.hwui.text_large_cache_width"
#define PROPERTY_TEXT_LARGE_CACHE_HEIGHT "ro.hwui.text_large_cache_height"
-// Gamma (>= 1.0, <= 10.0)
+// Gamma (>= 1.0, <= 3.0)
#define PROPERTY_TEXT_GAMMA "hwui.text_gamma"
///////////////////////////////////////////////////////////////////////////////
@@ -222,7 +222,7 @@
#define DEFAULT_TEXTURE_CACHE_FLUSH_RATE 0.6f
-#define DEFAULT_TEXT_GAMMA 1.4f
+#define DEFAULT_TEXT_GAMMA 1.45f // Match design tools
// cap to 256 to limite paths in the path cache
#define DEFAULT_PATH_TEXTURE_CAP 256
@@ -308,6 +308,7 @@
static ProfileType getProfileType();
static RenderPipelineType getRenderPipelineType();
+ static bool isSkiaEnabled();
// Should be used only by test apps
static bool waitForGpuCompletion;
diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
index 38fb70a..e3258e3 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.cpp
+++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
@@ -46,8 +46,17 @@
void PropertyValuesAnimatorSet::onFinished(BaseRenderNodeAnimator* animator) {
if (mOneShotListener.get()) {
- mOneShotListener->onAnimationFinished(animator);
+ sp<AnimationListener> listener = std::move(mOneShotListener);
+ // Set the listener to nullptr before the onAnimationFinished callback, rather than after,
+ // for two reasons:
+ // 1) We need to prevent changes to mOneShotListener during the onAnimationFinished
+ // callback (specifically in AnimationListenerBridge::onAnimationFinished(...) from
+ // triggering dtor of the bridge and potentially unsafely re-entering
+ // AnimationListenerBridge::onAnimationFinished(...).
+ // 2) It's possible that there are changes to the listener during the callback, therefore
+ // we need to reset the listener before the callback rather than afterwards.
mOneShotListener = nullptr;
+ listener->onAnimationFinished(animator);
}
}
diff --git a/libs/hwui/PropertyValuesHolder.cpp b/libs/hwui/PropertyValuesHolder.cpp
index 6ba0ab5..2a03e6a 100644
--- a/libs/hwui/PropertyValuesHolder.cpp
+++ b/libs/hwui/PropertyValuesHolder.cpp
@@ -16,6 +16,7 @@
#include "PropertyValuesHolder.h"
+#include "utils/Color.h"
#include "utils/VectorDrawableUtils.h"
#include <utils/Log.h>
@@ -25,18 +26,26 @@
using namespace VectorDrawable;
-inline U8CPU lerp(U8CPU fromValue, U8CPU toValue, float fraction) {
- return (U8CPU) (fromValue * (1 - fraction) + toValue * fraction);
+inline constexpr float lerp(float fromValue, float toValue, float fraction) {
+ return float (fromValue * (1 - fraction) + toValue * fraction);
+}
+
+inline constexpr float linearize(U8CPU component) {
+ return EOCF_sRGB(component / 255.0f);
}
// TODO: Add a test for this
void ColorEvaluator::evaluate(SkColor* outColor,
const SkColor& fromColor, const SkColor& toColor, float fraction) const {
- U8CPU alpha = lerp(SkColorGetA(fromColor), SkColorGetA(toColor), fraction);
- U8CPU red = lerp(SkColorGetR(fromColor), SkColorGetR(toColor), fraction);
- U8CPU green = lerp(SkColorGetG(fromColor), SkColorGetG(toColor), fraction);
- U8CPU blue = lerp(SkColorGetB(fromColor), SkColorGetB(toColor), fraction);
- *outColor = SkColorSetARGB(alpha, red, green, blue);
+ float a = lerp(SkColorGetA(fromColor) / 255.0f, SkColorGetA(toColor) / 255.0f, fraction);
+ float r = lerp(linearize(SkColorGetR(fromColor)), linearize(SkColorGetR(toColor)), fraction);
+ float g = lerp(linearize(SkColorGetG(fromColor)), linearize(SkColorGetG(toColor)), fraction);
+ float b = lerp(linearize(SkColorGetB(fromColor)), linearize(SkColorGetB(toColor)), fraction);
+ *outColor = SkColorSetARGB(
+ (U8CPU) roundf(a * 255.0f),
+ (U8CPU) roundf(OECF_sRGB(r) * 255.0f),
+ (U8CPU) roundf(OECF_sRGB(g) * 255.0f),
+ (U8CPU) roundf(OECF_sRGB(b) * 255.0f));
}
void PathEvaluator::evaluate(PathData* out,
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index ddca122..22c6dfc 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -197,7 +197,7 @@
Texture sourceTexture(caches);
sourceTexture.wrap(sourceTexId,
- sourceBuffer->getWidth(), sourceBuffer->getHeight(), 0 /* total lie */);
+ sourceBuffer->getWidth(), sourceBuffer->getHeight(), 0, 0 /* total lie */);
CopyResult copyResult = copyTextureInto(caches, renderThread.renderState(),
sourceTexture, texTransform, srcRect, bitmap);
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index a65c22c..ebc41b1 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -216,7 +216,6 @@
: SUPER(BitmapOp)
, bitmap(bitmap) {}
const SkBitmap* bitmap;
- // TODO: asset atlas/texture id lookup?
};
struct BitmapMeshOp : RecordedOp {
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index dd20a76..a03ded6 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -51,7 +51,7 @@
RenderNode::~RenderNode() {
deleteDisplayList(nullptr);
delete mStagingDisplayList;
- LOG_ALWAYS_FATAL_IF(mLayer, "layer missed detachment!");
+ LOG_ALWAYS_FATAL_IF(hasLayer(), "layer missed detachment!");
}
void RenderNode::setStagingDisplayList(DisplayList* displayList, TreeObserver* observer) {
@@ -81,7 +81,7 @@
<< (properties().hasShadow() ? ", casting shadow" : "")
<< (isRenderable() ? "" : ", empty")
<< (properties().getProjectBackwards() ? ", projected" : "")
- << (mLayer != nullptr ? ", on HW Layer" : "")
+ << (hasLayer() ? ", on HW Layer" : "")
<< ")" << std::endl;
properties().debugOutputProperties(output, level + 1);
@@ -229,19 +229,6 @@
}
}
-static OffscreenBuffer* createLayer(RenderState& renderState, uint32_t width, uint32_t height) {
- return renderState.layerPool().get(renderState, width, height);
-}
-
-static void destroyLayer(OffscreenBuffer* layer) {
- RenderState& renderState = layer->renderState;
- renderState.layerPool().putOrDelete(layer);
-}
-
-static bool layerMatchesWidthAndHeight(OffscreenBuffer* layer, int width, int height) {
- return layer->viewportWidth == (uint32_t) width && layer->viewportHeight == (uint32_t)height;
-}
-
void RenderNode::pushLayerUpdate(TreeInfo& info) {
LayerType layerType = properties().effectiveLayerType();
// If we are not a layer OR we cannot be rendered (eg, view was detached)
@@ -250,36 +237,17 @@
|| CC_UNLIKELY(!isRenderable())
|| CC_UNLIKELY(properties().getWidth() == 0)
|| CC_UNLIKELY(properties().getHeight() == 0)) {
- if (CC_UNLIKELY(mLayer)) {
- destroyLayer(mLayer);
- mLayer = nullptr;
+ if (CC_UNLIKELY(hasLayer())) {
+ renderthread::CanvasContext::destroyLayer(this);
}
return;
}
- bool transformUpdateNeeded = false;
- if (!mLayer) {
- mLayer = createLayer(info.canvasContext.getRenderState(), getWidth(), getHeight());
+ if(info.canvasContext.createOrUpdateLayer(this, *info.damageAccumulator)) {
damageSelf(info);
- transformUpdateNeeded = true;
- } else if (!layerMatchesWidthAndHeight(mLayer, getWidth(), getHeight())) {
- // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
- // Or, ideally, maintain damage between frames on node/layer so ordering is always correct
- RenderState& renderState = mLayer->renderState;
- if (properties().fitsOnLayer()) {
- mLayer = renderState.layerPool().resize(mLayer, getWidth(), getHeight());
- } else {
- destroyLayer(mLayer);
- mLayer = nullptr;
- }
- damageSelf(info);
- transformUpdateNeeded = true;
}
- SkRect dirty;
- info.damageAccumulator->peekAtDirty(&dirty);
-
- if (!mLayer) {
+ if (!hasLayer()) {
Caches::getInstance().dumpMemoryUsage();
if (info.errorHandler) {
std::ostringstream err;
@@ -296,13 +264,8 @@
return;
}
- if (transformUpdateNeeded && mLayer) {
- // update the transform in window of the layer to reset its origin wrt light source position
- Matrix4 windowTransform;
- info.damageAccumulator->computeCurrentTransform(&windowTransform);
- mLayer->setWindowTransform(windowTransform);
- }
-
+ SkRect dirty;
+ info.damageAccumulator->peekAtDirty(&dirty);
info.layerUpdateQueue->enqueueLayerWithDamage(this, dirty);
// There might be prefetched layers that need to be accounted for.
@@ -332,9 +295,9 @@
bool willHaveFunctor = false;
if (info.mode == TreeInfo::MODE_FULL && mStagingDisplayList) {
- willHaveFunctor = !mStagingDisplayList->getFunctors().empty();
+ willHaveFunctor = mStagingDisplayList->hasFunctor();
} else if (mDisplayList) {
- willHaveFunctor = !mDisplayList->getFunctors().empty();
+ willHaveFunctor = mDisplayList->hasFunctor();
}
bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence(
willHaveFunctor, functorsNeedLayer);
@@ -347,15 +310,15 @@
if (info.mode == TreeInfo::MODE_FULL) {
pushStagingDisplayListChanges(info);
}
- prepareSubTree(info, childFunctorsNeedLayer, mDisplayList);
if (mDisplayList) {
- for (auto& vectorDrawable : mDisplayList->getVectorDrawables()) {
- // If any vector drawable in the display list needs update, damage the node.
- if (vectorDrawable->isDirty()) {
- damageSelf(info);
- }
- vectorDrawable->setPropertyChangeWillBeConsumed(true);
+ info.out.hasFunctors |= mDisplayList->hasFunctor();
+ bool isDirty = mDisplayList->prepareListAndChildren(info, childFunctorsNeedLayer,
+ [](RenderNode* child, TreeInfo& info, bool functorsNeedLayer) {
+ child->prepareTreeImpl(info, functorsNeedLayer);
+ });
+ if (isDirty) {
+ damageSelf(info);
}
}
pushLayerUpdate(info);
@@ -393,20 +356,15 @@
// Make sure we inc first so that we don't fluctuate between 0 and 1,
// which would thrash the layer cache
if (mStagingDisplayList) {
- for (auto&& child : mStagingDisplayList->getChildren()) {
- child->renderNode->incParentRefCount();
- }
+ mStagingDisplayList->updateChildren([](RenderNode* child) {
+ child->incParentRefCount();
+ });
}
deleteDisplayList(info ? info->observer : nullptr, info);
mDisplayList = mStagingDisplayList;
mStagingDisplayList = nullptr;
if (mDisplayList) {
- for (auto& iter : mDisplayList->getFunctors()) {
- (*iter.functor)(DrawGlInfo::kModeSync, nullptr);
- }
- for (auto& vectorDrawable : mDisplayList->getVectorDrawables()) {
- vectorDrawable->syncProperties();
- }
+ mDisplayList->syncContents();
}
}
@@ -423,41 +381,24 @@
void RenderNode::deleteDisplayList(TreeObserver* observer, TreeInfo* info) {
if (mDisplayList) {
- for (auto&& child : mDisplayList->getChildren()) {
- child->renderNode->decParentRefCount(observer, info);
+ mDisplayList->updateChildren([observer, info](RenderNode* child) {
+ child->decParentRefCount(observer, info);
+ });
+ if (!mDisplayList->reuseDisplayList(this, info ? &info->canvasContext : nullptr)) {
+ delete mDisplayList;
}
}
- delete mDisplayList;
mDisplayList = nullptr;
}
-void RenderNode::prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayList* subtree) {
- if (subtree) {
- TextureCache& cache = Caches::getInstance().textureCache;
- info.out.hasFunctors |= subtree->getFunctors().size();
- for (auto&& bitmapResource : subtree->getBitmapResources()) {
- void* ownerToken = &info.canvasContext;
- info.prepareTextures = cache.prefetchAndMarkInUse(ownerToken, bitmapResource);
- }
- for (auto&& op : subtree->getChildren()) {
- RenderNode* childNode = op->renderNode;
- info.damageAccumulator->pushTransform(&op->localMatrix);
- bool childFunctorsNeedLayer = functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
- childNode->prepareTreeImpl(info, childFunctorsNeedLayer);
- info.damageAccumulator->popTransform();
- }
- }
-}
-
void RenderNode::destroyHardwareResources(TreeObserver* observer, TreeInfo* info) {
- if (mLayer) {
- destroyLayer(mLayer);
- mLayer = nullptr;
+ if (hasLayer()) {
+ renderthread::CanvasContext::destroyLayer(this);
}
if (mDisplayList) {
- for (auto&& child : mDisplayList->getChildren()) {
- child->renderNode->destroyHardwareResources(observer, info);
- }
+ mDisplayList->updateChildren([observer, info](RenderNode* child) {
+ child->destroyHardwareResources(observer, info);
+ });
if (mNeedsDisplayListSync) {
// Next prepare tree we are going to push a new display list, so we can
// drop our current one now
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index a0679b1..a05c744 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -32,6 +32,7 @@
#include "DisplayList.h"
#include "Matrix.h"
#include "RenderProperties.h"
+#include "SkiaDisplayList.h"
#include <vector>
@@ -39,6 +40,7 @@
class SkPaint;
class SkPath;
class SkRegion;
+class SkSurface;
namespace android {
namespace uirenderer {
@@ -48,6 +50,7 @@
class FrameBuilder;
class OffscreenBuffer;
class Rect;
+class SkiaDisplayList;
class SkiaShader;
struct RenderNodeOp;
@@ -199,6 +202,7 @@
}
OffscreenBuffer* getLayer() const { return mLayer; }
OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
+ void setLayer(OffscreenBuffer* layer) { mLayer = layer; }
// Note: The position callbacks are relying on the listener using
// the frameNumber to appropriately batch/synchronize these transactions.
@@ -239,7 +243,6 @@
void prepareTreeImpl(TreeInfo& info, bool functorsNeedLayer);
void pushStagingPropertiesChanges(TreeInfo& info);
void pushStagingDisplayListChanges(TreeInfo& info);
- void prepareSubTree(TreeInfo& info, bool functorsNeedLayer, DisplayList* subtree);
void prepareLayer(TreeInfo& info, uint32_t dirtyMask);
void pushLayerUpdate(TreeInfo& info);
void deleteDisplayList(TreeObserver* observer, TreeInfo* info = nullptr);
@@ -284,6 +287,63 @@
uint32_t mParentCount;
sp<PositionListener> mPositionListener;
+
+// METHODS & FIELDS ONLY USED BY THE SKIA RENDERER
+public:
+ /**
+ * Detach and transfer ownership of an already allocated displayList for use
+ * in recording updated content for this renderNode
+ */
+ std::unique_ptr<SkiaDisplayList> detachAvailableList() {
+ return std::move(mAvailableDisplayList);
+ }
+
+ /**
+ * Attach unused displayList to this node for potential future reuse.
+ */
+ void attachAvailableList(SkiaDisplayList* skiaDisplayList) {
+ mAvailableDisplayList.reset(skiaDisplayList);
+ }
+
+ /**
+ * Returns true if an offscreen layer from any renderPipeline is attached
+ * to this node.
+ */
+ bool hasLayer() const { return mLayer || mLayerSurface.get(); }
+
+ /**
+ * Used by the RenderPipeline to attach an offscreen surface to the RenderNode.
+ * The surface is then will be used to store the contents of a layer.
+ */
+ void setLayerSurface(sk_sp<SkSurface> layer) { mLayerSurface = layer; }
+
+
+ /**
+ * If the RenderNode is of type LayerType::RenderLayer then this method will
+ * return the an offscreen rendering surface that is used to both render into
+ * the layer and composite the layer into its parent. If the type is not
+ * LayerType::RenderLayer then it will return a nullptr.
+ *
+ * NOTE: this function is only guaranteed to return accurate results after
+ * prepareTree has been run for this RenderNode
+ */
+ SkSurface* getLayerSurface() const { return mLayerSurface.get(); }
+
+private:
+ /**
+ * If this RenderNode has been used in a previous frame then the SkiaDisplayList
+ * from that frame is cached here until one of the following conditions is met:
+ * 1) The RenderNode is deleted (causing this to be deleted)
+ * 2) It is replaced with the displayList from the next completed frame
+ * 3) It is detached and used to to record a new displayList for a later frame
+ */
+ std::unique_ptr<SkiaDisplayList> mAvailableDisplayList;
+
+ /**
+ * An offscreen rendering target used to contain the contents this RenderNode
+ * when it has been set to draw as a LayerType::RenderLayer.
+ */
+ sk_sp<SkSurface> mLayerSurface;
}; // class RenderNode
} /* namespace uirenderer */
diff --git a/libs/hwui/SkiaDisplayList.cpp b/libs/hwui/SkiaDisplayList.cpp
new file mode 100644
index 0000000..d10f306
--- /dev/null
+++ b/libs/hwui/SkiaDisplayList.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SkiaDisplayList.h"
+
+#include "renderthread/CanvasContext.h"
+#include "VectorDrawable.h"
+
+#include <SkImagePriv.h>
+#include <SkMutex.h>
+
+namespace android {
+namespace uirenderer {
+
+SkiaDisplayList::SkiaDisplayList(SkRect bounds) : mDrawable(SkLiteDL::New(bounds)) {
+ SkASSERT(projectionReceiveIndex == -1);
+}
+
+void SkiaDisplayList::syncContents() {
+ for (auto& functor : mChildFunctors) {
+ functor.syncFunctor();
+ }
+ for (auto& vectorDrawable : mVectorDrawables) {
+ vectorDrawable->syncProperties();
+ }
+}
+
+bool SkiaDisplayList::reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) {
+ reset(context ? context->getGrContext() : nullptr, SkRect::MakeEmpty());
+ node->attachAvailableList(this);
+ return true;
+}
+
+void SkiaDisplayList::updateChildren(std::function<void(RenderNode*)> updateFn) {
+ for (auto& child : mChildNodes) {
+ updateFn(child.getRenderNode());
+ }
+}
+
+bool SkiaDisplayList::prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeInfo&, bool)> childFn) {
+ // force all mutable images to be pinned in the GPU cache for the duration
+ // of this frame
+ pinImages(info.canvasContext.getGrContext());
+
+ for (auto& child : mChildNodes) {
+ RenderNode* childNode = child.getRenderNode();
+ Matrix4 mat4(child.getRecordedMatrix());
+ info.damageAccumulator->pushTransform(&mat4);
+ // TODO: a layer is needed if the canvas is rotated or has a non-rect clip
+ bool childFunctorsNeedLayer = functorsNeedLayer;
+ childFn(childNode, info, childFunctorsNeedLayer);
+ info.damageAccumulator->popTransform();
+ }
+
+ bool isDirty = false;
+ for (auto& vectorDrawable : mVectorDrawables) {
+ // If any vector drawable in the display list needs update, damage the node.
+ if (vectorDrawable->isDirty()) {
+ isDirty = true;
+ }
+ vectorDrawable->setPropertyChangeWillBeConsumed(true);
+ }
+ return isDirty;
+}
+
+static std::vector<sk_sp<SkImage>> gPinnedImages;
+static SkBaseMutex gLock;
+
+void SkiaDisplayList::pinImages(GrContext* context) {
+ if (mPinnedImages) return;
+ for (SkImage* image : mMutableImages) {
+ SkImage_pinAsTexture(image, context);
+ }
+ mPinnedImages = true;
+}
+
+void SkiaDisplayList::unpinImages(GrContext* context) {
+ if (!mPinnedImages) return;
+ if (context) {
+ for (SkImage* image : mMutableImages) {
+ SkImage_unpinAsTexture(image, context);
+ }
+ } else {
+ gLock.acquire();
+ for (SkImage* image : mMutableImages) {
+ gPinnedImages.emplace_back(sk_ref_sp(image));
+ }
+ gLock.release();
+ }
+ mPinnedImages = false;
+}
+
+void SkiaDisplayList::cleanupImages(GrContext* context) {
+ gLock.acquire();
+ for (auto& image : gPinnedImages) {
+ SkImage_unpinAsTexture(image.get(), context);
+ }
+ gPinnedImages.clear();
+ gLock.release();
+}
+
+void SkiaDisplayList::reset(GrContext* context, SkRect bounds) {
+ unpinImages(context);
+ SkASSERT(!mPinnedImages);
+ mIsProjectionReceiver = false;
+
+ mDrawable->reset(bounds);
+
+ mMutableImages.clear();
+ mVectorDrawables.clear();
+ mChildFunctors.clear();
+ mChildNodes.clear();
+
+ projectionReceiveIndex = -1;
+ allocator.~LinearAllocator();
+ new (&allocator) LinearAllocator();
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SkiaDisplayList.h b/libs/hwui/SkiaDisplayList.h
new file mode 100644
index 0000000..c8a82bd
--- /dev/null
+++ b/libs/hwui/SkiaDisplayList.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "DisplayList.h"
+#include "SkiaDrawables.h"
+
+#include <deque>
+#include <SkLiteDL.h>
+#include <SkPictureRecorder.h>
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * This class is intended to be self contained, but still subclasses from
+ * DisplayList to make it easier to support switching between the two at
+ * runtime. The downside of this inheritance is that we pay for the overhead
+ * of the parent class construction/destruction without any real benefit.
+ */
+class SkiaDisplayList : public DisplayList {
+public:
+ SkiaDisplayList(SkRect bounds);
+ virtual ~SkiaDisplayList() {
+ /* Given that we are using a LinearStdAllocator to store some of the
+ * SkDrawable contents we must ensure that any other object that is
+ * holding a reference to those drawables is destroyed prior to their
+ * deletion.
+ */
+ mDrawable.reset();
+ }
+
+ /**
+ * This resets the DisplayList so that it behaves as if the object were newly
+ * constructed with the provided bounds. The reuse avoids any overhead
+ * associated with destroying the SkLiteDL as well as the deques and vectors.
+ */
+ void reset(GrContext* context, SkRect bounds);
+
+ /**
+ * Use the linear allocator to create any SkDrawables needed by the display
+ * list. This could be dangerous as these objects are ref-counted, so we
+ * need to monitor that they don't extend beyond the lifetime of the class
+ * that creates them.
+ */
+ template<class T, typename... Params>
+ SkDrawable* allocateDrawable(Params&&... params) {
+ return allocator.create<T>(std::forward<Params>(params)...);
+ }
+
+ bool isSkiaDL() const override { return true; }
+
+ /**
+ * Returns true if the DisplayList does not have any recorded content
+ */
+ bool isEmpty() const override { return mDrawable->empty(); }
+
+ /**
+ * Returns true if this list directly contains a GLFunctor drawing command.
+ */
+ bool hasFunctor() const override { return !mChildFunctors.empty(); }
+
+ /**
+ * Returns true if this list directly contains a VectorDrawable drawing command.
+ */
+ bool hasVectorDrawables() const override { return !mVectorDrawables.empty(); }
+
+ /**
+ * Attempts to reset and reuse this DisplayList.
+ *
+ * @return true if the displayList will be reused and therefore should not be deleted
+ */
+ bool reuseDisplayList(RenderNode* node, renderthread::CanvasContext* context) override;
+
+ /**
+ * ONLY to be called by RenderNode::syncDisplayList so that we can notify any
+ * contained VectorDrawables or GLFunctors to sync their state.
+ *
+ * NOTE: This function can be folded into RenderNode when we no longer need
+ * to subclass from DisplayList
+ */
+ void syncContents() override;
+
+ /**
+ * ONLY to be called by RenderNode::prepareTree in order to prepare this
+ * list while the UI thread is blocked. Here we can upload mutable bitmaps
+ * and notify our parent if any of our content has been invalidated and in
+ * need of a redraw. If the renderNode has any children then they are also
+ * call in order to prepare them.
+ *
+ * @return true if any content change requires the node to be invalidated
+ *
+ * NOTE: This function can be folded into RenderNode when we no longer need
+ * to subclass from DisplayList
+ */
+
+ bool prepareListAndChildren(TreeInfo& info, bool functorsNeedLayer,
+ std::function<void(RenderNode*, TreeInfo&, bool)> childFn) override;
+
+ /**
+ * Calls the provided function once for each child of this DisplayList
+ */
+ void updateChildren(std::function<void(RenderNode*)> updateFn) override;
+
+ /**
+ * Pin/Unpin any mutable images to the GPU cache. A pinned images is
+ * guaranteed to be remain in the cache until it has been unpinned which
+ * we leverage to avoid making a CPU copy of the pixels.
+ */
+ void pinImages(GrContext* context);
+ void unpinImages(GrContext* context);
+
+ /**
+ * If a SkiaDisplayList is deleted on the UI thread we cache a list of any
+ * images that need unpinned from the GPU cache and call this function on
+ * a subsequent frame to perform that cleanup.
+ */
+ static void cleanupImages(GrContext* context);
+
+ /**
+ * We use std::deque here because (1) we need to iterate through these
+ * elements and (2) mDrawable holds pointers to the elements, so they cannot
+ * relocate.
+ */
+ std::deque<RenderNodeDrawable> mChildNodes;
+ std::deque<GLFunctorDrawable> mChildFunctors;
+ std::vector<SkImage*> mMutableImages;
+ std::vector<VectorDrawableRoot*> mVectorDrawables;
+ sk_sp<SkLiteDL> mDrawable;
+
+ bool mIsProjectionReceiver = false;
+
+private:
+ bool mPinnedImages = false;
+};
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SkiaDrawables.h b/libs/hwui/SkiaDrawables.h
new file mode 100644
index 0000000..a1ceeaa
--- /dev/null
+++ b/libs/hwui/SkiaDrawables.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "Layer.h"
+#include "RenderNode.h"
+
+#include <SkCanvas.h>
+#include <SkDrawable.h>
+#include <SkMatrix.h>
+
+#include <utils/RefBase.h>
+#include <utils/FatVector.h>
+#include <utils/Functor.h>
+
+namespace android {
+
+class Functor;
+
+namespace uirenderer {
+
+
+class RenderProperties;
+class OffscreenBuffer;
+class GlFunctorLifecycleListener;
+class SkiaDisplayList;
+
+/**
+ * This drawable wraps a RenderNode and enables it to be recorded into a list
+ * of Skia drawing commands.
+ */
+class RenderNodeDrawable : public SkDrawable {
+public:
+ explicit RenderNodeDrawable(RenderNode* node, SkCanvas* canvas)
+ : mRenderNode(node)
+ , mRecordedTransform(canvas->getTotalMatrix()) {}
+
+ /**
+ * The renderNode (and its properties) that is to be drawn
+ */
+ RenderNode* getRenderNode() const { return mRenderNode.get(); }
+
+ /**
+ * Returns the transform on the canvas at time of recording and is used for
+ * computing total transform without rerunning DL contents.
+ */
+ const SkMatrix& getRecordedMatrix() const { return mRecordedTransform; }
+
+protected:
+ virtual SkRect onGetBounds() override {
+ // We don't want to enable a record time quick reject because the properties
+ // of the RenderNode may be updated on subsequent frames.
+ return SkRect::MakeLargest();
+ }
+ virtual void onDraw(SkCanvas* canvas) override { /* TODO */ }
+
+private:
+ sp<RenderNode> mRenderNode;
+ const SkMatrix mRecordedTransform;
+};
+
+/**
+ * This drawable wraps a OpenGL functor enabling it to be recorded into a list
+ * of Skia drawing commands.
+ */
+class GLFunctorDrawable : public SkDrawable {
+public:
+ GLFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
+ : mFunctor(functor)
+ , mListener(listener) {
+ canvas->getClipBounds(&mBounds);
+ }
+ virtual ~GLFunctorDrawable() {}
+
+ void syncFunctor() const { (*mFunctor)(DrawGlInfo::kModeSync, nullptr); }
+
+ protected:
+ virtual SkRect onGetBounds() override { return mBounds; }
+ virtual void onDraw(SkCanvas* canvas) override { /* TODO */ }
+
+ private:
+ Functor* mFunctor;
+ sp<GlFunctorLifecycleListener> mListener;
+ SkRect mBounds;
+};
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 6f4a683..5d9e5c0 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -173,15 +173,16 @@
outData->gradientSampler = 0;
outData->gradientTexture = nullptr;
- outData->startColor.set(gradInfo.fColors[0]);
- outData->endColor.set(gradInfo.fColors[1]);
+ outData->startColor.setSRGB(gradInfo.fColors[0]);
+ outData->endColor.setSRGB(gradInfo.fColors[1]);
}
- outData->ditherSampler = (*textureUnit)++;
return true;
}
-void applyGradient(Caches& caches, const SkiaShaderData::GradientShaderData& data) {
+void applyGradient(Caches& caches, const SkiaShaderData::GradientShaderData& data,
+ const GLsizei width, const GLsizei height) {
+
if (CC_UNLIKELY(data.gradientTexture)) {
caches.textureState().activateTexture(data.gradientSampler);
bindTexture(&caches, data.gradientTexture, data.wrapST, data.wrapST);
@@ -191,10 +192,7 @@
bindUniformColor(caches.program().getUniform("endColor"), data.endColor);
}
- // TODO: remove sampler slot incrementing from dither.setupProgram,
- // since this assignment of slots is done at store, not apply time
- GLuint ditherSampler = data.ditherSampler;
- caches.dither.setupProgram(caches.program(), &ditherSampler);
+ glUniform2f(caches.program().getUniform("screenSize"), 1.0f / width, 1.0f / height);
glUniformMatrix4fv(caches.program().getUniform("screenSpace"), 1,
GL_FALSE, &data.screenSpace.data[0]);
}
@@ -208,13 +206,7 @@
return false;
}
- /*
- * Bypass the AssetAtlas, since those textures:
- * 1) require UV mapping, which isn't implemented in matrix computation below
- * 2) can't handle REPEAT simply
- * 3) are safe to upload here (outside of sync stage), since they're static
- */
- outData->bitmapTexture = caches.textureCache.getAndBypassAtlas(&bitmap);
+ outData->bitmapTexture = caches.textureCache.get(&bitmap);
if (!outData->bitmapTexture) return false;
outData->bitmapSampler = (*textureUnit)++;
@@ -388,11 +380,12 @@
outData->skiaShaderType = kNone_SkiaShaderType;
}
-void SkiaShader::apply(Caches& caches, const SkiaShaderData& data) {
+void SkiaShader::apply(Caches& caches, const SkiaShaderData& data,
+ const GLsizei width, const GLsizei height) {
if (!data.skiaShaderType) return;
if (data.skiaShaderType & kGradient_SkiaShaderType) {
- applyGradient(caches, data.gradientData);
+ applyGradient(caches, data.gradientData, width, height);
}
if (data.skiaShaderType & kBitmap_SkiaShaderType) {
applyBitmap(caches, data.bitmapData);
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 884196d..5854289 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -62,7 +62,6 @@
} bitmapData;
struct GradientShaderData {
Matrix4 screenSpace;
- GLuint ditherSampler;
// simple gradient
FloatColor startColor;
@@ -72,7 +71,6 @@
Texture* gradientTexture;
GLuint gradientSampler;
GLenum wrapST;
-
} gradientData;
struct LayerShaderData {
Layer* layer;
@@ -90,7 +88,8 @@
static void store(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
GLuint* textureUnit, ProgramDescription* description,
SkiaShaderData* outData);
- static void apply(Caches& caches, const SkiaShaderData& data);
+ static void apply(Caches& caches, const SkiaShaderData& data,
+ const GLsizei width, const GLsizei height);
};
}; // namespace uirenderer
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index e2ee5bf..7b0a1bc 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -927,9 +927,13 @@
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], newPenumbra[i].x,
newPenumbra[i].y, PENUMBRA_ALPHA);
}
+ // Since the umbra can be a faked one when the occluder is too high, the umbra should be lighter
+ // in this case.
+ float scaledUmbraAlpha = UMBRA_ALPHA * shadowStrengthScale;
+
for (int i = 0; i < umbraLength; i++) {
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], umbra[i].x, umbra[i].y,
- UMBRA_ALPHA);
+ scaledUmbraAlpha);
}
for (int i = 0; i < verticesPairIndex; i++) {
@@ -969,14 +973,14 @@
indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
- closerVertex.x, closerVertex.y, UMBRA_ALPHA);
+ closerVertex.x, closerVertex.y, scaledUmbraAlpha);
}
} else {
// If there is no occluded umbra at all, then draw the triangle fan
// starting from the centroid to all umbra vertices.
int lastCentroidIndex = vertexBufferIndex;
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid.x,
- centroid.y, UMBRA_ALPHA);
+ centroid.y, scaledUmbraAlpha);
for (int i = 0; i < umbraLength; i++) {
indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
indexBuffer[indexBufferIndex++] = lastCentroidIndex;
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 4f49a35..908f572 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -26,19 +26,23 @@
namespace android {
namespace uirenderer {
+// Number of bytes used by a texture in the given format
static int bytesPerPixel(GLint glFormat) {
switch (glFormat) {
// The wrapped-texture case, usually means a SurfaceTexture
case 0:
return 0;
+ case GL_LUMINANCE:
case GL_ALPHA:
return 1;
+ case GL_SRGB8:
case GL_RGB:
return 3;
+ case GL_SRGB8_ALPHA8:
case GL_RGBA:
return 4;
case GL_RGBA16F:
- return 16;
+ return 8;
default:
LOG_ALWAYS_FATAL("UNKNOWN FORMAT %d", glFormat);
}
@@ -83,14 +87,16 @@
mId = 0;
}
-bool Texture::updateSize(uint32_t width, uint32_t height, GLint format) {
- if (mWidth == width && mHeight == height && mFormat == format) {
+bool Texture::updateSize(uint32_t width, uint32_t height, GLint internalFormat, GLint format) {
+ if (mWidth == width && mHeight == height &&
+ mFormat == format && mInternalFormat == internalFormat) {
return false;
}
mWidth = width;
mHeight = height;
mFormat = format;
- notifySizeChanged(mWidth * mHeight * bytesPerPixel(mFormat));
+ mInternalFormat = internalFormat;
+ notifySizeChanged(mWidth * mHeight * bytesPerPixel(internalFormat));
return true;
}
@@ -101,10 +107,10 @@
mMagFilter = GL_LINEAR;
}
-void Texture::upload(GLint internalformat, uint32_t width, uint32_t height,
+void Texture::upload(GLint internalFormat, uint32_t width, uint32_t height,
GLenum format, GLenum type, const void* pixels) {
GL_CHECKPOINT(MODERATE);
- bool needsAlloc = updateSize(width, height, internalformat);
+ bool needsAlloc = updateSize(width, height, internalFormat, format);
if (!mId) {
glGenTextures(1, &mId);
needsAlloc = true;
@@ -112,17 +118,17 @@
}
mCaches.textureState().bindTexture(GL_TEXTURE_2D, mId);
if (needsAlloc) {
- glTexImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0,
format, type, pixels);
} else if (pixels) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, mFormat, mWidth, mHeight, 0,
+ glTexSubImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0,
format, type, pixels);
}
GL_CHECKPOINT(MODERATE);
}
-static void uploadToTexture(bool resize, GLenum format, GLenum type, GLsizei stride, GLsizei bpp,
- GLsizei width, GLsizei height, const GLvoid * data) {
+static void uploadToTexture(bool resize, GLint internalFormat, GLenum format, GLenum type,
+ GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height, const GLvoid * data) {
const bool useStride = stride != width
&& Caches::getInstance().extensions().hasUnpackRowLength();
@@ -132,7 +138,7 @@
}
if (resize) {
- glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, data);
} else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
}
@@ -156,7 +162,7 @@
}
if (resize) {
- glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, temp);
} else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
}
@@ -166,31 +172,44 @@
}
static void uploadSkBitmapToTexture(const SkBitmap& bitmap,
- bool resize, GLenum format, GLenum type) {
- uploadToTexture(resize, format, type, bitmap.rowBytesAsPixels(), bitmap.bytesPerPixel(),
- bitmap.width(), bitmap.height(), bitmap.getPixels());
+ bool resize, GLint internalFormat, GLenum format, GLenum type) {
+ uploadToTexture(resize, internalFormat, format, type, bitmap.rowBytesAsPixels(),
+ bitmap.bytesPerPixel(), bitmap.width(), bitmap.height(), bitmap.getPixels());
}
-static void colorTypeToGlFormatAndType(SkColorType colorType,
- GLint* outFormat, GLint* outType) {
+static void colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType,
+ bool needSRGB, GLint* outInternalFormat, GLint* outFormat, GLint* outType) {
switch (colorType) {
case kAlpha_8_SkColorType:
*outFormat = GL_ALPHA;
+ *outInternalFormat = GL_ALPHA;
*outType = GL_UNSIGNED_BYTE;
break;
case kRGB_565_SkColorType:
- *outFormat = GL_RGB;
- *outType = GL_UNSIGNED_SHORT_5_6_5;
+ if (needSRGB) {
+ // We would ideally use a GL_RGB/GL_SRGB8 texture but the
+ // intermediate Skia bitmap needs to be ARGB_8888
+ *outFormat = GL_RGBA;
+ *outInternalFormat = caches.rgbaInternalFormat();
+ *outType = GL_UNSIGNED_BYTE;
+ } else {
+ *outFormat = GL_RGB;
+ *outInternalFormat = GL_RGB;
+ *outType = GL_UNSIGNED_SHORT_5_6_5;
+ }
break;
// ARGB_4444 and Index_8 are both upconverted to RGBA_8888
case kARGB_4444_SkColorType:
case kIndex_8_SkColorType:
case kN32_SkColorType:
*outFormat = GL_RGBA;
+ *outInternalFormat = caches.rgbaInternalFormat(needSRGB);
*outType = GL_UNSIGNED_BYTE;
break;
case kGray_8_SkColorType:
+ // TODO: Handle sRGB
*outFormat = GL_LUMINANCE;
+ *outInternalFormat = GL_LUMINANCE;
*outType = GL_UNSIGNED_BYTE;
break;
default:
@@ -224,29 +243,36 @@
setDefaultParams = true;
}
- GLint format, type;
- colorTypeToGlFormatAndType(bitmap.colorType(), &format, &type);
+ sk_sp<SkColorSpace> sRGB = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+ bool needSRGB = bitmap.colorSpace() == sRGB.get();
- if (updateSize(bitmap.width(), bitmap.height(), format)) {
+ GLint internalFormat, format, type;
+ colorTypeToGlFormatAndType(mCaches, bitmap.colorType(), needSRGB, &internalFormat, &format, &type);
+
+ if (updateSize(bitmap.width(), bitmap.height(), internalFormat, format)) {
needsAlloc = true;
}
blend = !bitmap.isOpaque();
mCaches.textureState().bindTexture(mId);
+ // TODO: Handle sRGB gray bitmaps
+ bool hasSRGB = mCaches.extensions().hasSRGB();
if (CC_UNLIKELY(bitmap.colorType() == kARGB_4444_SkColorType
- || bitmap.colorType() == kIndex_8_SkColorType)) {
+ || bitmap.colorType() == kIndex_8_SkColorType
+ || (bitmap.colorType() == kRGB_565_SkColorType && hasSRGB && needSRGB))) {
+
SkBitmap rgbaBitmap;
- rgbaBitmap.allocPixels(SkImageInfo::MakeN32(mWidth, mHeight,
- bitmap.alphaType()));
+ rgbaBitmap.allocPixels(SkImageInfo::MakeN32(
+ mWidth, mHeight, bitmap.alphaType(), hasSRGB ? sRGB : nullptr));
rgbaBitmap.eraseColor(0);
SkCanvas canvas(rgbaBitmap);
canvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr);
- uploadSkBitmapToTexture(rgbaBitmap, needsAlloc, format, type);
+ uploadSkBitmapToTexture(rgbaBitmap, needsAlloc, internalFormat, format, type);
} else {
- uploadSkBitmapToTexture(bitmap, needsAlloc, format, type);
+ uploadSkBitmapToTexture(bitmap, needsAlloc, internalFormat, format, type);
}
if (canMipMap) {
@@ -262,11 +288,12 @@
}
}
-void Texture::wrap(GLuint id, uint32_t width, uint32_t height, GLint format) {
+void Texture::wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat, GLint format) {
mId = id;
mWidth = width;
mHeight = height;
mFormat = format;
+ mInternalFormat = internalFormat;
// We're wrapping an existing texture, so don't double count this memory
notifySizeChanged(0);
}
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index b72742f..aa8a6d3 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -69,8 +69,8 @@
*
* The image data is undefined after calling this.
*/
- void resize(uint32_t width, uint32_t height, GLint format) {
- upload(format, width, height, format, GL_UNSIGNED_BYTE, nullptr);
+ void resize(uint32_t width, uint32_t height, GLint internalFormat, GLint format) {
+ upload(internalFormat, width, height, format, GL_UNSIGNED_BYTE, nullptr);
}
/**
@@ -85,13 +85,13 @@
/**
* Basically glTexImage2D/glTexSubImage2D.
*/
- void upload(GLint internalformat, uint32_t width, uint32_t height,
+ void upload(GLint internalFormat, uint32_t width, uint32_t height,
GLenum format, GLenum type, const void* pixels);
/**
* Wraps an existing texture.
*/
- void wrap(GLuint id, uint32_t width, uint32_t height, GLint format);
+ void wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat, GLint format);
GLuint id() const {
return mId;
@@ -109,6 +109,10 @@
return mFormat;
}
+ GLint internalFormat() const {
+ return mInternalFormat;
+ }
+
/**
* Generation of the backing bitmap,
*/
@@ -148,13 +152,14 @@
friend class Layer;
// Returns true if the size changed, false if it was the same
- bool updateSize(uint32_t width, uint32_t height, GLint format);
+ bool updateSize(uint32_t width, uint32_t height, GLint internalFormat, GLint format);
void resetCachedParams();
GLuint mId = 0;
uint32_t mWidth = 0;
uint32_t mHeight = 0;
GLint mFormat = 0;
+ GLint mInternalFormat = 0;
/* See GLES spec section 3.8.14
* "In the initial state, the value assigned to TEXTURE_MIN_FILTER is
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 523924a..5ccdbda 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -18,7 +18,6 @@
#include <utils/Mutex.h>
-#include "AssetAtlas.h"
#include "Caches.h"
#include "Texture.h"
#include "TextureCache.h"
@@ -36,8 +35,7 @@
: mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity)
, mSize(0)
, mMaxSize(Properties::textureCacheSize)
- , mFlushRate(Properties::textureCacheFlushRate)
- , mAssetAtlas(nullptr) {
+ , mFlushRate(Properties::textureCacheFlushRate) {
mCache.setOnEntryRemovedListener(this);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
@@ -84,10 +82,6 @@
// Caching
///////////////////////////////////////////////////////////////////////////////
-void TextureCache::setAssetAtlas(AssetAtlas* assetAtlas) {
- mAssetAtlas = assetAtlas;
-}
-
void TextureCache::resetMarkInUse(void* ownerToken) {
LruCache<uint32_t, Texture*>::Iterator iter(mCache);
while (iter.next()) {
@@ -108,14 +102,7 @@
// Returns a prepared Texture* that either is already in the cache or can fit
// in the cache (and is thus added to the cache)
-Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType atlasUsageType) {
- if (CC_LIKELY(mAssetAtlas != nullptr) && atlasUsageType == AtlasUsageType::Use) {
- AssetAtlas::Entry* entry = mAssetAtlas->getEntry(bitmap->pixelRef());
- if (CC_UNLIKELY(entry)) {
- return entry->texture;
- }
- }
-
+Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) {
Texture* texture = mCache.get(bitmap->pixelRef()->getStableID());
if (!texture) {
@@ -160,7 +147,7 @@
}
bool TextureCache::prefetchAndMarkInUse(void* ownerToken, const SkBitmap* bitmap) {
- Texture* texture = getCachedTexture(bitmap, AtlasUsageType::Use);
+ Texture* texture = getCachedTexture(bitmap);
if (texture) {
texture->isInUse = ownerToken;
}
@@ -168,11 +155,11 @@
}
bool TextureCache::prefetch(const SkBitmap* bitmap) {
- return getCachedTexture(bitmap, AtlasUsageType::Use);
+ return getCachedTexture(bitmap);
}
-Texture* TextureCache::get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType) {
- Texture* texture = getCachedTexture(bitmap, atlasUsageType);
+Texture* TextureCache::get(const SkBitmap* bitmap) {
+ Texture* texture = getCachedTexture(bitmap);
if (!texture) {
if (!canMakeTextureFromBitmap(bitmap)) {
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 0a61b6b..88ef771 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -47,8 +47,6 @@
// Classes
///////////////////////////////////////////////////////////////////////////////
-class AssetAtlas;
-
/**
* A simple LRU texture cache. The cache has a maximum size expressed in bytes.
* Any texture added to the cache causing the cache to grow beyond the maximum
@@ -85,20 +83,10 @@
bool prefetch(const SkBitmap* bitmap);
/**
- * Returns the texture associated with the specified bitmap from either within the cache, or
- * the AssetAtlas. If the texture cannot be found in the cache, a new texture is generated.
+ * Returns the texture associated with the specified bitmap from within the cache.
+ * If the texture cannot be found in the cache, a new texture is generated.
*/
- Texture* get(const SkBitmap* bitmap) {
- return get(bitmap, AtlasUsageType::Use);
- }
-
- /**
- * Returns the texture associated with the specified bitmap. If the texture cannot be found in
- * the cache, a new texture is generated, even if it resides in the AssetAtlas.
- */
- Texture* getAndBypassAtlas(const SkBitmap* bitmap) {
- return get(bitmap, AtlasUsageType::Bypass);
- }
+ Texture* get(const SkBitmap* bitmap);
/**
* Removes the texture associated with the specified pixelRef. This is meant
@@ -130,18 +118,10 @@
*/
void flush();
- void setAssetAtlas(AssetAtlas* assetAtlas);
-
private:
- enum class AtlasUsageType {
- Use,
- Bypass,
- };
-
bool canMakeTextureFromBitmap(const SkBitmap* bitmap);
- Texture* get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType);
- Texture* getCachedTexture(const SkBitmap* bitmap, AtlasUsageType atlasUsageType);
+ Texture* getCachedTexture(const SkBitmap* bitmap);
LruCache<uint32_t, Texture*> mCache;
@@ -155,8 +135,6 @@
std::vector<uint32_t> mGarbage;
mutable Mutex mLock;
-
- AssetAtlas* mAssetAtlas;
}; // class TextureCache
}; // namespace uirenderer
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 2b79941..a2f3cb6 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -202,7 +202,9 @@
if (properties.getFillGradient() != nullptr) {
paint.setColor(applyAlpha(SK_ColorBLACK, properties.getFillAlpha()));
SkShader* newShader = properties.getFillGradient()->newWithLocalMatrix(matrix);
- paint.setShader(newShader);
+ // newWithLocalMatrix(...) creates a new SkShader and returns a bare pointer. We need to
+ // remove the extra ref so that the ref count is correctly managed.
+ paint.setShader(newShader)->unref();
needsFill = true;
} else if (properties.getFillColor() != SK_ColorTRANSPARENT) {
paint.setColor(applyAlpha(properties.getFillColor(), properties.getFillAlpha()));
@@ -222,7 +224,9 @@
if (properties.getStrokeGradient() != nullptr) {
paint.setColor(applyAlpha(SK_ColorBLACK, properties.getStrokeAlpha()));
SkShader* newShader = properties.getStrokeGradient()->newWithLocalMatrix(matrix);
- paint.setShader(newShader);
+ // newWithLocalMatrix(...) creates a new SkShader and returns a bare pointer. We need to
+ // remove the extra ref so that the ref count is correctly managed.
+ paint.setShader(newShader)->unref();
needsStroke = true;
} else if (properties.getStrokeColor() != SK_ColorTRANSPARENT) {
paint.setColor(applyAlpha(properties.getStrokeColor(), properties.getStrokeAlpha()));
@@ -561,8 +565,12 @@
bool Tree::allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height) {
if (!canReuseBitmap(*outCache, width, height)) {
- SkImageInfo info = SkImageInfo::Make(width, height,
- kN32_SkColorType, kPremul_SkAlphaType);
+#ifndef ANDROID_ENABLE_LINEAR_BLENDING
+ sk_sp<SkColorSpace> colorSpace = nullptr;
+#else
+ sk_sp<SkColorSpace> colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+#endif
+ SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType, colorSpace);
outCache->setInfo(info);
// TODO: Count the bitmap cache against app's java heap
outCache->allocPixels(info);
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index c1bf980..db982ad 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -19,6 +19,7 @@
#include "Vector.h"
+#include "FloatColor.h"
#include "utils/Macros.h"
namespace android {
@@ -76,21 +77,19 @@
REQUIRE_COMPATIBLE_LAYOUT(TextureVertex);
/**
- * Simple structure to describe a vertex with a position, texture UV and ARGB color.
+ * Simple structure to describe a vertex with a position, texture UV and an
+ * sRGB color with alpha. The color is stored pre-multiplied in linear space.
*/
struct ColorTextureVertex {
float x, y;
float u, v;
- float r, g, b, a;
+ float r, g, b, a; // pre-multiplied linear
static inline void set(ColorTextureVertex* vertex, float x, float y,
- float u, float v, int color) {
-
- float a = ((color >> 24) & 0xff) / 255.0f;
- float r = a * ((color >> 16) & 0xff) / 255.0f;
- float g = a * ((color >> 8) & 0xff) / 255.0f;
- float b = a * ((color) & 0xff) / 255.0f;
- *vertex = { x, y, u, v, r, g, b, a };
+ float u, float v, uint32_t color) {
+ FloatColor c;
+ c.set(color);
+ *vertex = { x, y, u, v, c.r, c.g, c.b, c.a };
}
}; // struct ColorTextureVertex
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 49e9f65..e2844ad06 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -180,7 +180,12 @@
mPixelBuffer = PixelBuffer::create(mFormat, getWidth(), getHeight());
}
- mTexture.resize(mWidth, mHeight, mFormat);
+ GLint internalFormat = mFormat;
+ if (mFormat == GL_RGBA) {
+ internalFormat = mCaches.rgbaInternalFormat();
+ }
+
+ mTexture.resize(mWidth, mHeight, internalFormat, mFormat);
mTexture.setFilter(getLinearFiltering() ? GL_LINEAR : GL_NEAREST);
mTexture.setWrap(GL_CLAMP_TO_EDGE);
}
diff --git a/libs/hwui/hwui/PixelRef.cpp b/libs/hwui/hwui/PixelRef.cpp
new file mode 100644
index 0000000..795de6b
--- /dev/null
+++ b/libs/hwui/hwui/PixelRef.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "PixelRef.h"
+
+#include "Caches.h"
+
+#include <cutils/log.h>
+#include <sys/mman.h>
+#include <cutils/ashmem.h>
+
+namespace android {
+
+void PixelRef::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, SkColorTable* ctable) {
+ if (kIndex_8_SkColorType != newInfo.colorType()) {
+ ctable = nullptr;
+ }
+ mRowBytes = rowBytes;
+ if (mColorTable.get() != ctable) {
+ mColorTable.reset(ctable);
+ }
+
+ // Need to validate the alpha type to filter against the color type
+ // to prevent things like a non-opaque RGB565 bitmap
+ SkAlphaType alphaType;
+ LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
+ newInfo.colorType(), newInfo.alphaType(), &alphaType),
+ "Failed to validate alpha type!");
+
+ // Dirty hack is dirty
+ // TODO: Figure something out here, Skia's current design makes this
+ // really hard to work with. Skia really, really wants immutable objects,
+ // but with the nested-ref-count hackery going on that's just not
+ // feasible without going insane trying to figure it out
+ SkImageInfo* myInfo = const_cast<SkImageInfo*>(&this->info());
+ *myInfo = newInfo;
+ changeAlphaType(alphaType);
+
+ // Docs say to only call this in the ctor, but we're going to call
+ // it anyway even if this isn't always the ctor.
+ // TODO: Fix this too as part of the above TODO
+ setPreLocked(getStorage(), mRowBytes, mColorTable.get());
+}
+
+PixelRef::PixelRef(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
+ : SkPixelRef(info)
+ , mPixelStorageType(PixelStorageType::Heap) {
+ mPixelStorage.heap.address = address;
+ mPixelStorage.heap.size = size;
+ reconfigure(info, rowBytes, ctable);
+}
+
+PixelRef::PixelRef(void* address, void* context, FreeFunc freeFunc,
+ const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
+ : SkPixelRef(info)
+ , mPixelStorageType(PixelStorageType::External) {
+ mPixelStorage.external.address = address;
+ mPixelStorage.external.context = context;
+ mPixelStorage.external.freeFunc = freeFunc;
+ reconfigure(info, rowBytes, ctable);
+}
+
+PixelRef::PixelRef(void* address, int fd, size_t mappedSize,
+ const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable)
+ : SkPixelRef(info)
+ , mPixelStorageType(PixelStorageType::Ashmem) {
+ mPixelStorage.ashmem.address = address;
+ mPixelStorage.ashmem.fd = fd;
+ mPixelStorage.ashmem.size = mappedSize;
+ reconfigure(info, rowBytes, ctable);
+}
+
+PixelRef::~PixelRef() {
+ switch (mPixelStorageType) {
+ case PixelStorageType::External:
+ mPixelStorage.external.freeFunc(mPixelStorage.external.address,
+ mPixelStorage.external.context);
+ break;
+ case PixelStorageType::Ashmem:
+ munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
+ close(mPixelStorage.ashmem.fd);
+ break;
+ case PixelStorageType::Heap:
+ free(mPixelStorage.heap.address);
+ break;
+ }
+
+ if (android::uirenderer::Caches::hasInstance()) {
+ android::uirenderer::Caches::getInstance().textureCache.releaseTexture(getStableID());
+ }
+}
+
+bool PixelRef::hasHardwareMipMap() const {
+ return mHasHardwareMipMap;
+}
+
+void PixelRef::setHasHardwareMipMap(bool hasMipMap) {
+ mHasHardwareMipMap = hasMipMap;
+}
+
+void* PixelRef::getStorage() const {
+ switch (mPixelStorageType) {
+ case PixelStorageType::External:
+ return mPixelStorage.external.address;
+ case PixelStorageType::Ashmem:
+ return mPixelStorage.ashmem.address;
+ case PixelStorageType::Heap:
+ return mPixelStorage.heap.address;
+ }
+}
+
+bool PixelRef::onNewLockPixels(LockRec* rec) {
+ rec->fPixels = getStorage();
+ rec->fRowBytes = mRowBytes;
+ rec->fColorTable = mColorTable.get();
+ return true;
+}
+
+size_t PixelRef::getAllocatedSizeInBytes() const {
+ return info().getSafeSize(mRowBytes);
+}
+
+int PixelRef::getAshmemFd() const {
+ switch (mPixelStorageType) {
+ case PixelStorageType::Ashmem:
+ return mPixelStorage.ashmem.fd;
+ default:
+ return -1;
+ }
+}
+
+size_t PixelRef::getAllocationByteCount() const {
+ switch (mPixelStorageType) {
+ case PixelStorageType::Heap:
+ return mPixelStorage.heap.size;
+ default:
+ return rowBytes() * height();
+ }
+}
+
+void PixelRef::reconfigure(const SkImageInfo& info) {
+ reconfigure(info, info.minRowBytes(), nullptr);
+}
+
+void PixelRef::setAlphaType(SkAlphaType alphaType) {
+ if (!SkColorTypeValidateAlphaType(info().colorType(), alphaType, &alphaType)) {
+ return;
+ }
+
+ changeAlphaType(alphaType);
+}
+
+void PixelRef::getSkBitmap(SkBitmap* outBitmap) {
+ outBitmap->setInfo(info(), rowBytes());
+ outBitmap->setPixelRef(this);
+ outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/hwui/hwui/PixelRef.h b/libs/hwui/hwui/PixelRef.h
new file mode 100644
index 0000000..3f8aea6e
--- /dev/null
+++ b/libs/hwui/hwui/PixelRef.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <SkBitmap.h>
+#include <SkColorTable.h>
+#include <SkImageInfo.h>
+#include <SkPixelRef.h>
+#include <cutils/compiler.h>
+
+namespace android {
+
+enum class PixelStorageType {
+ External,
+ Heap,
+ Ashmem,
+};
+
+typedef void (*FreeFunc)(void* addr, void* context);
+
+class ANDROID_API PixelRef : public SkPixelRef {
+public:
+ PixelRef(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes,
+ SkColorTable* ctable);
+ PixelRef(void* address, void* context, FreeFunc freeFunc,
+ const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
+ PixelRef(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
+ size_t rowBytes, SkColorTable* ctable);
+
+ int width() const { return info().width(); }
+ int height() const { return info().height(); }
+
+ // Can't mark as override since SkPixelRef::rowBytes isn't virtual
+ // but that's OK since we just want Bitmap to be able to rely
+ // on calling rowBytes() on an unlocked pixelref, which it will be
+ // doing on a PixelRef type, not a SkPixelRef, so static
+ // dispatching will do what we want.
+ size_t rowBytes() const { return mRowBytes; }
+ void reconfigure(const SkImageInfo& info, size_t rowBytes, SkColorTable* ctable);
+ void reconfigure(const SkImageInfo& info);
+ void setAlphaType(SkAlphaType alphaType);
+
+ void getSkBitmap(SkBitmap* outBitmap);
+
+ int getAshmemFd() const;
+ size_t getAllocationByteCount() const;
+
+protected:
+ virtual bool onNewLockPixels(LockRec* rec) override;
+ virtual void onUnlockPixels() override { };
+ virtual size_t getAllocatedSizeInBytes() const override;
+private:
+ friend class Bitmap;
+ virtual ~PixelRef();
+ void doFreePixels();
+ void* getStorage() const;
+ void setHasHardwareMipMap(bool hasMipMap);
+ bool hasHardwareMipMap() const;
+
+ PixelStorageType mPixelStorageType;
+
+ size_t mRowBytes = 0;
+ sk_sp<SkColorTable> mColorTable;
+ bool mHasHardwareMipMap = false;
+
+ union {
+ struct {
+ void* address;
+ void* context;
+ FreeFunc freeFunc;
+ } external;
+ struct {
+ void* address;
+ int fd;
+ size_t size;
+ } ashmem;
+ struct {
+ void* address;
+ size_t size;
+ } heap;
+ } mPixelStorage;
+};
+
+} //namespace android
\ No newline at end of file
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp
index 10a26e0..a9bbb27 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.cpp
+++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp
@@ -22,6 +22,7 @@
#include "utils/FatVector.h"
#include "utils/TraceUtils.h"
+#include <utils/Color.h>
#include <utils/Log.h>
#include <GLES2/gl2.h>
@@ -44,7 +45,7 @@
uint32_t height = computeIdealDimension(viewportHeight);
ATRACE_FORMAT("Allocate %ux%u HW Layer", width, height);
caches.textureState().activateTexture(0);
- texture.resize(width, height, GL_RGBA);
+ texture.resize(width, height, caches.rgbaInternalFormat(), GL_RGBA);
texture.blend = true;
texture.setWrap(GL_CLAMP_TO_EDGE);
// not setting filter on texture, since it's set when drawing, based on transform
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index ee4619d..84ab3f3 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -52,7 +52,6 @@
mCaches = &Caches::createInstance(*this);
}
mCaches->init();
- mCaches->textureCache.setAssetAtlas(&mAssetAtlas);
}
static void layerLostGlContext(Layer* layer) {
@@ -64,7 +63,6 @@
// TODO: reset all cached state in state objects
std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext);
- mAssetAtlas.terminate();
mCaches->terminate();
@@ -147,9 +145,17 @@
meshState().resetVertexPointers();
meshState().disableTexCoordsVertexArray();
debugOverdraw(false, false);
+ // TODO: We need a way to know whether the functor is sRGB aware (b/32072673)
+ if (mCaches->extensions().hasSRGBWriteControl()) {
+ glDisable(GL_FRAMEBUFFER_SRGB_EXT);
+ }
}
void RenderState::resumeFromFunctorInvoke() {
+ if (mCaches->extensions().hasSRGBWriteControl()) {
+ glEnable(GL_FRAMEBUFFER_SRGB_EXT);
+ }
+
glViewport(0, 0, mViewportWidth, mViewportHeight);
glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer);
debugOverdraw(false, false);
@@ -308,7 +314,7 @@
glVertexAttribPointer(alphaLocation, 1, GL_FLOAT, GL_FALSE, vertices.stride, alphaCoords);
}
// Shader uniforms
- SkiaShader::apply(*mCaches, fill.skiaShaderData);
+ SkiaShader::apply(*mCaches, fill.skiaShaderData, mViewportWidth, mViewportHeight);
GL_CHECKPOINT(MODERATE);
Texture* texture = (fill.skiaShaderData.skiaShaderType & kBitmap_SkiaShaderType) ?
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index 9e0fb12..3d119dc 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -16,7 +16,6 @@
#ifndef RENDERSTATE_H
#define RENDERSTATE_H
-#include "AssetAtlas.h"
#include "Caches.h"
#include "Glop.h"
#include "renderstate/Blend.h"
@@ -92,7 +91,6 @@
void render(const Glop& glop, const Matrix4& orthoMatrix);
- AssetAtlas& assetAtlas() { return mAssetAtlas; }
Blend& blend() { return *mBlend; }
MeshState& meshState() { return *mMeshState; }
Scissor& scissor() { return *mScissor; }
@@ -120,7 +118,6 @@
OffscreenBufferPool mLayerPool;
- AssetAtlas mAssetAtlas;
std::set<Layer*> mActiveLayers;
std::set<renderthread::CanvasContext*> mRegisteredContexts;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 43471e5..fe0f56a 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -85,6 +85,18 @@
return nullptr;
}
+void CanvasContext::destroyLayer(RenderNode* node) {
+ auto renderType = Properties::getRenderPipelineType();
+ switch (renderType) {
+ case RenderPipelineType::OpenGL:
+ OpenGLPipeline::destroyLayer(node);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ break;
+ }
+}
+
CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
RenderNode* rootRenderNode, IContextFactory* contextFactory,
std::unique_ptr<IRenderPipeline> renderPipeline)
@@ -533,11 +545,6 @@
return mRenderPipeline->createTextureLayer();
}
-void CanvasContext::setTextureAtlas(RenderThread& thread,
- const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize) {
- thread.eglManager().setTextureAtlas(buffer, map, mapSize);
-}
-
void CanvasContext::dumpFrames(int fd) {
FILE* file = fdopen(fd, "a");
fprintf(file, "\n\n---PROFILEDATA---\n");
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 7ebe0ae..559ac87 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -68,6 +68,29 @@
RenderNode* rootRenderNode, IContextFactory* contextFactory);
virtual ~CanvasContext();
+ /**
+ * Update or create a layer specific for the provided RenderNode. The layer
+ * attached to the node will be specific to the RenderPipeline used by this
+ * context
+ *
+ * @return true if the layer has been created or updated
+ */
+ bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& dmgAccumulator) {
+ return mRenderPipeline->createOrUpdateLayer(node, dmgAccumulator);
+ }
+
+ /**
+ * Destroy any layers that have been attached to the provided RenderNode removing
+ * any state that may have been set during createOrUpdateLayer().
+ */
+ static void destroyLayer(RenderNode* node);
+
+ /*
+ * If Properties::isSkiaEnabled() is true then this will return the Skia
+ * grContext associated with the current RenderPipeline.
+ */
+ GrContext* getGrContext() const { return mRenderPipeline->getGrContext(); }
+
// Won't take effect until next EGLSurface creation
void setSwapBehavior(SwapBehavior swapBehavior);
@@ -102,9 +125,6 @@
DeferredLayerUpdater* createTextureLayer();
- ANDROID_API static void setTextureAtlas(RenderThread& thread,
- const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
-
void stopDrawing();
void notifyFramePending();
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 86731c9..beda045 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -91,9 +91,7 @@
, mEglConfig(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
- , mCurrentSurface(EGL_NO_SURFACE)
- , mAtlasMap(nullptr)
- , mAtlasMapSize(0) {
+ , mCurrentSurface(EGL_NO_SURFACE) {
}
void EglManager::initialize() {
@@ -128,7 +126,6 @@
makeCurrent(mPBufferSurface);
DeviceInfo::initialize();
mRenderThread.renderState().onGLContextCreated();
- initAtlas();
}
void EglManager::initExtensions() {
@@ -191,32 +188,6 @@
"Failed to create context, error = %s", egl_error_str());
}
-void EglManager::setTextureAtlas(const sp<GraphicBuffer>& buffer,
- int64_t* map, size_t mapSize) {
-
- // Already initialized
- if (mAtlasBuffer.get()) {
- ALOGW("Multiple calls to setTextureAtlas!");
- delete map;
- return;
- }
-
- mAtlasBuffer = buffer;
- mAtlasMap = map;
- mAtlasMapSize = mapSize;
-
- if (hasEglContext()) {
- initAtlas();
- }
-}
-
-void EglManager::initAtlas() {
- if (mAtlasBuffer.get()) {
- mRenderThread.renderState().assetAtlas().init(mAtlasBuffer,
- mAtlasMap, mAtlasMapSize);
- }
-}
-
void EglManager::createPBufferSurface() {
LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
"usePBufferSurface() called on uninitialized GlobalContext!");
@@ -229,7 +200,16 @@
EGLSurface EglManager::createSurface(EGLNativeWindowType window) {
initialize();
- EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, nullptr);
+
+ EGLint attribs[] = {
+#ifdef ANDROID_ENABLE_LINEAR_BLENDING
+ EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR,
+ EGL_COLORSPACE, EGL_COLORSPACE_sRGB,
+#endif
+ EGL_NONE
+ };
+
+ EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, attribs);
LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
"Failed to create EGLSurface for window %p, eglErr = %s",
(void*) window, egl_error_str());
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 41047fe..ba4a3e1 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -79,8 +79,6 @@
// Returns true iff the surface is now preserving buffers.
bool setPreserveBuffer(EGLSurface surface, bool preserve);
- void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize);
-
void fence();
private:
@@ -94,7 +92,6 @@
void createPBufferSurface();
void loadConfig();
void createContext();
- void initAtlas();
EGLint queryBufferAge(EGLSurface surface);
RenderThread& mRenderThread;
@@ -106,10 +103,6 @@
EGLSurface mCurrentSurface;
- sp<GraphicBuffer> mAtlasBuffer;
- int64_t* mAtlasMap;
- size_t mAtlasMapSize;
-
enum class SwapBehavior {
Discard,
Preserved,
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index 3250fed..f96c2fd 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -22,6 +22,8 @@
#include <SkRect.h>
#include <utils/RefBase.h>
+class GrContext;
+
namespace android {
class Surface;
@@ -43,6 +45,8 @@
Succeeded
};
+class Frame;
+
class IRenderPipeline {
public:
virtual MakeCurrentResult makeCurrent() = 0;
@@ -67,6 +71,9 @@
LayerUpdateQueue* layerUpdateQueue, bool opaque,
const BakedOpRenderer::LightInfo& lightInfo) = 0;
virtual TaskManager* getTaskManager() = 0;
+ virtual bool createOrUpdateLayer(RenderNode* node,
+ const DamageAccumulator& damageAccumulator) = 0;
+ virtual GrContext* getGrContext() = 0;
virtual ~IRenderPipeline() {}
};
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index c8971f8..c758f6c 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -183,6 +183,46 @@
return &Caches::getInstance().tasks;
}
+static bool layerMatchesWH(OffscreenBuffer* layer, int width, int height) {
+ return layer->viewportWidth == (uint32_t)width && layer->viewportHeight == (uint32_t)height;
+}
+
+bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node,
+ const DamageAccumulator& damageAccumulator) {
+ RenderState& renderState = mRenderThread.renderState();
+ OffscreenBufferPool& layerPool = renderState.layerPool();
+ bool transformUpdateNeeded = false;
+ if (node->getLayer() == nullptr) {
+ node->setLayer(layerPool.get(renderState, node->getWidth(), node->getHeight()));
+ transformUpdateNeeded = true;
+ } else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) {
+ // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
+ // Or, ideally, maintain damage between frames on node/layer so ordering is always correct
+ if (node->properties().fitsOnLayer()) {
+ node->setLayer(layerPool.resize(node->getLayer(), node->getWidth(), node->getHeight()));
+ } else {
+ destroyLayer(node);
+ }
+ transformUpdateNeeded = true;
+ }
+
+ if (transformUpdateNeeded && node->getLayer()) {
+ // update the transform in window of the layer to reset its origin wrt light source position
+ Matrix4 windowTransform;
+ damageAccumulator.computeCurrentTransform(&windowTransform);
+ node->getLayer()->setWindowTransform(windowTransform);
+ }
+
+ return transformUpdateNeeded;
+}
+
+void OpenGLPipeline::destroyLayer(RenderNode* node) {
+ if (OffscreenBuffer* layer = node->getLayer()) {
+ layer->renderState.layerPool().putOrDelete(layer);
+ node->setLayer(nullptr);
+ }
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
index e08fd9b..d024aec 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -26,9 +26,6 @@
namespace uirenderer {
namespace renderthread {
-class Frame;
-
-
class OpenGLPipeline : public IRenderPipeline {
public:
OpenGLPipeline(RenderThread& thread);
@@ -56,6 +53,10 @@
LayerUpdateQueue* layerUpdateQueue, bool opaque,
const BakedOpRenderer::LightInfo& lightInfo) override;
TaskManager* getTaskManager() override;
+ bool createOrUpdateLayer(RenderNode* node,
+ const DamageAccumulator& damageAccumulator) override;
+ static void destroyLayer(RenderNode* node);
+ GrContext* getGrContext() override { return nullptr; }
private:
EglManager& mEglManager;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index dcbc980..c2ed864 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -480,23 +480,6 @@
staticPostAndWait(task);
}
-CREATE_BRIDGE4(setTextureAtlas, RenderThread* thread, GraphicBuffer* buffer, int64_t* map,
- size_t size) {
- CanvasContext::setTextureAtlas(*args->thread, args->buffer, args->map, args->size);
- args->buffer->decStrong(nullptr);
- return nullptr;
-}
-
-void RenderProxy::setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size) {
- SETUP_TASK(setTextureAtlas);
- args->thread = &mRenderThread;
- args->buffer = buffer.get();
- args->buffer->incStrong(nullptr);
- args->map = map;
- args->size = size;
- post(task);
-}
-
CREATE_BRIDGE2(setProcessStatsBuffer, RenderThread* thread, int fd) {
args->thread->jankTracker().switchStorageToAshmem(args->fd);
close(args->fd);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index d4aaea6..50a6f64 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -112,7 +112,6 @@
uint32_t frameTimePercentile(int p);
ANDROID_API static void dumpGraphicsMemory(int fd);
- ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size);
ANDROID_API void setProcessStatsBuffer(int fd);
ANDROID_API int getRenderThreadTid();
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 78e9bc4..51c0a05 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -124,8 +124,9 @@
static SkBitmap createSkBitmap(int width, int height,
SkColorType colorType = kN32_SkColorType) {
SkBitmap bitmap;
+ sk_sp<SkColorSpace> colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
SkImageInfo info = SkImageInfo::Make(width, height,
- colorType, kPremul_SkAlphaType);
+ colorType, kPremul_SkAlphaType, colorSpace);
bitmap.setInfo(info);
bitmap.allocPixels(info);
return bitmap;
diff --git a/libs/hwui/tests/scripts/prep_ryu.sh b/libs/hwui/tests/scripts/prep_ryu.sh
new file mode 100644
index 0000000..7c6c0df
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_ryu.sh
@@ -0,0 +1,31 @@
+adb root
+adb wait-for-device
+adb shell stop thermal-engine
+adb shell stop perfd
+
+# 51000 102000 204000 306000 408000 510000 612000 714000 816000 918000
+# 1020000 1122000 1224000 1326000 1428000 1530000 1632000 1734000 1836000 1912500
+S=1326000
+echo "set cpu to $S hz";
+adb shell "echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"
+adb shell "echo $S > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq"
+
+#01: core 76 MHz emc 408 MHz
+#02: core 153 MHz emc 665 MHz
+#03: core 230 MHz emc 800 MHz *
+#04: core 307 MHz emc 1065 MHz
+#05: core 384 MHz emc 1331 MHz
+#06: core 460 MHz emc 1600 MHz
+#07: core 537 MHz emc 1600 MHz
+#08: core 614 MHz emc 1600 MHz
+#09: core 691 MHz emc 1600 MHz
+#0a: core 768 MHz emc 1600 MHz
+#0b: core 844 MHz emc 1600 MHz
+#0c: core 921 MHz emc 1600 MHz
+#0d: core 998 MHz emc 1600 MHz
+#AC: core 230 MHz emc 800 MHz a A d D
+
+echo "set gpu to core 307 MHz emc 1065 MHz"
+# it will lock gpu until you touch a screen
+adb shell "echo 04 > /sys/devices/57000000.gpu/pstate"
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index 0d90afa..39c7f32 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -160,7 +160,7 @@
// Check that the VD is in the dislay list, and the layer update queue contains the correct
// damage rect.
- EXPECT_FALSE(rootNode->getDisplayList()->getVectorDrawables().empty());
+ EXPECT_TRUE(rootNode->getDisplayList()->hasVectorDrawables());
EXPECT_FALSE(info.layerUpdateQueue->entries().empty());
EXPECT_EQ(rootNode.get(), info.layerUpdateQueue->entries().at(0).renderNode);
EXPECT_EQ(uirenderer::Rect(0, 0, 200, 400), info.layerUpdateQueue->entries().at(0).damage);
diff --git a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index a30ada0..5cab04d 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -18,6 +18,7 @@
#include <gtest/gtest.h>
#include <SkColorMatrixFilter.h>
+#include <SkColorSpace.h>
#include <SkImagePriv.h>
#include <SkShader.h>
@@ -82,3 +83,9 @@
paint.setXfermodeMode(SkXfermode::kOverlay_Mode);
ASSERT_EQ(expected, paint.getXfermode());
}
+
+TEST(SkiaBehavior, srgbColorSpaceIsSingleton) {
+ sk_sp<SkColorSpace> sRGB1 = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+ sk_sp<SkColorSpace> sRGB2 = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
+ ASSERT_EQ(sRGB1.get(), sRGB2.get());
+}
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
new file mode 100644
index 0000000..7f622eb
--- /dev/null
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <VectorDrawable.h>
+
+#include "AnimationContext.h"
+#include "DamageAccumulator.h"
+#include "IContextFactory.h"
+#include "SkiaDisplayList.h"
+#include "renderthread/CanvasContext.h"
+#include "tests/common/TestUtils.h"
+
+
+using namespace android;
+using namespace android::uirenderer;
+using namespace android::uirenderer::renderthread;
+
+TEST(SkiaDisplayList, create) {
+ SkRect bounds = SkRect::MakeWH(200, 200);
+ SkiaDisplayList skiaDL(bounds);
+ ASSERT_TRUE(skiaDL.isEmpty());
+ ASSERT_FALSE(skiaDL.mIsProjectionReceiver);
+ ASSERT_EQ(skiaDL.mDrawable->getBounds(), bounds);
+}
+
+TEST(SkiaDisplayList, reset) {
+ SkRect bounds = SkRect::MakeWH(200, 200);
+ SkiaDisplayList skiaDL(bounds);
+
+ SkCanvas dummyCanvas;
+ skiaDL.mChildNodes.emplace_back(nullptr, &dummyCanvas);
+ skiaDL.mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas);
+ skiaDL.mMutableImages.push_back(nullptr);
+ skiaDL.mVectorDrawables.push_back(nullptr);
+ skiaDL.mDrawable->drawAnnotation(bounds, "testAnnotation", nullptr);
+ skiaDL.mIsProjectionReceiver = true;
+
+ ASSERT_EQ(skiaDL.mDrawable->getBounds(), bounds);
+ ASSERT_FALSE(skiaDL.mChildNodes.empty());
+ ASSERT_FALSE(skiaDL.mChildFunctors.empty());
+ ASSERT_FALSE(skiaDL.mMutableImages.empty());
+ ASSERT_FALSE(skiaDL.mVectorDrawables.empty());
+ ASSERT_FALSE(skiaDL.isEmpty());
+ ASSERT_TRUE(skiaDL.mIsProjectionReceiver);
+
+ bounds = SkRect::MakeWH(100, 100);
+ skiaDL.reset(nullptr, bounds);
+
+ ASSERT_EQ(skiaDL.mDrawable->getBounds(), bounds);
+ ASSERT_TRUE(skiaDL.mChildNodes.empty());
+ ASSERT_TRUE(skiaDL.mChildFunctors.empty());
+ ASSERT_TRUE(skiaDL.mMutableImages.empty());
+ ASSERT_TRUE(skiaDL.mVectorDrawables.empty());
+ ASSERT_TRUE(skiaDL.isEmpty());
+ ASSERT_FALSE(skiaDL.mIsProjectionReceiver);
+}
+
+TEST(SkiaDisplayList, reuseDisplayList) {
+ sp<RenderNode> renderNode = new RenderNode();
+ std::unique_ptr<SkiaDisplayList> availableList;
+
+ // no list has been attached so it should return a nullptr
+ availableList = renderNode->detachAvailableList();
+ ASSERT_EQ(availableList.get(), nullptr);
+
+ // attach a displayList for reuse
+ SkiaDisplayList skiaDL(SkRect::MakeWH(200, 200));
+ ASSERT_TRUE(skiaDL.reuseDisplayList(renderNode.get(), nullptr));
+
+ // detach the list that you just attempted to reuse
+ availableList = renderNode->detachAvailableList();
+ ASSERT_EQ(availableList.get(), &skiaDL);
+ availableList.release(); // prevents an invalid free since our DL is stack allocated
+
+ // after detaching there should return no available list
+ availableList = renderNode->detachAvailableList();
+ ASSERT_EQ(availableList.get(), nullptr);
+}
+
+class TestFunctor : public Functor {
+public:
+ bool didSync = false;
+
+ virtual status_t operator ()(int what, void* data) {
+ if (what == DrawGlInfo::kModeSync) { didSync = true; }
+ return DrawGlInfo::kStatusDone;
+ }
+};
+
+TEST(SkiaDisplayList, syncContexts) {
+ SkRect bounds = SkRect::MakeWH(200, 200);
+ SkiaDisplayList skiaDL(bounds);
+
+ SkCanvas dummyCanvas;
+ TestFunctor functor;
+ skiaDL.mChildFunctors.emplace_back(&functor, nullptr, &dummyCanvas);
+
+ VectorDrawableRoot vectorDrawable(new VectorDrawable::Group());
+ vectorDrawable.mutateStagingProperties()->setBounds(bounds);
+ skiaDL.mVectorDrawables.push_back(&vectorDrawable);
+
+ // ensure that the functor and vectorDrawable are properly synced
+ skiaDL.syncContents();
+
+ ASSERT_TRUE(functor.didSync);
+ ASSERT_EQ(vectorDrawable.mutateProperties()->getBounds(), bounds);
+}
+
+class ContextFactory : public IContextFactory {
+public:
+ virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
+ return new AnimationContext(clock);
+ }
+};
+
+RENDERTHREAD_TEST(SkiaDisplayList, prepareListAndChildren) {
+ auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
+ ContextFactory contextFactory;
+ std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
+ renderThread, false, rootNode.get(), &contextFactory));
+ TreeInfo info(TreeInfo::MODE_FULL, *canvasContext.get());
+ DamageAccumulator damageAccumulator;
+ info.damageAccumulator = &damageAccumulator;
+ info.observer = nullptr;
+
+ SkiaDisplayList skiaDL(SkRect::MakeWH(200, 200));
+
+ // prepare with a clean VD
+ VectorDrawableRoot cleanVD(new VectorDrawable::Group());
+ skiaDL.mVectorDrawables.push_back(&cleanVD);
+ cleanVD.getBitmapUpdateIfDirty(); // this clears the dirty bit
+
+ ASSERT_FALSE(cleanVD.isDirty());
+ ASSERT_FALSE(cleanVD.getPropertyChangeWillBeConsumed());
+ ASSERT_FALSE(skiaDL.prepareListAndChildren(info, false, [](RenderNode*, TreeInfo&, bool) {}));
+ ASSERT_TRUE(cleanVD.getPropertyChangeWillBeConsumed());
+
+ // prepare again this time adding a dirty VD
+ VectorDrawableRoot dirtyVD(new VectorDrawable::Group());
+ skiaDL.mVectorDrawables.push_back(&dirtyVD);
+
+ ASSERT_TRUE(dirtyVD.isDirty());
+ ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed());
+ ASSERT_TRUE(skiaDL.prepareListAndChildren(info, false, [](RenderNode*, TreeInfo&, bool) {}));
+ ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed());
+
+ // prepare again this time adding a RenderNode and a callback
+ sp<RenderNode> renderNode = new RenderNode();
+ TreeInfo* infoPtr = &info;
+ SkCanvas dummyCanvas;
+ skiaDL.mChildNodes.emplace_back(renderNode.get(), &dummyCanvas);
+ bool hasRun = false;
+ ASSERT_TRUE(skiaDL.prepareListAndChildren(info, false,
+ [&hasRun, renderNode, infoPtr](RenderNode* n, TreeInfo& i, bool r) {
+ hasRun = true;
+ ASSERT_EQ(renderNode.get(), n);
+ ASSERT_EQ(infoPtr, &i);
+ ASSERT_FALSE(r);
+ }));
+ ASSERT_TRUE(hasRun);
+
+ canvasContext->destroy(nullptr);
+}
+
+TEST(SkiaDisplayList, updateChildren) {
+ SkRect bounds = SkRect::MakeWH(200, 200);
+ SkiaDisplayList skiaDL(bounds);
+
+ sp<RenderNode> renderNode = new RenderNode();
+ SkCanvas dummyCanvas;
+ skiaDL.mChildNodes.emplace_back(renderNode.get(), &dummyCanvas);
+ skiaDL.updateChildren([renderNode](RenderNode* n) {
+ ASSERT_EQ(renderNode.get(), n);
+ });
+}
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 83b485f..8e0d3ee 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -426,5 +426,49 @@
EXPECT_EQ(1.0f, properties->getPivotY());
}
+
+static SkShader* createShader(bool* isDestroyed) {
+ class TestShader : public SkShader {
+ public:
+ TestShader(bool* isDestroyed) : SkShader(), mDestroyed(isDestroyed) {
+ }
+ ~TestShader() {
+ *mDestroyed = true;
+ }
+
+ Factory getFactory() const override { return nullptr; }
+ private:
+ bool* mDestroyed;
+ };
+ return new TestShader(isDestroyed);
+}
+
+TEST(VectorDrawable, drawPathWithoutIncrementingShaderRefCount) {
+ VectorDrawable::FullPath path("m1 1", 4);
+ SkBitmap bitmap;
+ SkImageInfo info = SkImageInfo::Make(5, 5, kN32_SkColorType, kPremul_SkAlphaType);
+ bitmap.setInfo(info);
+ bitmap.allocPixels(info);
+ SkCanvas canvas(bitmap);
+
+ bool shaderIsDestroyed = false;
+
+ // Initial ref count is 1
+ SkShader* shader = createShader(&shaderIsDestroyed);
+
+ // Setting the fill gradient increments the ref count of the shader by 1
+ path.mutateStagingProperties()->setFillGradient(shader);
+ path.draw(&canvas, SkMatrix::I(), 1.0f, 1.0f, true);
+ // Resetting the fill gradient decrements the ref count of the shader by 1
+ path.mutateStagingProperties()->setFillGradient(nullptr);
+
+ // Expect ref count to be 1 again, i.e. nothing else to have a ref to the shader now. Unref()
+ // again should bring the ref count to zero and consequently trigger detor.
+ shader->unref();
+
+ // Verify that detor is called.
+ EXPECT_TRUE(shaderIsDestroyed);
+}
+
}; // namespace uirenderer
}; // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index b5157f4..f9cc46d 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -16,6 +16,8 @@
#ifndef COLOR_H
#define COLOR_H
+#include <math.h>
+
#include <SkColor.h>
namespace android {
@@ -80,6 +82,42 @@
};
static constexpr int BrightColorsCount = sizeof(BrightColors) / sizeof(Color::Color);
+ // Opto-electronic conversion function for the sRGB color space
+ // Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
+ static constexpr float OECF_sRGB(float linear) {
+ // IEC 61966-2-1:1999
+ return linear <= 0.0031308f ?
+ linear * 12.92f : (powf(linear, 1.0f / 2.4f) * 1.055f) - 0.055f;
+ }
+
+ // Opto-electronic conversion function for the sRGB color space
+ // Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
+ // This function returns the input unmodified if linear blending is not enabled
+ static constexpr float OECF(float linear) {
+#ifdef ANDROID_ENABLE_LINEAR_BLENDING
+ return OECF_sRGB(linear);
+#else
+ return linear;
+#endif
+ }
+
+ // Electro-optical conversion function for the sRGB color space
+ // Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
+ static constexpr float EOCF_sRGB(float srgb) {
+ // IEC 61966-2-1:1999
+ return srgb <= 0.04045f ? srgb / 12.92f : powf((srgb + 0.055f) / 1.055f, 2.4f);
+ }
+
+ // Electro-optical conversion function for the sRGB color space
+ // Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
+ // This function returns the input unmodified if linear blending is not enabled
+ static constexpr float EOCF(float srgb) {
+#ifdef ANDROID_ENABLE_LINEAR_BLENDING
+ return EOCF_sRGB(srgb);
+#else
+ return srgb;
+#endif
+ }
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
index b879f78..624d207 100644
--- a/libs/hwui/utils/TestWindowContext.cpp
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -110,9 +110,10 @@
}
bool capturePixels(SkBitmap* bmp) {
+ sk_sp<SkColorSpace> colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
SkImageInfo destinationConfig =
SkImageInfo::Make(mSize.width(), mSize.height(),
- kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType, colorSpace);
bmp->allocPixels(destinationConfig);
android_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
mSize.width() * mSize.height() * 4);
diff --git a/media/java/android/media/AmrInputStream.java b/media/java/android/media/AmrInputStream.java
index f90f1e2..fb91bbb 100644
--- a/media/java/android/media/AmrInputStream.java
+++ b/media/java/android/media/AmrInputStream.java
@@ -18,45 +18,69 @@
import java.io.InputStream;
import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import android.media.MediaCodec.BufferInfo;
+import android.util.Log;
/**
* AmrInputStream
* @hide
*/
-public final class AmrInputStream extends InputStream
-{
- static {
- System.loadLibrary("media_jni");
- }
-
+public final class AmrInputStream extends InputStream {
private final static String TAG = "AmrInputStream";
// frame is 20 msec at 8.000 khz
private final static int SAMPLES_PER_FRAME = 8000 * 20 / 1000;
-
+
+ MediaCodec mCodec;
+ BufferInfo mInfo;
+ boolean mSawOutputEOS;
+ boolean mSawInputEOS;
+
// pcm input stream
private InputStream mInputStream;
-
- // native handle
- private long mGae;
-
+
// result amr stream
private final byte[] mBuf = new byte[SAMPLES_PER_FRAME * 2];
private int mBufIn = 0;
private int mBufOut = 0;
-
+
// helper for bytewise read()
private byte[] mOneByte = new byte[1];
-
+
/**
* Create a new AmrInputStream, which converts 16 bit PCM to AMR
* @param inputStream InputStream containing 16 bit PCM.
*/
public AmrInputStream(InputStream inputStream) {
mInputStream = inputStream;
- mGae = GsmAmrEncoderNew();
- GsmAmrEncoderInitialize(mGae);
+
+ MediaFormat format = new MediaFormat();
+ format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AMR_NB);
+ format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 8000);
+ format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, 12200);
+
+ MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+ String name = mcl.findEncoderForFormat(format);
+ if (name != null) {
+ try {
+ mCodec = MediaCodec.createByCodecName(name);
+ mCodec.configure(format,
+ null /* surface */,
+ null /* crypto */,
+ MediaCodec.CONFIGURE_FLAG_ENCODE);
+ mCodec.start();
+ } catch (IOException e) {
+ if (mCodec != null) {
+ mCodec.release();
+ }
+ mCodec = null;
+ }
+ }
+ mInfo = new BufferInfo();
}
@Override
@@ -64,7 +88,7 @@
int rtn = read(mOneByte, 0, 1);
return rtn == 1 ? (0xff & mOneByte[0]) : -1;
}
-
+
@Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
@@ -72,67 +96,100 @@
@Override
public int read(byte[] b, int offset, int length) throws IOException {
- if (mGae == 0) throw new IllegalStateException("not open");
-
- // local buffer of amr encoded audio empty
- if (mBufOut >= mBufIn) {
- // reset the buffer
+ if (mCodec == null) {
+ throw new IllegalStateException("not open");
+ }
+
+ if (mBufOut >= mBufIn && !mSawOutputEOS) {
+ // no data left in buffer, refill it
mBufOut = 0;
mBufIn = 0;
-
- // fetch a 20 msec frame of pcm
- for (int i = 0; i < SAMPLES_PER_FRAME * 2; ) {
- int n = mInputStream.read(mBuf, i, SAMPLES_PER_FRAME * 2 - i);
- if (n == -1) return -1;
- i += n;
+
+ // first push as much data into the encoder as possible
+ while (!mSawInputEOS) {
+ int index = mCodec.dequeueInputBuffer(0);
+ if (index < 0) {
+ // no input buffer currently available
+ break;
+ } else {
+ int numRead;
+ for (numRead = 0; numRead < SAMPLES_PER_FRAME * 2; ) {
+ int n = mInputStream.read(mBuf, numRead, SAMPLES_PER_FRAME * 2 - numRead);
+ if (n == -1) {
+ mSawInputEOS = true;
+ break;
+ }
+ numRead += n;
+ }
+ ByteBuffer buf = mCodec.getInputBuffer(index);
+ buf.put(mBuf, 0, numRead);
+ mCodec.queueInputBuffer(index,
+ 0 /* offset */,
+ numRead,
+ 0 /* presentationTimeUs */,
+ mSawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0 /* flags */);
+ }
}
-
- // encode it
- mBufIn = GsmAmrEncoderEncode(mGae, mBuf, 0, mBuf, 0);
+
+ // now read encoded data from the encoder (blocking, since we just filled up the
+ // encoder's input with data it should be able to output at least one buffer)
+ while (true) {
+ int index = mCodec.dequeueOutputBuffer(mInfo, -1);
+ if (index >= 0) {
+ mBufIn = mInfo.size;
+ ByteBuffer out = mCodec.getOutputBuffer(index);
+ out.get(mBuf, 0 /* offset */, mBufIn /* length */);
+ mCodec.releaseOutputBuffer(index, false /* render */);
+ if ((mInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
+ mSawOutputEOS = true;
+ }
+ break;
+ }
+ }
}
-
- // return encoded audio to user
- if (length > mBufIn - mBufOut) length = mBufIn - mBufOut;
- System.arraycopy(mBuf, mBufOut, b, offset, length);
- mBufOut += length;
-
- return length;
+
+ if (mBufOut < mBufIn) {
+ // there is data in the buffer
+ if (length > mBufIn - mBufOut) {
+ length = mBufIn - mBufOut;
+ }
+ System.arraycopy(mBuf, mBufOut, b, offset, length);
+ mBufOut += length;
+ return length;
+ }
+
+ if (mSawInputEOS && mSawOutputEOS) {
+ // no more data available in buffer, codec or input stream
+ return -1;
+ }
+
+ // caller should try again
+ return 0;
}
@Override
public void close() throws IOException {
try {
- if (mInputStream != null) mInputStream.close();
+ if (mInputStream != null) {
+ mInputStream.close();
+ }
} finally {
mInputStream = null;
try {
- if (mGae != 0) GsmAmrEncoderCleanup(mGae);
- } finally {
- try {
- if (mGae != 0) GsmAmrEncoderDelete(mGae);
- } finally {
- mGae = 0;
+ if (mCodec != null) {
+ mCodec.release();
}
+ } finally {
+ mCodec = null;
}
}
}
@Override
protected void finalize() throws Throwable {
- if (mGae != 0) {
- close();
- throw new IllegalStateException("someone forgot to close AmrInputStream");
+ if (mCodec != null) {
+ Log.w(TAG, "AmrInputStream wasn't closed");
+ mCodec.release();
}
}
-
- //
- // AudioRecord JNI interface
- //
- private static native long GsmAmrEncoderNew();
- private static native void GsmAmrEncoderInitialize(long gae);
- private static native int GsmAmrEncoderEncode(long gae,
- byte[] pcm, int pcmOffset, byte[] amr, int amrOffset) throws IOException;
- private static native void GsmAmrEncoderCleanup(long gae);
- private static native void GsmAmrEncoderDelete(long gae);
-
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 33c1c3f..f24bf09 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -312,29 +312,32 @@
*/
public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
- /** The audio stream for phone calls */
+ /** Used to identify the volume of audio streams for phone calls */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
- /** The audio stream for system sounds */
+ /** Used to identify the volume of audio streams for system sounds */
public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
- /** The audio stream for the phone ring */
+ /** Used to identify the volume of audio streams for the phone ring */
public static final int STREAM_RING = AudioSystem.STREAM_RING;
- /** The audio stream for music playback */
+ /** Used to identify the volume of audio streams for music playback */
public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
- /** The audio stream for alarms */
+ /** Used to identify the volume of audio streams for alarms */
public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
- /** The audio stream for notifications */
+ /** Used to identify the volume of audio streams for notifications */
public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
- /** @hide The audio stream for phone calls when connected to bluetooth */
+ /** @hide Used to identify the volume of audio streams for phone calls when connected
+ * to bluetooth */
public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
- /** @hide The audio stream for enforced system sounds in certain countries (e.g camera in Japan) */
+ /** @hide Used to identify the volume of audio streams for enforced system sounds
+ * in certain countries (e.g camera in Japan) */
public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
- /** The audio stream for DTMF Tones */
+ /** Used to identify the volume of audio streams for DTMF Tones */
public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
- /** @hide The audio stream for text to speech (TTS) */
+ /** @hide Used to identify the volume of audio streams exclusively transmitted through the
+ * speaker (TTS) of the device */
public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
/** Number of audio streams */
/**
- * @deprecated Use AudioSystem.getNumStreamTypes() instead
+ * @deprecated Do not iterate on volume stream type values.
*/
@Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index f9bc95c..384be5c 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -39,27 +39,29 @@
* If these are modified, please also update Settings.System.VOLUME_SETTINGS
* and attrs.xml and AudioManager.java.
*/
- /* The default audio stream */
+ /** Used to identify the default audio stream volume */
public static final int STREAM_DEFAULT = -1;
- /* The audio stream for phone calls */
+ /** Used to identify the volume of audio streams for phone calls */
public static final int STREAM_VOICE_CALL = 0;
- /* The audio stream for system sounds */
+ /** Used to identify the volume of audio streams for system sounds */
public static final int STREAM_SYSTEM = 1;
- /* The audio stream for the phone ring and message alerts */
+ /** Used to identify the volume of audio streams for the phone ring and message alerts */
public static final int STREAM_RING = 2;
- /* The audio stream for music playback */
+ /** Used to identify the volume of audio streams for music playback */
public static final int STREAM_MUSIC = 3;
- /* The audio stream for alarms */
+ /** Used to identify the volume of audio streams for alarms */
public static final int STREAM_ALARM = 4;
- /* The audio stream for notifications */
+ /** Used to identify the volume of audio streams for notifications */
public static final int STREAM_NOTIFICATION = 5;
- /* @hide The audio stream for phone calls when connected on bluetooth */
+ /** Used to identify the volume of audio streams for phone calls when connected on bluetooth */
public static final int STREAM_BLUETOOTH_SCO = 6;
- /* @hide The audio stream for enforced system sounds in certain countries (e.g camera in Japan) */
+ /** Used to identify the volume of audio streams for enforced system sounds in certain
+ * countries (e.g camera in Japan) */
public static final int STREAM_SYSTEM_ENFORCED = 7;
- /* @hide The audio stream for DTMF tones */
+ /** Used to identify the volume of audio streams for DTMF tones */
public static final int STREAM_DTMF = 8;
- /* @hide The audio stream for text to speech (TTS) */
+ /** Used to identify the volume of audio streams exclusively transmitted through the
+ * speaker (TTS) of the device */
public static final int STREAM_TTS = 9;
/**
* @deprecated Use {@link #numStreamTypes() instead}
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 69710d6..d77a082 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -1764,16 +1764,13 @@
* <p>
* This method is only supported for JPEG files.
* </p>
- *
- * @throws UnsupportedOperationException If this method is called with unsupported files.
*/
public void saveAttributes() throws IOException {
if (!mIsSupportedFile || mMimeType != IMAGE_TYPE_JPEG) {
- throw new UnsupportedOperationException(
- "ExifInterface only supports saving attributes on JPEG formats.");
+ throw new IOException("ExifInterface only supports saving attributes on JPEG formats.");
}
if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
- throw new UnsupportedOperationException(
+ throw new IOException(
"ExifInterface does not support saving attributes for the current input.");
}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index abbace1..bd68fec 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -389,8 +389,8 @@
/** @hide Stream over a socket, limited to a single stream */
public static final int OUTPUT_FORMAT_RTP_AVP = 7;
- /** @hide H.264/AAC data encapsulated in MPEG2/TS */
- public static final int OUTPUT_FORMAT_MPEG2TS = 8;
+ /** H.264/AAC data encapsulated in MPEG2/TS */
+ public static final int MPEG_2_TS = 8;
/** VP8/VORBIS data in a WEBM container */
public static final int WEBM = 9;
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 8ae6e6b..754fe45 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -371,6 +371,7 @@
private void destroyLocalPlayer() {
if (mLocalPlayer != null) {
+ mLocalPlayer.setOnCompletionListener(null);
mLocalPlayer.reset();
mLocalPlayer.release();
mLocalPlayer = null;
@@ -467,11 +468,14 @@
}
class MyOnCompletionListener implements MediaPlayer.OnCompletionListener {
- public void onCompletion(MediaPlayer mp)
- {
+ @Override
+ public void onCompletion(MediaPlayer mp) {
synchronized (sActiveRingtones) {
sActiveRingtones.remove(Ringtone.this);
}
+ if (mLocalPlayer != null) {
+ mLocalPlayer.setOnCompletionListener(null);
+ }
}
}
}
diff --git a/media/java/android/media/midi/MidiDeviceInfo.java b/media/java/android/media/midi/MidiDeviceInfo.java
index 66d1ed7..5fd9006 100644
--- a/media/java/android/media/midi/MidiDeviceInfo.java
+++ b/media/java/android/media/midi/MidiDeviceInfo.java
@@ -20,6 +20,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
+
/**
* This class contains information to describe a MIDI device.
* For now we only have information that can be retrieved easily for USB devices,
@@ -352,9 +354,15 @@
private Bundle getBasicProperties(String[] keys) {
Bundle basicProperties = new Bundle();
for (String key : keys) {
- String val = mProperties.getString(key);
+ Object val = mProperties.get(key);
if (val != null) {
- basicProperties.putString(key, val);
+ if (val instanceof String) {
+ basicProperties.putString(key, (String) val);
+ } else if (val instanceof Integer) {
+ basicProperties.putInt(key, (Integer) val);
+ } else {
+ Log.w(TAG, "Unsupported property type: " + val.getClass().getName());
+ }
}
}
return basicProperties;
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index dcd5057..44f7e56 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -2,7 +2,6 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
- android_media_AmrInputStream.cpp \
android_media_ImageWriter.cpp \
android_media_ImageReader.cpp \
android_media_MediaCrypto.cpp \
@@ -44,11 +43,9 @@
libmtp \
libusbhost \
libexif \
- libpiex \
- libstagefright_amrnb_common
+ libpiex
LOCAL_STATIC_LIBRARIES := \
- libstagefright_amrnbenc
LOCAL_C_INCLUDES += \
external/libexif/ \
@@ -58,9 +55,6 @@
frameworks/base/libs/hwui \
frameworks/av/media/libmedia \
frameworks/av/media/libstagefright \
- frameworks/av/media/libstagefright/codecs/amrnb/enc/src \
- frameworks/av/media/libstagefright/codecs/amrnb/common \
- frameworks/av/media/libstagefright/codecs/amrnb/common/include \
frameworks/av/media/mtp \
frameworks/native/include/media/openmax \
$(call include-path-for, libhardware)/hardware \
diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp
deleted file mode 100644
index b56a364..0000000
--- a/media/jni/android_media_AmrInputStream.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
-**
-** Copyright 2007, 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.
-*/
-
-#define LOG_TAG "AmrInputStream"
-#include "utils/Log.h"
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "gsmamr_enc.h"
-
-// ----------------------------------------------------------------------------
-
-using namespace android;
-
-// Corresponds to max bit rate of 12.2 kbps.
-static const int MAX_OUTPUT_BUFFER_SIZE = 32;
-static const int FRAME_DURATION_MS = 20;
-static const int SAMPLING_RATE_HZ = 8000;
-static const int SAMPLES_PER_FRAME = ((SAMPLING_RATE_HZ * FRAME_DURATION_MS) / 1000);
-static const int BYTES_PER_SAMPLE = 2; // Assume 16-bit PCM samples
-static const int BYTES_PER_FRAME = (SAMPLES_PER_FRAME * BYTES_PER_SAMPLE);
-
-struct GsmAmrEncoderState {
- GsmAmrEncoderState()
- : mEncState(NULL),
- mSidState(NULL),
- mLastModeUsed(0) {
- }
-
- ~GsmAmrEncoderState() {}
-
- void* mEncState;
- void* mSidState;
- int32_t mLastModeUsed;
-};
-
-static jlong android_media_AmrInputStream_GsmAmrEncoderNew
- (JNIEnv *env, jclass /* clazz */) {
- GsmAmrEncoderState* gae = new GsmAmrEncoderState();
- if (gae == NULL) {
- jniThrowRuntimeException(env, "Out of memory");
- }
- return (jlong)gae;
-}
-
-static void android_media_AmrInputStream_GsmAmrEncoderInitialize
- (JNIEnv *env, jclass /* clazz */, jlong gae) {
- GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae;
- int32_t nResult = AMREncodeInit(&state->mEncState, &state->mSidState, false);
- if (nResult != OK) {
- jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
- "GsmAmrEncoder initialization failed %d", nResult);
- }
-}
-
-static jint android_media_AmrInputStream_GsmAmrEncoderEncode
- (JNIEnv *env, jclass /* clazz */,
- jlong gae, jbyteArray pcm, jint pcmOffset, jbyteArray amr, jint amrOffset) {
-
- jbyte inBuf[BYTES_PER_FRAME];
- jbyte outBuf[MAX_OUTPUT_BUFFER_SIZE];
-
- env->GetByteArrayRegion(pcm, pcmOffset, sizeof(inBuf), inBuf);
- GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae;
- int32_t length = AMREncode(state->mEncState, state->mSidState,
- (Mode) MR122,
- (int16_t *) inBuf,
- (unsigned char *) outBuf,
- (Frame_Type_3GPP*) &state->mLastModeUsed,
- AMR_TX_WMF);
- if (length < 0) {
- jniThrowExceptionFmt(env, "java/io/IOException",
- "Failed to encode a frame with error code: %d", length);
- return (jint)-1;
- }
-
- // The 1st byte of PV AMR frames are WMF (Wireless Multimedia Forum)
- // bitpacked, i.e.;
- // [P(4) + FT(4)]. Q=1 for good frame, P=padding bit, 0
- // Here we are converting the header to be as specified in Section 5.3 of
- // RFC 3267 (AMR storage format) i.e.
- // [P(1) + FT(4) + Q(1) + P(2)].
- if (length > 0) {
- outBuf[0] = (outBuf[0] << 3) | 0x4;
- }
-
- env->SetByteArrayRegion(amr, amrOffset, length, outBuf);
-
- return (jint)length;
-}
-
-static void android_media_AmrInputStream_GsmAmrEncoderCleanup
- (JNIEnv* /* env */, jclass /* clazz */, jlong gae) {
- GsmAmrEncoderState *state = (GsmAmrEncoderState *) gae;
- AMREncodeExit(&state->mEncState, &state->mSidState);
- state->mEncState = NULL;
- state->mSidState = NULL;
-}
-
-static void android_media_AmrInputStream_GsmAmrEncoderDelete
- (JNIEnv* /* env */, jclass /* clazz */, jlong gae) {
- delete (GsmAmrEncoderState*)gae;
-}
-
-// ----------------------------------------------------------------------------
-
-static const JNINativeMethod gMethods[] = {
- {"GsmAmrEncoderNew", "()J", (void*)android_media_AmrInputStream_GsmAmrEncoderNew},
- {"GsmAmrEncoderInitialize", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize},
- {"GsmAmrEncoderEncode", "(J[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode},
- {"GsmAmrEncoderCleanup", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderCleanup},
- {"GsmAmrEncoderDelete", "(J)V", (void*)android_media_AmrInputStream_GsmAmrEncoderDelete},
-};
-
-
-int register_android_media_AmrInputStream(JNIEnv *env)
-{
- const char* const kClassPathName = "android/media/AmrInputStream";
-
- return AndroidRuntime::registerNativeMethods(env,
- kClassPathName, gMethods, NELEM(gMethods));
-}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 810996e..c2c66fd 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -32,6 +32,7 @@
#include <gui/Surface.h>
#include <media/ICrypto.h>
+#include <media/MediaCodecBuffer.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -407,7 +408,7 @@
status_t JMediaCodec::getBuffers(
JNIEnv *env, bool input, jobjectArray *bufArray) const {
- Vector<sp<ABuffer> > buffers;
+ Vector<sp<MediaCodecBuffer> > buffers;
status_t err =
input
@@ -425,7 +426,7 @@
}
for (size_t i = 0; i < buffers.size(); ++i) {
- const sp<ABuffer> &buffer = buffers.itemAt(i);
+ const sp<MediaCodecBuffer> &buffer = buffers.itemAt(i);
jobject byteBuffer = NULL;
err = createByteBufferFromABuffer(
@@ -446,8 +447,9 @@
}
// static
+template <typename T>
status_t JMediaCodec::createByteBufferFromABuffer(
- JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
+ JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
jobject *buf) const {
// if this is an ABuffer that doesn't actually hold any accessible memory,
// use a null ByteBuffer
@@ -492,7 +494,7 @@
status_t JMediaCodec::getBuffer(
JNIEnv *env, bool input, size_t index, jobject *buf) const {
- sp<ABuffer> buffer;
+ sp<MediaCodecBuffer> buffer;
status_t err =
input
@@ -509,7 +511,7 @@
status_t JMediaCodec::getImage(
JNIEnv *env, bool input, size_t index, jobject *buf) const {
- sp<ABuffer> buffer;
+ sp<MediaCodecBuffer> buffer;
status_t err =
input
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index c0c47ef..5f0d3df 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -31,7 +31,7 @@
struct AMessage;
struct AString;
struct ICrypto;
-struct IGraphicBufferProducer;
+class IGraphicBufferProducer;
struct MediaCodec;
struct PersistentSurface;
class Surface;
@@ -146,8 +146,9 @@
status_t mInitStatus;
+ template <typename T>
status_t createByteBufferFromABuffer(
- JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
+ JNIEnv *env, bool readOnly, bool clearBuffer, const sp<T> &buffer,
jobject *buf) const;
void cacheJavaObjects(JNIEnv *env);
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index ecf733f..c825702 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1105,7 +1105,6 @@
extern int register_android_media_MediaSync(JNIEnv *env);
extern int register_android_media_ResampleInputStream(JNIEnv *env);
extern int register_android_media_MediaProfiles(JNIEnv *env);
-extern int register_android_media_AmrInputStream(JNIEnv *env);
extern int register_android_mtp_MtpDatabase(JNIEnv *env);
extern int register_android_mtp_MtpDevice(JNIEnv *env);
extern int register_android_mtp_MtpServer(JNIEnv *env);
@@ -1151,11 +1150,6 @@
goto bail;
}
- if (register_android_media_AmrInputStream(env) < 0) {
- ALOGE("ERROR: AmrInputStream native registration failed\n");
- goto bail;
- }
-
if (register_android_media_ResampleInputStream(env) < 0) {
ALOGE("ERROR: ResampleInputStream native registration failed\n");
goto bail;
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index a9b7062..401012f 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -352,7 +352,7 @@
effectCallback,
&lpJniStorage->mCallbackData,
(audio_session_t) sessionId,
- 0);
+ AUDIO_IO_HANDLE_NONE);
if (lpAudioEffect == 0) {
ALOGE("Error creating AudioEffect");
goto setup_failure;
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 20575e0..308c665 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -7,8 +7,6 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_JAVA_LANGUAGE_VERSION := 1.8
-
LOCAL_STATIC_JAVA_LIBRARIES := \
mockito-target-minus-junit4 \
android-support-test \
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 33d6b9a..3b575a8 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -41,6 +41,7 @@
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract.Path;
import android.provider.DocumentsProvider;
import android.provider.MediaStore;
import android.provider.Settings;
@@ -48,6 +49,7 @@
import android.util.ArrayMap;
import android.util.DebugUtils;
import android.util.Log;
+import android.util.Pair;
import android.webkit.MimeTypeMap;
import com.android.internal.annotations.GuardedBy;
@@ -183,7 +185,8 @@
root.rootId = rootId;
root.volumeId = volume.id;
root.flags = Root.FLAG_LOCAL_ONLY
- | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD;
+ | Root.FLAG_SUPPORTS_SEARCH
+ | Root.FLAG_SUPPORTS_IS_CHILD;
final DiskInfo disk = volume.getDisk();
if (DEBUG) Log.d(TAG, "Disk for root " + rootId + " is " + disk);
@@ -270,7 +273,6 @@
return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION;
}
-
private String getDocIdForFile(File file) throws FileNotFoundException {
return getDocIdForFileMaybeCreate(file, false);
}
@@ -323,6 +325,11 @@
}
private File getFileForDocId(String docId, boolean visible) throws FileNotFoundException {
+ return resolveDocId(docId, visible).second;
+ }
+
+ private Pair<RootInfo, File> resolveDocId(String docId, boolean visible)
+ throws FileNotFoundException {
final int splitIndex = docId.indexOf(':', 1);
final String tag = docId.substring(0, splitIndex);
final String path = docId.substring(splitIndex + 1);
@@ -346,7 +353,7 @@
if (!target.exists()) {
throw new FileNotFoundException("Missing file for " + docId + " at " + target);
}
- return target;
+ return Pair.create(root, target);
}
private void includeFile(MatrixCursor result, String docId, File file)
@@ -423,6 +430,28 @@
}
@Override
+ public Path findPath(String documentId)
+ throws FileNotFoundException {
+ LinkedList<String> path = new LinkedList<>();
+
+ final Pair<RootInfo, File> resolvedDocId = resolveDocId(documentId, false);
+ RootInfo root = resolvedDocId.first;
+ File file = resolvedDocId.second;
+
+ if (!file.exists()) {
+ throw new FileNotFoundException();
+ }
+
+ while (file != null && file.getAbsolutePath().startsWith(root.path.getAbsolutePath())) {
+ path.addFirst(getDocIdForFile(file));
+
+ file = file.getParentFile();
+ }
+
+ return new Path(root.rootId, path);
+ }
+
+ @Override
public String createDocument(String docId, String mimeType, String displayName)
throws FileNotFoundException {
displayName = FileUtils.buildValidFatFilename(displayName);
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
index f9e2686..38cf559 100644
--- a/packages/Keyguard/Android.mk
+++ b/packages/Keyguard/Android.mk
@@ -14,6 +14,17 @@
#
LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := SystemUI-tags
+
+LOCAL_SRC_FILES := src/com/android/systemui/EventLogTags.logtags
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+# ------------------
+
include $(CLEAR_VARS)
LOCAL_USE_AAPT2 := true
@@ -26,6 +37,8 @@
LOCAL_JAVA_LIBRARIES := SettingsLib
+LOCAL_STATIC_JAVA_LIBRARIES = SystemUI-tags
+
LOCAL_PRIVILEGED_MODULE := true
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
diff --git a/packages/Keyguard/res/values-b+sr+Latn/strings.xml b/packages/Keyguard/res/values-b+sr+Latn/strings.xml
index 570f4bc..8006125 100644
--- a/packages/Keyguard/res/values-b+sr+Latn/strings.xml
+++ b/packages/Keyguard/res/values-b+sr+Latn/strings.xml
@@ -56,7 +56,7 @@
<string name="kg_wrong_pattern" msgid="1850806070801358830">"Pogrešan šablon"</string>
<string name="kg_wrong_password" msgid="2333281762128113157">"Pogrešna lozinka"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"Pogrešan PIN"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Pokušajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sekunde(i)."</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Probajte ponovo za <xliff:g id="NUMBER">%d</xliff:g> sekunde(i)."</string>
<string name="kg_pattern_instructions" msgid="398978611683075868">"Nacrtajte šablon"</string>
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Unesite PIN SIM kartice"</string>
<string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"Unesite PIN za SIM „<xliff:g id="CARRIER">%1$s</xliff:g>“"</string>
@@ -72,9 +72,9 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Ponovo unesite ispravni PUK kôd. Ponovljeni pokušaji će trajno onemogućiti SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN kodovi se ne podudaraju"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Previše pokušaja unosa šablona"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nPokušajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Uneli ste netačni PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Uneli ste netačnu lozinku <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. \n\nProbajte ponovo za <xliff:g id="NUMBER_1">%2$d</xliff:g> sekunde(i)."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se tablet resetuje i svi podaci sa njega brišu."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se telefon resetuje i svi podaci sa njega brišu."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> put(a). Tablet će biti resetovan i svi podaci sa njega će biti izbrisani."</string>
@@ -87,8 +87,8 @@
<string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER_0">%1$d</xliff:g> put(a). Imate još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaj(a), nakon čega se poslovni profil uklanja i svi podaci sa profila brišu."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Pogrešno ste pokušali da otključate tablet <xliff:g id="NUMBER">%d</xliff:g> put(a). Poslovni profil će biti uklonjen i svi podaci sa njega će biti izbrisani."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Pogrešno ste pokušali da otključate telefon <xliff:g id="NUMBER">%d</xliff:g> put(a). Poslovni profil će biti uklonjen i svi podaci sa njega će biti izbrisani."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nPokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate tablet pomoću naloga e-pošte.\n\nProbajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nProbajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde(i)."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Netačan SIM PIN kôd. Sada morate da kontaktirate mobilnog operatera da biste otključali uređaj."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">Netačan SIM PIN kôd. Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj.</item>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index ebea6ee..b98a253 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -128,5 +128,5 @@
<item quantity="one">Enheden blev sidst låst op for <xliff:g id="NUMBER_1">%d</xliff:g> timer siden. Bekræft adgangskoden.</item>
<item quantity="other">Enheden blev sidst låst op for <xliff:g id="NUMBER_1">%d</xliff:g> timer siden. Bekræft adgangskoden.</item>
</plurals>
- <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Kan ikke genkendes"</string>
+ <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Ikke genkendt"</string>
</resources>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index 840cae7..23c0b50 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -56,7 +56,7 @@
<string name="kg_wrong_pattern" msgid="1850806070801358830">"Погрешан шаблон"</string>
<string name="kg_wrong_password" msgid="2333281762128113157">"Погрешна лозинка"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"Погрешан PIN"</string>
- <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Покушајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
+ <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Пробајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
<string name="kg_pattern_instructions" msgid="398978611683075868">"Нацртајте шаблон"</string>
<string name="kg_sim_pin_instructions" msgid="2319508550934557331">"Унесите PIN SIM картице"</string>
<string name="kg_sim_pin_instructions_multi" msgid="7818515973197201434">"Унесите PIN за SIM „<xliff:g id="CARRIER">%1$s</xliff:g>“"</string>
@@ -72,9 +72,9 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Поново унесите исправни PUK кôд. Поновљени покушаји ће трајно онемогућити SIM."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"PIN кодови се не подударају"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Превише покушаја уноса шаблона"</string>
- <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте нетачни PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте нетачну лозинку <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
- <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПокушајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
+ <string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"Унели сте нетачни PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"Унели сте нетачну лозинку <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
+ <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. \n\nПробајте поново за <xliff:g id="NUMBER_1">%2$d</xliff:g> секунде(и)."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER_0">%1$d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%2$d</xliff:g> покушај(а), након чега се таблет ресетује и сви подаци са њега бришу."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%2$d</xliff:g> покушај(а), након чега се телефон ресетује и сви подаци са њега бришу."</string>
<string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пут(а). Таблет ће бити ресетован и сви подаци са њега ће бити избрисани."</string>
@@ -87,8 +87,8 @@
<string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER_0">%1$d</xliff:g> пут(а). Имате још <xliff:g id="NUMBER_1">%2$d</xliff:g> покушај(а), након чега се пословни профил уклања и сви подаци са профила бришу."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"Погрешно сте покушали да откључате таблет <xliff:g id="NUMBER">%d</xliff:g> пут(а). Пословни профил ће бити уклоњен и сви подаци са њега ће бити избрисани."</string>
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"Погрешно сте покушали да откључате телефон <xliff:g id="NUMBER">%d</xliff:g> пут(а). Пословни профил ће бити уклоњен и сви подаци са њега ће бити избрисани."</string>
- <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
- <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПокушајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште.\n\nПробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
+ <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде(и)."</string>
<string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"Нетачан SIM PIN кôд. Сада морате да контактирате мобилног оператера да бисте откључали уређај."</string>
<plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
<item quantity="one">Нетачан SIM PIN кôд. Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај.</item>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index 0723ab1..e15950f 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -36,7 +36,7 @@
<string name="keyguard_low_battery" msgid="8143808018719173859">"请连接充电器。"</string>
<string name="keyguard_instructions_when_pattern_disabled" msgid="1332288268600329841">"按“菜单”键解锁。"</string>
<string name="keyguard_network_locked_message" msgid="9169717779058037168">"网络已锁定"</string>
- <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"无 SIM 卡"</string>
+ <string name="keyguard_missing_sim_message_short" msgid="494980561304211931">"没有 SIM 卡"</string>
<string name="keyguard_missing_sim_message" product="tablet" msgid="1445849005909260039">"平板电脑中没有SIM卡。"</string>
<string name="keyguard_missing_sim_message" product="default" msgid="3481110395508637643">"手机中没有SIM卡。"</string>
<string name="keyguard_missing_sim_instructions" msgid="5210891509995942250">"请插入SIM卡。"</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 704e4dd..94286ec 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -16,6 +16,9 @@
package com.android.keyguard;
+import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL;
+import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
+
import android.content.Context;
import android.os.AsyncTask;
import android.os.CountDownTimer;
@@ -132,6 +135,10 @@
return;
}
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);
+ LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
mPendingLockCheck = LockPatternChecker.checkPassword(
mLockPatternUtils,
entry,
@@ -140,12 +147,20 @@
@Override
public void onEarlyMatched() {
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL);
+ }
onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */,
true /* isValidPassword */);
}
@Override
public void onChecked(boolean matched, int timeoutMs) {
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
setPasswordEntryInputEnabled(true);
mPendingLockCheck = null;
if (!matched) {
@@ -153,6 +168,16 @@
true /* isValidPassword */);
}
}
+
+ @Override
+ public void onCancelled() {
+ // We already got dismissed with the early matched callback, so we cancelled
+ // the check. However, we still need to note down the latency.
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
+ }
});
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index c9caefb..330632b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -15,6 +15,9 @@
*/
package com.android.keyguard;
+import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL;
+import static com.android.keyguard.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
+
import android.content.Context;
import android.graphics.Rect;
import android.os.AsyncTask;
@@ -242,6 +245,10 @@
return;
}
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);
+ LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
mPendingLockCheck = LockPatternChecker.checkPattern(
mLockPatternUtils,
pattern,
@@ -250,12 +257,20 @@
@Override
public void onEarlyMatched() {
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL);
+ }
onPatternChecked(userId, true /* matched */, 0 /* timeoutMs */,
true /* isValidPattern */);
}
@Override
public void onChecked(boolean matched, int timeoutMs) {
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
mLockPatternView.enableInput();
mPendingLockCheck = null;
if (!matched) {
@@ -263,6 +278,16 @@
true /* isValidPattern */);
}
}
+
+ @Override
+ public void onCancelled() {
+ // We already got dismissed with the early matched callback, so we
+ // cancelled the check. However, we still need to note down the latency.
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(
+ ACTION_CHECK_CREDENTIAL_UNLOCKED);
+ }
+ }
});
if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
mCallback.userActivity();
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 04f32a1..91c943d 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -174,6 +174,7 @@
final AlertDialog dialog = new AlertDialog.Builder(mContext)
.setTitle(title)
.setMessage(message)
+ .setCancelable(false)
.setNeutralButton(R.string.ok, null)
.create();
if (!(mContext instanceof Activity)) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 288b954..66e56e0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -16,6 +16,7 @@
package com.android.keyguard;
+import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
import static android.os.BatteryManager.BATTERY_STATUS_FULL;
import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
@@ -136,6 +137,7 @@
private static final int MSG_SCREEN_TURNED_ON = 331;
private static final int MSG_SCREEN_TURNED_OFF = 332;
private static final int MSG_DREAMING_STATE_CHANGED = 333;
+ private static final int MSG_USER_UNLOCKED = 334;
/** Fingerprint state: Not listening to fingerprint. */
private static final int FINGERPRINT_STATE_STOPPED = 0;
@@ -291,6 +293,9 @@
case MSG_DREAMING_STATE_CHANGED:
handleDreamingStateChanged(msg.arg1);
break;
+ case MSG_USER_UNLOCKED:
+ handleUserUnlocked();
+ break;
}
}
};
@@ -723,6 +728,8 @@
} else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
.equals(action)) {
mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);
+ } else if (ACTION_USER_UNLOCKED.equals(action)) {
+ mHandler.sendEmptyMessage(MSG_USER_UNLOCKED);
}
}
};
@@ -1025,6 +1032,16 @@
}
}
+ private void handleUserUnlocked() {
+ mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+ if (cb != null) {
+ cb.onUserUnlocked();
+ }
+ }
+ }
+
private KeyguardUpdateMonitor(Context context) {
mContext = context;
mSubscriptionManager = SubscriptionManager.from(context);
@@ -1065,6 +1082,7 @@
allUserFilter.addAction(ACTION_FACE_UNLOCK_STARTED);
allUserFilter.addAction(ACTION_FACE_UNLOCK_STOPPED);
allUserFilter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ allUserFilter.addAction(ACTION_USER_UNLOCKED);
context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, allUserFilter,
null, null);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index eb29d9b..14d6b59 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -128,6 +128,11 @@
public void onUserInfoChanged(int userId) { }
/**
+ * Called when a user got unlocked.
+ */
+ public void onUserUnlocked() { }
+
+ /**
* Called when boot completed.
*
* Note, this callback will only be received if boot complete occurs after registering with
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTracker.java b/packages/Keyguard/src/com/android/keyguard/LatencyTracker.java
similarity index 80%
rename from packages/SystemUI/src/com/android/systemui/LatencyTracker.java
rename to packages/Keyguard/src/com/android/keyguard/LatencyTracker.java
index 0196815..cee0afc 100644
--- a/packages/SystemUI/src/com/android/systemui/LatencyTracker.java
+++ b/packages/Keyguard/src/com/android/keyguard/LatencyTracker.java
@@ -14,14 +14,13 @@
* limitations under the License
*/
-package com.android.systemui;
+package com.android.keyguard;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
-import android.os.Handler;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
@@ -29,9 +28,15 @@
import android.util.Log;
import android.util.SparseLongArray;
+import com.android.systemui.EventLogTags;
+
/**
* Class to track various latencies in SystemUI. It then outputs the latency to logcat so these
* latencies can be captured by tests and then used for dashboards.
+ * <p>
+ * This is currently only in Keyguard so it can be shared between SystemUI and Keyguard, but
+ * eventually we'd want to merge these two packages together so Keyguard can use common classes
+ * that are shared with SystemUI.
*/
public class LatencyTracker {
@@ -55,10 +60,29 @@
*/
public static final int ACTION_FINGERPRINT_WAKE_AND_UNLOCK = 2;
+ /**
+ * Time it takes to check PIN/Pattern/Password.
+ */
+ public static final int ACTION_CHECK_CREDENTIAL = 3;
+
+ /**
+ * Time it takes to check fully PIN/Pattern/Password, i.e. that's the time spent including the
+ * actions to unlock a user.
+ */
+ public static final int ACTION_CHECK_CREDENTIAL_UNLOCKED = 4;
+
+ /**
+ * Time it takes to turn on the screen.
+ */
+ public static final int ACTION_TURN_ON_SCREEN = 5;
+
private static final String[] NAMES = new String[] {
"expand panel",
"toggle recents",
- "fingerprint wake-and-unlock" };
+ "fingerprint wake-and-unlock",
+ "check credential",
+ "check credential unlocked",
+ "turn on screen" };
private static LatencyTracker sLatencyTracker;
@@ -117,6 +141,7 @@
if (startRtc == -1) {
return;
}
+ mStartRtc.delete(action);
Trace.asyncTraceEnd(Trace.TRACE_TAG_APP, NAMES[action], 0);
long duration = endRtc - startRtc;
Log.i(TAG, "action=" + action + " latency=" + duration);
diff --git a/packages/SystemUI/src/com/android/systemui/EventLogTags.logtags b/packages/Keyguard/src/com/android/systemui/EventLogTags.logtags
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/EventLogTags.logtags
rename to packages/Keyguard/src/com/android/systemui/EventLogTags.logtags
diff --git a/packages/MtpDocumentsProvider/perf_tests/Android.mk b/packages/MtpDocumentsProvider/perf_tests/Android.mk
new file mode 100644
index 0000000..f0d4878
--- /dev/null
+++ b/packages/MtpDocumentsProvider/perf_tests/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_PACKAGE_NAME := MtpDocumentsProviderPerfTests
+LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
+LOCAL_CERTIFICATE := media
+
+include $(BUILD_PACKAGE)
diff --git a/packages/MtpDocumentsProvider/perf_tests/AndroidManifest.xml b/packages/MtpDocumentsProvider/perf_tests/AndroidManifest.xml
new file mode 100644
index 0000000..26e109d
--- /dev/null
+++ b/packages/MtpDocumentsProvider/perf_tests/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.mtp.perftests"
+ android:sharedUserId="android.media">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.mtp"
+ android:label="Performance tests for MtpDocumentsProvider." />
+</manifest>
diff --git a/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java b/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
new file mode 100644
index 0000000..0762571
--- /dev/null
+++ b/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.support.test.filters.LargeTest;
+import android.support.test.InstrumentationRegistry;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Arrays;
+import libcore.io.IoUtils;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.junit.Test;
+
+@RunWith(JUnit4.class)
+public class AppFusePerfTest {
+ @Test
+ @LargeTest
+ public void testReadWriteFile() throws IOException {
+ final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ final StorageManager storageManager = context.getSystemService(StorageManager.class);
+ final int INODE = 10;
+ final int SIZE = 10 * 1024 * 1024; // 10MB
+ final AppFuse appFuse = new AppFuse(
+ "test",
+ new TestCallback() {
+ @Override
+ public long getFileSize(int inode) throws FileNotFoundException {
+ if (inode != INODE) {
+ throw new FileNotFoundException();
+ }
+ return SIZE;
+ }
+
+ @Override
+ public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
+ throws IOException {
+ return size;
+ }
+
+ @Override
+ public int writeObjectBytes(
+ long fileHandle, int inode, long offset, int size, byte[] bytes) {
+ return size;
+ }
+ });
+
+ appFuse.mount(storageManager);
+
+ final byte[] bytes = new byte[SIZE];
+ final int SAMPLES = 100;
+ final double[] readTime = new double[SAMPLES];
+ final double[] writeTime = new double[SAMPLES];
+
+ for (int i = 0; i < SAMPLES; i++) {
+ final ParcelFileDescriptor fd = appFuse.openFile(
+ INODE,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ try (final ParcelFileDescriptor.AutoCloseInputStream stream =
+ new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
+ final long startTime = System.nanoTime();
+ stream.read(bytes);
+ readTime[i] = (System.nanoTime() - startTime) / 1000.0 / 1000.0;
+ }
+
+ }
+
+ for (int i = 0; i < SAMPLES; i++) {
+ final ParcelFileDescriptor fd = appFuse.openFile(
+ INODE,
+ ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
+ try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
+ new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
+ final long startTime = System.nanoTime();
+ stream.write(bytes);
+ writeTime[i] = (System.nanoTime() - startTime) / 1000.0 / 1000.0;
+ }
+ }
+
+ appFuse.close();
+
+ double readAverage = 0;
+ double writeAverage = 0;
+ double readSquaredAverage = 0;
+ double writeSquaredAverage = 0;
+ for (int i = 0; i < SAMPLES; i++) {
+ readAverage += readTime[i];
+ writeAverage += writeTime[i];
+ readSquaredAverage += readTime[i] * readTime[i];
+ writeSquaredAverage += writeTime[i] * writeTime[i];
+ }
+
+ readAverage /= SAMPLES;
+ writeAverage /= SAMPLES;
+ readSquaredAverage /= SAMPLES;
+ writeSquaredAverage /= SAMPLES;
+
+ final Bundle results = new Bundle();
+ results.putDouble("readAverage", readAverage);
+ results.putDouble("readStandardDeviation",
+ Math.sqrt(readSquaredAverage - readAverage * readAverage));
+ results.putDouble("writeAverage", writeAverage);
+ results.putDouble("writeStandardDeviation",
+ Math.sqrt(writeSquaredAverage - writeAverage * writeAverage));
+ InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, results);
+ }
+
+ private static class TestCallback implements AppFuse.Callback {
+ @Override
+ public long getFileSize(int inode) throws FileNotFoundException {
+ throw new FileNotFoundException();
+ }
+
+ @Override
+ public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
+ throws IOException {
+ throw new IOException();
+ }
+
+ @Override
+ public int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes)
+ throws IOException {
+ throw new IOException();
+ }
+
+ @Override
+ public void flushFileHandle(long fileHandle) throws IOException {}
+
+ @Override
+ public void closeFileHandle(long fileHandle) {}
+ }
+}
diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
index ce8a81e..2b1b8ca 100644
--- a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
+++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
@@ -103,8 +103,8 @@
<item msgid="3199660090246166812">"Vodoravno"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"Upisivanje u datoteku nije moguće"</string>
- <string name="print_error_default_message" msgid="8602678405502922346">"Žao nam je, ovo nije uspelo. Pokušajte ponovo."</string>
- <string name="print_error_retry" msgid="1426421728784259538">"Pokušajte ponovo"</string>
+ <string name="print_error_default_message" msgid="8602678405502922346">"Žao nam je, ovo nije uspelo. Probajte ponovo."</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Probajte ponovo"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Ovaj štampač trenutno nije dostupan."</string>
<string name="print_cannot_load_page" msgid="6179560924492912009">"Nije uspeo prikaz pregleda"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Priprema pregleda..."</string>
diff --git a/packages/PrintSpooler/res/values-kn-rIN/strings.xml b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
index ef3ea16..c6e36d2 100644
--- a/packages/PrintSpooler/res/values-kn-rIN/strings.xml
+++ b/packages/PrintSpooler/res/values-kn-rIN/strings.xml
@@ -47,7 +47,7 @@
<string name="savetopdf_button" msgid="2976186791686924743">"PDF ಗೆ ಉಳಿಸು"</string>
<string name="print_options_expanded" msgid="6944679157471691859">"ಪ್ರಿಂಟ್ ಆಯ್ಕೆಗಳನ್ನು ವಿಸ್ತರಿಸಲಾಗಿದೆ"</string>
<string name="print_options_collapsed" msgid="7455930445670414332">"ಪ್ರಿಂಟ್ ಆಯ್ಕೆಗಳನ್ನು ಮುಚ್ಚಲಾಗಿದೆ"</string>
- <string name="search" msgid="5421724265322228497">"ಹುಡುಕು"</string>
+ <string name="search" msgid="5421724265322228497">"ಹುಡುಕಿ"</string>
<string name="all_printers_label" msgid="3178848870161526399">"ಎಲ್ಲಾ ಪ್ರಿಂಟರ್ಗಳು"</string>
<string name="add_print_service_label" msgid="5356702546188981940">"ಸೇವೆಯನ್ನು ಸೇರಿಸು"</string>
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"ಹುಡುಕಾಟ ಪೆಟ್ಟಿಗೆಯನ್ನು ತೋರಿಸಲಾಗಿದೆ"</string>
diff --git a/packages/PrintSpooler/res/values-sr/strings.xml b/packages/PrintSpooler/res/values-sr/strings.xml
index 012bbbc..9283d77 100644
--- a/packages/PrintSpooler/res/values-sr/strings.xml
+++ b/packages/PrintSpooler/res/values-sr/strings.xml
@@ -103,8 +103,8 @@
<item msgid="3199660090246166812">"Водоравно"</item>
</string-array>
<string name="print_write_error_message" msgid="5787642615179572543">"Уписивање у датотеку није могуће"</string>
- <string name="print_error_default_message" msgid="8602678405502922346">"Жао нам је, ово није успело. Покушајте поново."</string>
- <string name="print_error_retry" msgid="1426421728784259538">"Покушајте поново"</string>
+ <string name="print_error_default_message" msgid="8602678405502922346">"Жао нам је, ово није успело. Пробајте поново."</string>
+ <string name="print_error_retry" msgid="1426421728784259538">"Пробајте поново"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"Овај штампач тренутно није доступан."</string>
<string name="print_cannot_load_page" msgid="6179560924492912009">"Није успео приказ прегледа"</string>
<string name="print_preparing_preview" msgid="3939930735671364712">"Припрема прегледа..."</string>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index b3cfea5..23c6615 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -46,7 +46,6 @@
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.os.UserManager;
import android.print.IPrintDocumentAdapter;
import android.print.PageRange;
@@ -760,8 +759,11 @@
mPrintJob.setPrinterId(printerInfo.getId());
mPrintJob.setPrinterName(printerInfo.getName());
- if (printerInfo.getCapabilities() != null) {
+ if (canPrint(printerInfo)) {
updatePrintAttributesFromCapabilities(printerInfo.getCapabilities());
+ onPrinterAvailable(printerInfo);
+ } else {
+ onPrinterUnavailable(printerInfo);
}
mDestinationSpinnerAdapter.ensurePrinterInVisibleAdapterPosition(printerInfo);
@@ -2050,7 +2052,7 @@
}
public void onPrinterUnavailable(PrinterInfo printer) {
- if (mCurrentPrinter.getId().equals(printer.getId())) {
+ if (mCurrentPrinter == null || mCurrentPrinter.getId().equals(printer.getId())) {
setState(STATE_PRINTER_UNAVAILABLE);
mPrintedDocument.cancel(false);
ensureErrorUiShown(getString(R.string.print_error_printer_unavailable),
@@ -2309,8 +2311,7 @@
public int getPrinterIndex(PrinterId printerId) {
for (int i = 0; i < getCount(); i++) {
PrinterHolder printerHolder = (PrinterHolder) getItem(i);
- if (printerHolder != null && !printerHolder.removed
- && printerHolder.printer.getId().equals(printerId)) {
+ if (printerHolder != null && printerHolder.printer.getId().equals(printerId)) {
return i;
}
}
@@ -2539,7 +2540,11 @@
if (updatedPrinter != null) {
printerHolder.printer = updatedPrinter;
printerHolder.removed = false;
- onPrinterAvailable(printerHolder.printer);
+ if (canPrint(printerHolder.printer)) {
+ onPrinterAvailable(printerHolder.printer);
+ } else {
+ onPrinterUnavailable(printerHolder.printer);
+ }
newPrinterHolders.add(printerHolder);
} else if (mCurrentPrinter != null && mCurrentPrinter.getId().equals(oldPrinterId)){
printerHolder.removed = true;
diff --git a/packages/PrintSpooler/tests/Android.mk b/packages/PrintSpooler/tests/Android.mk
new file mode 100644
index 0000000..83e00ce
--- /dev/null
+++ b/packages/PrintSpooler/tests/Android.mk
@@ -0,0 +1,19 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk
new file mode 100644
index 0000000..d1d0ee4
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
+
+LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests
+
+include $(BUILD_PACKAGE)
diff --git a/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml b/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml
new file mode 100644
index 0000000..4a05f6f
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/AndroidManifest.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.printspooler.outofprocess.tests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+
+ <activity android:name=".PrintTestActivity"/>
+
+ <service
+ android:name=".mockservice.MockPrintService"
+ android:permission="android.permission.BIND_PRINT_SERVICE">
+
+ <intent-filter>
+ <action android:name="android.printservice.PrintService" />
+ </intent-filter>
+ <meta-data
+ android:name="android.printservice"
+ android:resource="@xml/printservice">
+ </meta-data>
+ </service>
+
+ <activity
+ android:name=".mockservice.SettingsActivity"
+ android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+ android:exported="true">
+ </activity>
+
+ <activity
+ android:name=".mockservice.AddPrintersActivity"
+ android:exported="true">
+ </activity>
+
+ </application>
+
+ <!-- This runs in its own process, hence it instruments itself -->
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.printspooler.outofprocess.tests"
+ android:label="PrintSpooler Out of Process Test Cases">
+ </instrumentation>
+
+</manifest>
diff --git a/packages/PrintSpooler/tests/outofprocess/res/xml/printservice.xml b/packages/PrintSpooler/tests/outofprocess/res/xml/printservice.xml
new file mode 100644
index 0000000..9eecf45
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/res/xml/printservice.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<print-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:addPrintersActivity="com.android.printspooler.outofprocess.tests.mockservice.AddPrintersActivity" />
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/BasePrintTest.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/BasePrintTest.java
new file mode 100644
index 0000000..4de3570
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/BasePrintTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.outofprocess.tests;
+
+import android.annotation.NonNull;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintManager;
+import android.print.PrinterId;
+import com.android.printspooler.outofprocess.tests.mockservice.PrintServiceCallbacks;
+import com.android.printspooler.outofprocess.tests.mockservice.PrinterDiscoverySessionCallbacks;
+import com.android.printspooler.outofprocess.tests.mockservice.StubbablePrinterDiscoverySession;
+import android.printservice.CustomPrinterIconCallback;
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.uiautomator.UiDevice;
+import org.junit.After;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.mockito.stubbing.Answer;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.List;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * This is the base class for print tests.
+ */
+abstract class BasePrintTest {
+ protected static final long OPERATION_TIMEOUT = 30000;
+ private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success";
+ private static final int CURRENT_USER_ID = -2; // Mirrors UserHandle.USER_CURRENT
+
+ private android.print.PrintJob mPrintJob;
+
+ private static Instrumentation sInstrumentation;
+ private static UiDevice sUiDevice;
+
+ @Rule
+ public ActivityTestRule<PrintTestActivity> mActivityRule =
+ new ActivityTestRule<>(PrintTestActivity.class, false, true);
+
+ /**
+ * Return the UI device
+ *
+ * @return the UI device
+ */
+ public UiDevice getUiDevice() {
+ return sUiDevice;
+ }
+
+ protected static Instrumentation getInstrumentation() {
+ return sInstrumentation;
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ sInstrumentation = InstrumentationRegistry.getInstrumentation();
+ assumeTrue(sInstrumentation.getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_PRINTING));
+
+ sUiDevice = UiDevice.getInstance(sInstrumentation);
+
+ // Make sure we start with a clean slate.
+ clearPrintSpoolerData();
+
+ // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
+ // Dexmaker is used by mockito.
+ System.setProperty("dexmaker.dexcache", getInstrumentation()
+ .getTargetContext().getCacheDir().getPath());
+ }
+
+ @After
+ public void exitActivities() throws Exception {
+ // Exit print spooler
+ getUiDevice().pressBack();
+ getUiDevice().pressBack();
+ }
+
+ protected android.print.PrintJob print(@NonNull final PrintDocumentAdapter adapter,
+ final PrintAttributes attributes) {
+ // Initiate printing as if coming from the app.
+ getInstrumentation().runOnMainSync(() -> {
+ PrintManager printManager = (PrintManager) getActivity()
+ .getSystemService(Context.PRINT_SERVICE);
+ mPrintJob = printManager.print("Print job", adapter, attributes);
+ });
+
+ return mPrintJob;
+ }
+
+ protected PrintTestActivity getActivity() {
+ return mActivityRule.getActivity();
+ }
+
+ public static String runShellCommand(Instrumentation instrumentation, String cmd)
+ throws IOException {
+ ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
+ byte[] buf = new byte[512];
+ int bytesRead;
+ FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ StringBuilder stdout = new StringBuilder();
+ while ((bytesRead = fis.read(buf)) != -1) {
+ stdout.append(new String(buf, 0, bytesRead));
+ }
+ fis.close();
+ return stdout.toString();
+ }
+
+ protected static void clearPrintSpoolerData() throws Exception {
+ assertTrue("failed to clear print spooler data",
+ runShellCommand(getInstrumentation(), String.format(
+ "pm clear --user %d %s", CURRENT_USER_ID,
+ PrintManager.PRINT_SPOOLER_PACKAGE_NAME))
+ .contains(PM_CLEAR_SUCCESS_OUTPUT));
+ }
+
+ @SuppressWarnings("unchecked")
+ protected PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
+ Answer<Void> onStartPrinterDiscovery, Answer<Void> onStopPrinterDiscovery,
+ Answer<Void> onValidatePrinters, Answer<Void> onStartPrinterStateTracking,
+ Answer<Void> onRequestCustomPrinterIcon, Answer<Void> onStopPrinterStateTracking,
+ Answer<Void> onDestroy) {
+ PrinterDiscoverySessionCallbacks callbacks = mock(PrinterDiscoverySessionCallbacks.class);
+
+ doCallRealMethod().when(callbacks).setSession(any(StubbablePrinterDiscoverySession.class));
+ when(callbacks.getSession()).thenCallRealMethod();
+
+ if (onStartPrinterDiscovery != null) {
+ doAnswer(onStartPrinterDiscovery).when(callbacks).onStartPrinterDiscovery(
+ any(List.class));
+ }
+ if (onStopPrinterDiscovery != null) {
+ doAnswer(onStopPrinterDiscovery).when(callbacks).onStopPrinterDiscovery();
+ }
+ if (onValidatePrinters != null) {
+ doAnswer(onValidatePrinters).when(callbacks).onValidatePrinters(
+ any(List.class));
+ }
+ if (onStartPrinterStateTracking != null) {
+ doAnswer(onStartPrinterStateTracking).when(callbacks).onStartPrinterStateTracking(
+ any(PrinterId.class));
+ }
+ if (onRequestCustomPrinterIcon != null) {
+ doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon(
+ any(PrinterId.class), any(CancellationSignal.class),
+ any(CustomPrinterIconCallback.class));
+ }
+ if (onStopPrinterStateTracking != null) {
+ doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
+ any(PrinterId.class));
+ }
+ if (onDestroy != null) {
+ doAnswer(onDestroy).when(callbacks).onDestroy();
+ }
+
+ return callbacks;
+ }
+
+ protected PrintServiceCallbacks createMockPrintServiceCallbacks(
+ Answer<PrinterDiscoverySessionCallbacks> onCreatePrinterDiscoverySessionCallbacks,
+ Answer<Void> onPrintJobQueued, Answer<Void> onRequestCancelPrintJob) {
+ final PrintServiceCallbacks service = mock(PrintServiceCallbacks.class);
+
+ doCallRealMethod().when(service).setService(any(PrintService.class));
+ when(service.getService()).thenCallRealMethod();
+
+ if (onCreatePrinterDiscoverySessionCallbacks != null) {
+ doAnswer(onCreatePrinterDiscoverySessionCallbacks).when(service)
+ .onCreatePrinterDiscoverySessionCallbacks();
+ }
+ if (onPrintJobQueued != null) {
+ doAnswer(onPrintJobQueued).when(service).onPrintJobQueued(any(PrintJob.class));
+ }
+ if (onRequestCancelPrintJob != null) {
+ doAnswer(onRequestCancelPrintJob).when(service).onRequestCancelPrintJob(
+ any(PrintJob.class));
+ }
+
+ return service;
+ }
+}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/PrintTestActivity.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/PrintTestActivity.java
new file mode 100644
index 0000000..4905a0b
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/PrintTestActivity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.outofprocess.tests;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class PrintTestActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+ }
+}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java
new file mode 100644
index 0000000..184e559
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.outofprocess.tests;
+
+import android.graphics.pdf.PdfDocument;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentInfo;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import com.android.printspooler.outofprocess.tests.mockservice.AddPrintersActivity;
+import com.android.printspooler.outofprocess.tests.mockservice.MockPrintService;
+import com.android.printspooler.outofprocess.tests.mockservice.PrinterDiscoverySessionCallbacks;
+import com.android.printspooler.outofprocess.tests.mockservice.StubbablePrinterDiscoverySession;
+import android.print.pdf.PrintedPdfDocument;
+import android.support.test.filters.LargeTest;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+import android.util.Log;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+import java.util.function.Supplier;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Tests for the basic printing workflows
+ */
+@RunWith(Parameterized.class)
+public class WorkflowTest extends BasePrintTest {
+ private static final String LOG_TAG = WorkflowTest.class.getSimpleName();
+
+ private static float sWindowAnimationScaleBefore;
+ private static float sTransitionAnimationScaleBefore;
+ private static float sAnimatiorDurationScaleBefore;
+
+ private PrintAttributes.MediaSize mFirst;
+ private boolean mSelectPrinter;
+ private PrintAttributes.MediaSize mSecond;
+
+ public WorkflowTest(PrintAttributes.MediaSize first, boolean selectPrinter,
+ PrintAttributes.MediaSize second) {
+ mFirst = first;
+ mSelectPrinter = selectPrinter;
+ mSecond = second;
+ }
+
+ interface InterruptableConsumer<T> {
+ void accept(T t) throws InterruptedException;
+ }
+
+ /**
+ * Execute {@code waiter} until {@code condition} is met.
+ *
+ * @param condition Conditions to wait for
+ * @param waiter Code to execute while waiting
+ */
+ private void waitWithTimeout(Supplier<Boolean> condition, InterruptableConsumer<Long> waiter)
+ throws TimeoutException, InterruptedException {
+ long startTime = System.currentTimeMillis();
+ while (condition.get()) {
+ long timeLeft = OPERATION_TIMEOUT - (System.currentTimeMillis() - startTime);
+ if (timeLeft < 0) {
+ throw new TimeoutException();
+ }
+
+ waiter.accept(timeLeft);
+ }
+ }
+
+ /**
+ * Executes a shell command using shell user identity, and return the standard output in
+ * string.
+ *
+ * @param cmd the command to run
+ *
+ * @return the standard output of the command
+ */
+ private static String runShellCommand(String cmd) throws IOException {
+ try (FileInputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
+ getInstrumentation().getUiAutomation().executeShellCommand(cmd))) {
+ byte[] buf = new byte[64];
+ int bytesRead;
+
+ StringBuilder stdout = new StringBuilder();
+ while ((bytesRead = is.read(buf)) != -1) {
+ stdout.append(new String(buf, 0, bytesRead));
+ }
+
+ return stdout.toString();
+ }
+ }
+
+ @BeforeClass
+ public static void disableAnimations() throws Exception {
+ try {
+ sWindowAnimationScaleBefore = Float.parseFloat(runShellCommand(
+ "settings get global window_animation_scale"));
+
+ runShellCommand("settings put global window_animation_scale 0");
+ } catch (NumberFormatException e) {
+ sWindowAnimationScaleBefore = Float.NaN;
+ }
+ try {
+ sTransitionAnimationScaleBefore = Float.parseFloat(runShellCommand(
+ "settings get global transition_animation_scale"));
+
+ runShellCommand("settings put global transition_animation_scale 0");
+ } catch (NumberFormatException e) {
+ sTransitionAnimationScaleBefore = Float.NaN;
+ }
+ try {
+ sAnimatiorDurationScaleBefore = Float.parseFloat(runShellCommand(
+ "settings get global animator_duration_scale"));
+
+ runShellCommand("settings put global animator_duration_scale 0");
+ } catch (NumberFormatException e) {
+ sAnimatiorDurationScaleBefore = Float.NaN;
+ }
+ }
+
+ @AfterClass
+ public static void enableAnimations() throws Exception {
+ if (sWindowAnimationScaleBefore != Float.NaN) {
+ runShellCommand(
+ "settings put global window_animation_scale " + sWindowAnimationScaleBefore);
+ }
+ if (sTransitionAnimationScaleBefore != Float.NaN) {
+ runShellCommand(
+ "settings put global transition_animation_scale " +
+ sTransitionAnimationScaleBefore);
+ }
+ if (sAnimatiorDurationScaleBefore != Float.NaN) {
+ runShellCommand(
+ "settings put global animator_duration_scale " + sAnimatiorDurationScaleBefore);
+ }
+ }
+
+ /** Add a printer with a given name and supported mediasize to a session */
+ private void addPrinter(StubbablePrinterDiscoverySession session,
+ String name, PrintAttributes.MediaSize mediaSize) {
+ PrinterId printerId = session.getService().generatePrinterId(name);
+ List<PrinterInfo> printers = new ArrayList<>(1);
+
+ PrinterCapabilitiesInfo.Builder builder =
+ new PrinterCapabilitiesInfo.Builder(printerId);
+
+ PrinterInfo printerInfo;
+ if (mediaSize != null) {
+ builder.setMinMargins(new PrintAttributes.Margins(0, 0, 0, 0))
+ .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .addMediaSize(mediaSize, true)
+ .addResolution(new PrintAttributes.Resolution("300x300", "300x300", 300, 300),
+ true);
+
+ printerInfo = new PrinterInfo.Builder(printerId, name,
+ PrinterInfo.STATUS_IDLE).setCapabilities(builder.build()).build();
+ } else {
+ printerInfo = (new PrinterInfo.Builder(printerId, name,
+ PrinterInfo.STATUS_IDLE)).build();
+ }
+
+ printers.add(printerInfo);
+ session.addPrinters(printers);
+ }
+
+ /** Find a certain element in the UI and click on it */
+ private void clickOn(UiSelector selector) throws UiObjectNotFoundException {
+ Log.i(LOG_TAG, "Click on " + selector);
+ UiObject view = getUiDevice().findObject(selector);
+ view.click();
+ getUiDevice().waitForIdle();
+ }
+
+ /** Find a certain text in the UI and click on it */
+ private void clickOnText(String text) throws UiObjectNotFoundException {
+ clickOn(new UiSelector().text(text));
+ }
+
+ /** Set the printer in the print activity */
+ private void setPrinter(String printerName) throws UiObjectNotFoundException {
+ clickOn(new UiSelector().resourceId("com.android.printspooler:id/destination_spinner"));
+
+ clickOnText(printerName);
+ }
+
+ /**
+ * Init mock print servic that returns a single printer by default.
+ *
+ * @param sessionRef Where to store the reference to the session once started
+ */
+ private void setMockPrintServiceCallbacks(StubbablePrinterDiscoverySession[] sessionRef,
+ ArrayList<String> trackedPrinters, PrintAttributes.MediaSize mediaSize) {
+ MockPrintService.setCallbacks(createMockPrintServiceCallbacks(
+ inv -> createMockPrinterDiscoverySessionCallbacks(inv2 -> {
+ synchronized (sessionRef) {
+ sessionRef[0] = ((PrinterDiscoverySessionCallbacks) inv2.getMock())
+ .getSession();
+
+ addPrinter(sessionRef[0], "1st printer", mediaSize);
+
+ sessionRef.notifyAll();
+ }
+ return null;
+ },
+ null, null, inv2 -> {
+ synchronized (trackedPrinters) {
+ trackedPrinters
+ .add(((PrinterId) inv2.getArguments()[0]).getLocalId());
+ trackedPrinters.notifyAll();
+ }
+ return null;
+ }, null, inv2 -> {
+ synchronized (trackedPrinters) {
+ trackedPrinters
+ .remove(((PrinterId) inv2.getArguments()[0]).getLocalId());
+ trackedPrinters.notifyAll();
+ }
+ return null;
+ }, inv2 -> {
+ synchronized (sessionRef) {
+ sessionRef[0] = null;
+ sessionRef.notifyAll();
+ }
+ return null;
+ }
+ ), null, null));
+ }
+
+ /**
+ * Start print operation that just prints a single empty page
+ *
+ * @param printAttributesRef Where to store the reference to the print attributes once started
+ */
+ private void print(PrintAttributes[] printAttributesRef) {
+ print(new PrintDocumentAdapter() {
+ @Override
+ public void onStart() {
+ }
+
+ @Override
+ public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+ CancellationSignal cancellationSignal, LayoutResultCallback callback,
+ Bundle extras) {
+ callback.onLayoutFinished((new PrintDocumentInfo.Builder("doc")).build(),
+ !newAttributes.equals(printAttributesRef[0]));
+
+ synchronized (printAttributesRef) {
+ printAttributesRef[0] = newAttributes;
+ printAttributesRef.notifyAll();
+ }
+ }
+
+ @Override
+ public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
+ CancellationSignal cancellationSignal, WriteResultCallback callback) {
+ try {
+ try {
+ PrintedPdfDocument document = new PrintedPdfDocument(getActivity(),
+ printAttributesRef[0]);
+ try {
+ PdfDocument.Page page = document.startPage(0);
+ document.finishPage(page);
+ try (FileOutputStream os = new FileOutputStream(
+ destination.getFileDescriptor())) {
+ document.writeTo(os);
+ os.flush();
+ }
+ } finally {
+ document.close();
+ }
+ } finally {
+ destination.close();
+ }
+
+ callback.onWriteFinished(pages);
+ } catch (IOException e) {
+ callback.onWriteFailed(e.getMessage());
+ }
+ }
+ }, null);
+ }
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> getParameters() {
+ ArrayList<Object[]> tests = new ArrayList<>();
+
+ for (PrintAttributes.MediaSize first : new PrintAttributes.MediaSize[]{
+ PrintAttributes.MediaSize.ISO_A0, null}) {
+ for (Boolean selectPrinter : new Boolean[]{true, false}) {
+ for (PrintAttributes.MediaSize second : new PrintAttributes.MediaSize[]{
+ PrintAttributes.MediaSize.ISO_A1, null}) {
+ // If we do not use the second printer, no need to try various options
+ if (!selectPrinter && second == null) {
+ continue;
+ }
+ tests.add(new Object[]{first, selectPrinter, second});
+ }
+ }
+ }
+
+ return tests;
+ }
+
+ @Test
+ @LargeTest
+ public void addAndSelectPrinter() throws Exception {
+ final StubbablePrinterDiscoverySession session[] = new StubbablePrinterDiscoverySession[1];
+ final PrintAttributes printAttributes[] = new PrintAttributes[1];
+ ArrayList<String> trackedPrinters = new ArrayList<>();
+
+ Log.i(LOG_TAG, "Running " + mFirst + " " + mSelectPrinter + " " + mSecond);
+
+ setMockPrintServiceCallbacks(session, trackedPrinters, mFirst);
+ print(printAttributes);
+
+ // We are now in the PrintActivity
+ Log.i(LOG_TAG, "Waiting for session");
+ synchronized (session) {
+ waitWithTimeout(() -> session[0] == null, session::wait);
+ }
+
+ setPrinter("1st printer");
+
+ Log.i(LOG_TAG, "Waiting for 1st printer to be tracked");
+ synchronized (trackedPrinters) {
+ waitWithTimeout(() -> !trackedPrinters.contains("1st printer"), trackedPrinters::wait);
+ }
+
+ if (mFirst != null) {
+ Log.i(LOG_TAG, "Waiting for print attributes to change");
+ synchronized (printAttributes) {
+ waitWithTimeout(
+ () -> printAttributes[0] == null ||
+ !printAttributes[0].getMediaSize().equals(
+ mFirst), printAttributes::wait);
+ }
+ } else {
+ Log.i(LOG_TAG, "Waiting for error message");
+ assertNotNull(getUiDevice().wait(Until.findObject(
+ By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
+ }
+
+ setPrinter("All printers\u2026");
+
+ // We are now in the SelectPrinterActivity
+ clickOnText("Add printer");
+
+ // We are now in the AddPrinterActivity
+ AddPrintersActivity.addObserver(
+ () -> addPrinter(session[0], "2nd printer", mSecond));
+
+ // This executes the observer registered above
+ clickOn(new UiSelector().text(MockPrintService.class.getCanonicalName())
+ .resourceId("com.android.printspooler:id/title"));
+
+ getUiDevice().pressBack();
+ AddPrintersActivity.clearObservers();
+
+ if (mSelectPrinter) {
+ // We are now in the SelectPrinterActivity
+ clickOnText("2nd printer");
+ } else {
+ getUiDevice().pressBack();
+ }
+
+ // We are now in the PrintActivity
+ if (mSelectPrinter) {
+ if (mSecond != null) {
+ Log.i(LOG_TAG, "Waiting for print attributes to change");
+ synchronized (printAttributes) {
+ waitWithTimeout(
+ () -> printAttributes[0] == null ||
+ !printAttributes[0].getMediaSize().equals(
+ mSecond), printAttributes::wait);
+ }
+ } else {
+ Log.i(LOG_TAG, "Waiting for error message");
+ assertNotNull(getUiDevice().wait(Until.findObject(
+ By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
+ }
+
+ Log.i(LOG_TAG, "Waiting for 1st printer to be not tracked");
+ synchronized (trackedPrinters) {
+ waitWithTimeout(() -> trackedPrinters.contains("1st printer"),
+ trackedPrinters::wait);
+ }
+
+ Log.i(LOG_TAG, "Waiting for 2nd printer to be tracked");
+ synchronized (trackedPrinters) {
+ waitWithTimeout(() -> !trackedPrinters.contains("2nd printer"),
+ trackedPrinters::wait);
+ }
+ } else {
+ Thread.sleep(100);
+
+ if (mFirst != null) {
+ Log.i(LOG_TAG, "Waiting for print attributes to change");
+ synchronized (printAttributes) {
+ waitWithTimeout(
+ () -> printAttributes[0] == null ||
+ !printAttributes[0].getMediaSize().equals(
+ mFirst), printAttributes::wait);
+ }
+ } else {
+ Log.i(LOG_TAG, "Waiting for error message");
+ assertNotNull(getUiDevice().wait(Until.findObject(
+ By.text("This printer isn't available right now.")), OPERATION_TIMEOUT));
+ }
+
+ Log.i(LOG_TAG, "Waiting for 1st printer to be tracked");
+ synchronized (trackedPrinters) {
+ waitWithTimeout(() -> !trackedPrinters.contains("1st printer"),
+ trackedPrinters::wait);
+ }
+ }
+
+ getUiDevice().pressBack();
+
+ // We are back in the test activity
+ Log.i(LOG_TAG, "Waiting for session to end");
+ synchronized (session) {
+ waitWithTimeout(() -> session[0] != null, session::wait);
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/AddPrintersActivity.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/AddPrintersActivity.java
similarity index 95%
rename from core/tests/coretests/src/android/print/mockservice/AddPrintersActivity.java
rename to packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/AddPrintersActivity.java
index 8f1a9ed..2ea4e7d 100644
--- a/core/tests/coretests/src/android/print/mockservice/AddPrintersActivity.java
+++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/AddPrintersActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.print.mockservice;
+package com.android.printspooler.outofprocess.tests.mockservice;
import android.app.Activity;
import android.os.Bundle;
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/MockPrintService.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/MockPrintService.java
new file mode 100644
index 0000000..3a23113
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/MockPrintService.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.outofprocess.tests.mockservice;
+
+public class MockPrintService extends StubbablePrintService {
+
+ private static final Object sLock = new Object();
+
+ private static PrintServiceCallbacks sCallbacks;
+
+ public static void setCallbacks(PrintServiceCallbacks callbacks) {
+ synchronized (sLock) {
+ sCallbacks = callbacks;
+ }
+ }
+
+ @Override
+ protected PrintServiceCallbacks getCallbacks() {
+ synchronized (sLock) {
+ if (sCallbacks != null) {
+ sCallbacks.setService(this);
+ }
+ return sCallbacks;
+ }
+ }
+}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrintServiceCallbacks.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrintServiceCallbacks.java
new file mode 100644
index 0000000..07baa0f
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrintServiceCallbacks.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.outofprocess.tests.mockservice;
+
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+
+public abstract class PrintServiceCallbacks {
+
+ private PrintService mService;
+
+ public PrintService getService() {
+ return mService;
+ }
+
+ public void setService(PrintService service) {
+ mService = service;
+ }
+
+ public abstract PrinterDiscoverySessionCallbacks onCreatePrinterDiscoverySessionCallbacks();
+
+ public abstract void onRequestCancelPrintJob(PrintJob printJob);
+
+ public abstract void onPrintJobQueued(PrintJob printJob);
+}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrinterDiscoverySessionCallbacks.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrinterDiscoverySessionCallbacks.java
new file mode 100644
index 0000000..5c1260c
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/PrinterDiscoverySessionCallbacks.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.outofprocess.tests.mockservice;
+
+import android.os.CancellationSignal;
+import android.print.PrinterId;
+import android.printservice.CustomPrinterIconCallback;
+
+import java.util.List;
+
+public abstract class PrinterDiscoverySessionCallbacks {
+
+ private StubbablePrinterDiscoverySession mSession;
+
+ public void setSession(StubbablePrinterDiscoverySession session) {
+ mSession = session;
+ }
+
+ public StubbablePrinterDiscoverySession getSession() {
+ return mSession;
+ }
+
+ public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
+
+ public abstract void onStopPrinterDiscovery();
+
+ public abstract void onValidatePrinters(List<PrinterId> printerIds);
+
+ public abstract void onStartPrinterStateTracking(PrinterId printerId);
+
+ public abstract void onRequestCustomPrinterIcon(PrinterId printerId,
+ CancellationSignal cancellationSignal, CustomPrinterIconCallback callback);
+
+ public abstract void onStopPrinterStateTracking(PrinterId printerId);
+
+ public abstract void onDestroy();
+}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrintService.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrintService.java
new file mode 100644
index 0000000..be9d19b
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrintService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.outofprocess.tests.mockservice;
+
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.printservice.PrinterDiscoverySession;
+
+public abstract class StubbablePrintService extends PrintService {
+
+ @Override
+ public PrinterDiscoverySession onCreatePrinterDiscoverySession() {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ return new StubbablePrinterDiscoverySession(this,
+ getCallbacks().onCreatePrinterDiscoverySessionCallbacks());
+ }
+ return null;
+ }
+
+ @Override
+ public void onRequestCancelPrintJob(PrintJob printJob) {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ callbacks.onRequestCancelPrintJob(printJob);
+ }
+ }
+
+ @Override
+ public void onPrintJobQueued(PrintJob printJob) {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ callbacks.onPrintJobQueued(printJob);
+ }
+ }
+
+ protected abstract PrintServiceCallbacks getCallbacks();
+}
diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrinterDiscoverySession.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrinterDiscoverySession.java
new file mode 100644
index 0000000..a828cd6
--- /dev/null
+++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/mockservice/StubbablePrinterDiscoverySession.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.printspooler.outofprocess.tests.mockservice;
+
+import android.os.CancellationSignal;
+import android.print.PrinterId;
+import android.printservice.CustomPrinterIconCallback;
+import android.printservice.PrintService;
+import android.printservice.PrinterDiscoverySession;
+import android.support.annotation.NonNull;
+
+import java.util.List;
+
+public class StubbablePrinterDiscoverySession extends PrinterDiscoverySession {
+ private final PrintService mService;
+ private final PrinterDiscoverySessionCallbacks mCallbacks;
+
+ public StubbablePrinterDiscoverySession(PrintService service,
+ PrinterDiscoverySessionCallbacks callbacks) {
+ mService = service;
+ mCallbacks = callbacks;
+ if (mCallbacks != null) {
+ mCallbacks.setSession(this);
+ }
+ }
+
+ public PrintService getService() {
+ return mService;
+ }
+
+ @Override
+ public void onStartPrinterDiscovery(@NonNull List<PrinterId> priorityList) {
+ if (mCallbacks != null) {
+ mCallbacks.onStartPrinterDiscovery(priorityList);
+ }
+ }
+
+ @Override
+ public void onStopPrinterDiscovery() {
+ if (mCallbacks != null) {
+ mCallbacks.onStopPrinterDiscovery();
+ }
+ }
+
+ @Override
+ public void onValidatePrinters(@NonNull List<PrinterId> printerIds) {
+ if (mCallbacks != null) {
+ mCallbacks.onValidatePrinters(printerIds);
+ }
+ }
+
+ @Override
+ public void onStartPrinterStateTracking(@NonNull PrinterId printerId) {
+ if (mCallbacks != null) {
+ mCallbacks.onStartPrinterStateTracking(printerId);
+ }
+ }
+
+ @Override
+ public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
+ @NonNull CancellationSignal cancellationSignal,
+ @NonNull CustomPrinterIconCallback callback) {
+ if (mCallbacks != null) {
+ mCallbacks.onRequestCustomPrinterIcon(printerId, cancellationSignal, callback);
+ }
+ }
+
+ @Override
+ public void onStopPrinterStateTracking(@NonNull PrinterId printerId) {
+ if (mCallbacks != null) {
+ mCallbacks.onStopPrinterStateTracking(printerId);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mCallbacks != null) {
+ mCallbacks.onDestroy();
+ }
+ }
+}
diff --git a/packages/SettingsLib/res/layout/restricted_switch_preference.xml b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
index 89dc10b..bb1d906 100644
--- a/packages/SettingsLib/res/layout/restricted_switch_preference.xml
+++ b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
@@ -20,7 +20,7 @@
android:gravity="center_vertical"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:background="?android:attr/activatedBackgroundIndicator"
+ android:background="?android:attr/selectableItemBackground"
android:clipToPadding="false">
<LinearLayout
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 81af941..295248c 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-verbinding het misluk"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Stawingsprobleem"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nie binne ontvangs nie"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Sal nie outomaties koppel nie"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Geen internettoegang nie"</string>
<string name="saved_network" msgid="4352716707126620811">"Gestoor deur <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Gekoppel via Wi-Fi-assistent"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Gekoppel via %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Wys snitgrense, kantlyne, ens."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Dwing RTL-uitlegrigting"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Dwing skermuitlegrigting na RTL vir alle locales"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Wys CPU-verbruik"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skermlaag wys huidige CPU-gebruik"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Forseer GPU-lewering"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Dwing gebruik van GPU vir 2D-tekening"</string>
<string name="force_msaa" msgid="7920323238677284387">"Dwing 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 792c434..bb50087 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"የWiFi ግንኙነት መሰናከል"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"የማረጋገጫ ችግር"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"በክልል ውስጥ የለም"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"በራስ-ሰር አይገናኝም"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"ምንም የበይነመረብ መዳረሻ ያለም"</string>
<string name="saved_network" msgid="4352716707126620811">"የተቀመጠው በ<xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"በWi‑Fi ረዳት አማካኝነት ተገናኝቷል"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"በ%1$s በኩል መገናኘት"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"የቅንጥብ ገደቦች፣ ጠርዞች፣ ወዘተ አሳይ"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"የቀኝ-ወደ-ግራ አቀማመጥ አቅጣጫ አስገድድ"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ለሁሉም አካባቢዎች የማያ ገጽ አቀማመጥ ከቀኝ-ወደ-ግራ እንዲሆን አስገድድ"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"የCPU አጠቃቀም አሳይ"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"የማያ ተደራቢ የአሁኑን የCPU አጠቃቀም እያሳየ ነው።"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU ምላሽ መስጠትን አስገድድ"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"ለ2-ልኬት መሳል የGPU ስራ አስገድድ"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA አስገድድ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index db9afee..829123c 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"أخفق اتصال WiFi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"حدثت مشكلة في المصادقة"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"ليست في النطاق"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"لن يتم الاتصال تلقائيًا"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"لا يتوفر اتصال بالإنترنت"</string>
<string name="saved_network" msgid="4352716707126620811">"تم الحفظ بواسطة <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"تم التوصيل عبر مساعد Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"تم الاتصال عبر %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"عرض حدود وهوامش المقطع وما إلى ذلك."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"فرض اتجاه التنسيق ليكون من اليمين إلى اليسار"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"فرض اتجاه تنسيق الشاشة ليكون من اليمين إلى اليسار لجميع اللغات"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"عرض استخدام CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"عرض تراكب الشاشة لاستخدام CPU الحالي"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"فرض عرض رسومات GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"فرض استخدام وحدة معالجة الرسومات للرسم ثنائي الأبعاد"</string>
<string name="force_msaa" msgid="7920323238677284387">"فرض 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 130cd75..483770f 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi Bağlantı Uğursuzluğu"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikasiya problemi"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Diapazonda deyil"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Avtomatik qoşulmayacaq"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"İnternet girişi yoxdur"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tərəfindən saxlandı"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi köməkçisi vasitəsilə qoşulub"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s vasitəsilə qoşuludur"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Klip sərhədləri, boşluqları və s. göstər"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL düzən istiqamətinə məcbur edin"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Ekran düzən istiqamətini RTL üzərinə bütün yerli variantlar üçün məcbur edin"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU istifadəsini göstər"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ekran örtüşməsi cari CPU istifadəsini göstərir"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU renderə məcbur edin"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2d rəsm üçün GPU məcburi istifadə"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA məcbur edin"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 5d7e852..5498580a 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi veza je otkazala"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem sa potvrdom autentičnosti"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u opsegu"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Automatsko povezivanje nije uspelo"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Sačuvao/la je <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Povezano preko Wi‑Fi pomoćnika"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Veza je uspostavljena preko pristupne tačke %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Prikaži granice klipa, margine itd."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Nametni smer rasporeda zdesna nalevo"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Nametni smer rasporeda ekrana zdesna nalevo za sve lokalitete"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Prik. upotrebu procesora"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Postav. element sa trenutnom upotrebom procesora"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Prinudni prikaz pom. GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Prinudno koristi GPU za 2D crtanje"</string>
<string name="force_msaa" msgid="7920323238677284387">"Nametni 4x MSAA"</string>
@@ -285,7 +281,7 @@
<string name="enable_webview_multiprocess_desc" msgid="2485604010404197724">"Pokrećite WebView prikazivače zasebno"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Primena WebView-a"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesite primenu WebView-a"</string>
- <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više nije važeći. Pokušajte ponovo."</string>
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više nije važeći. Probajte ponovo."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Konvertuj u šifrovanje datoteka"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Konvertuj..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Već se koristi šifrovanje datoteka"</string>
diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml
index a8428f2..f233db9 100644
--- a/packages/SettingsLib/res/values-be-rBY/strings.xml
+++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Збой падлучэння Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Праблема аўтэнтыфікацыі"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Не ў зоне дасягальнасці"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Не будзе аўтаматычна падключацца"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Няма доступу да інтэрнэту"</string>
<string name="saved_network" msgid="4352716707126620811">"Хто захаваў: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Падлучана праз памочніка Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Падлучана праз %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Паказаць межы кліпу, палі і г. д."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Прымусовая раскладка справа налева"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Прымусовая раскладка экрана справа налева для ўсіх рэгіянальных налад"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Паказаць выкарыстанне ЦП"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Наклад на экран з бягучым выкарыстаннем працэсара"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Прымусовае адлюстраванне GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Прымусовае выкарыстанне GPU для 2-мерных чарцяжоў"</string>
<string name="force_msaa" msgid="7920323238677284387">"Прымусовае выкананне 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index b356766..cd77792 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Неуспешна връзка с Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем при удостоверяването"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Извън обхват"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Няма да се свърже автоматично"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Няма достъп до интернет"</string>
<string name="saved_network" msgid="4352716707126620811">"Запазено от <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Установена е връзка чрез помощника за Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Установена е връзка през „%1$s“"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Показв. на границите на изрязване, полетата и др."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Принуд. оформл. отдясно наляво"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Принуд. оформл. на екрана отдясно наляво за вс. локали"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Употреба на процесора"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Наслагване на екрана показва употр. на процесора"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Принудително изобразяване"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Принуд. използв. на GPU за двуизмерно начертаване"</string>
<string name="force_msaa" msgid="7920323238677284387">"Задаване на 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index 4089562..a011fcf 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi সংযোগের ব্যর্থতা"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"প্রমাণীকরণ সমস্যা"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"পরিসরের মধ্যে নয়"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"স্বয়ংক্রিয়ভাবে সংযোগ করবে না"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"কোনো ইন্টারনেট অ্যাক্সেস নেই"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> দ্বারা সংরক্ষিত"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"ওয়াই-ফাই সহায়ক-এর মাধ্যমে সংযুক্ত হয়েছে"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s মাধ্যমে সংযুক্ত হয়েছে"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"ক্লিপ বাউন্ড, মার্জিন ইত্যাদি দেখান"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL লেআউট দিকনির্দেশ জোর দিন"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"সমস্ত স্থানের জন্য RTL এ স্ক্রীন লেআউট দিকনির্দেশে জোর দেয়"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU এর ব্যবহার দেখান"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"স্ক্রীন ওভারলে বর্তমান CPU ব্যবহার দেখাচ্ছে"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"জোর করে GPU রেন্ডারিং করুন"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2D অঙ্কনের জন্য GPU-এর ব্যবহারে জোর দিন"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA এ জোর দিন"</string>
diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
index 5115bbd..1df5ec9 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Greška pri povezivanju na Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem pri provjeri vjerodostojnosti."</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u dometu"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Neće se automatski povezati"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Sačuvao <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Povezani preko Wi-Fi pomoćnika"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Povezani preko %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Prikaži granice isječka, margine itd."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Prisilno postavi raspored s desna u lijevo"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Prisilno postavi raspored ekrana s desna u lijevo za sve regije"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Prikaži korištenje CPU-a"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Trenutno korištenje CPU-a prikazuje se u nadsloju preko ekrana"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Prisili GPU iscrtavanje"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Prisilno koristite GPU za 2d crtanje"</string>
<string name="force_msaa" msgid="7920323238677284387">"Prinudno primjeni 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index abc9390..92e9005 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de connexió Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema d\'autenticació"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fora de l\'abast"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"No es connectarà automàticament"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"No hi ha accés a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Desat per <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Connectat mitjançant l\'assistent de Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Connectada mitjançant %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Mostra els límits de clips, els marges, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Força direcció dreta-esquerra"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Força direcció de pantalla dreta-esquerra en totes les llengües"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Mostra l\'ús de la CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superposa l\'ús de la CPU a la pantalla"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Força acceleració GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Força l\'ús de GPU per a dibuixos en 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Força MSAA 4x"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index edc53ed..8ec531c 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Selhání připojení Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problém s ověřením"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Připojení nebude automaticky navázáno"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Nebyl zjištěn žádný přístup k internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Uloženo uživatelem <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Připojeno pomocí asistenta připojení Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Připojeno prostřednictvím %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Zobrazit u výstřižku ohraničení, okraje atd."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Vynutit rozvržení zprava doleva"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Vynutit ve všech jazycích rozvržení obrazovky zprava doleva"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Zobrazit využití CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Překryvná vrstva s aktuálním využitím procesoru"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Vykreslování pomocí GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Vynutit použití GPU pro 2D vykreslování"</string>
<string name="force_msaa" msgid="7920323238677284387">"Vynutit 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 5714901..a65c58f 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-forbindelsesfejl"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem med godkendelse"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ikke inden for rækkevidde"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Der oprettes ikke automatisk forbindelse"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Ingen internetadgang"</string>
<string name="saved_network" msgid="4352716707126620811">"Gemt af <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Forbindelse via Wi-Fi-assistent"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Tilsluttet via %1$s"</string>
@@ -154,7 +152,7 @@
<string name="clear_adb_keys" msgid="4038889221503122743">"Tilbagekald tilladelser for USB-fejlfinding"</string>
<string name="bugreport_in_power" msgid="7923901846375587241">"Genvej til fejlrapporting"</string>
<string name="bugreport_in_power_summary" msgid="1778455732762984579">"Vis en knap til oprettelse af fejlrapporter i menu for slukknap"</string>
- <string name="keep_screen_on" msgid="1146389631208760344">"Undgå dvale"</string>
+ <string name="keep_screen_on" msgid="1146389631208760344">"Lås ikke"</string>
<string name="keep_screen_on_summary" msgid="2173114350754293009">"Skærmen går ikke i dvale under opladning"</string>
<string name="bt_hci_snoop_log" msgid="3340699311158865670">"Aktivér Bluetooth HCI snoop log"</string>
<string name="bt_hci_snoop_log_summary" msgid="730247028210113851">"Gem alle Bluetooth HCI-pakker i en fil"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Vis grænser for klip, margener osv."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Tving læsning mod venstre"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tving til højre mod venstre-layout for alle sprog"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Vis CPU-forbrug"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skærmoverlejring viser det aktuelle CPU-forbrug"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Tving gengivelse af GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Gennemtving brug af GPU til 2D-tegning"</string>
<string name="force_msaa" msgid="7920323238677284387">"Tving 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 406523e..923eca1 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WLAN-Verbindungsfehler"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentifizierungsproblem"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nicht in Reichweite"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Kein automatischer Verbindungsaufbau"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Kein Internetzugriff"</string>
<string name="saved_network" msgid="4352716707126620811">"Gespeichert von <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Über WLAN-Assistenten verbunden"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Über %1$s verbunden"</string>
@@ -41,7 +39,7 @@
<string name="bluetooth_disconnecting" msgid="8913264760027764974">"Verbindung wird getrennt..."</string>
<string name="bluetooth_connecting" msgid="8555009514614320497">"Verbindung wird hergestellt..."</string>
<string name="bluetooth_connected" msgid="6038755206916626419">"Verbunden"</string>
- <string name="bluetooth_pairing" msgid="1426882272690346242">"Pairing läuft…"</string>
+ <string name="bluetooth_pairing" msgid="1426882272690346242">"Kopplung läuft…"</string>
<string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Verbunden (kein Telefon)"</string>
<string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Verbunden (außer Audiomedien)"</string>
<string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Verbunden (ohne Nachrichtenzugriff)"</string>
@@ -72,12 +70,12 @@
<string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Für Audiosystem des Telefons verwenden"</string>
<string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Für Dateiübertragung verwenden"</string>
<string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Für Eingabe verwenden"</string>
- <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pairing durchführen"</string>
- <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"Pairing durchführen"</string>
+ <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Koppeln"</string>
+ <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"KOPPELN"</string>
<string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Abbrechen"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Über das Pairing kann auf deine Kontakte und auf deinen Anrufverlauf zugegriffen werden, wenn eine Verbindung besteht."</string>
- <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich."</string>
- <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich, weil die eingegebene PIN oder der Zugangscode falsch ist."</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Über die Kopplung kann auf deine Kontakte und auf deinen Anrufverlauf zugegriffen werden, wenn eine Verbindung besteht."</string>
+ <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Kopplung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich."</string>
+ <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Kopplung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich, weil die eingegebene PIN oder der Zugangscode falsch ist."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kommunikation mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ist nicht möglich."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Verbindung wurde von <xliff:g id="DEVICE_NAME">%1$s</xliff:g> abgelehnt."</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"WLAN: aus"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Clip-Begrenzungen, Ränder usw. anzeigen"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL-Layout erzwingen"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"RTL-Bildschirmlayout für alle Sprachen erzwingen"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-Auslastung anzeigen"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Bildschirm-Overlay mit aktueller CPU-Auslastung"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU-Rendering erzwingen"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Einsatz von GPU für 2D-Zeichnung erzwingen"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA erzwingen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 117b9fe..017fff8 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Αποτυχία σύνδεσης Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Πρόβλημα ελέγχου ταυτότητας"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Εκτός εμβέλειας"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Δεν θα συνδεθεί αυτόματα"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Δεν υπάρχει πρόσβαση στο διαδίκτυο"</string>
<string name="saved_network" msgid="4352716707126620811">"Αποθηκεύτηκε από <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Σύνδεση μέσω βοηθού Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Συνδέθηκε μέσω %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Εμφάνιση ορίων κλιπ, περιθωρίων, κλπ."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Επιβολή κατ. διάταξης RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Επιβολή διάταξης οθόν. RTL για όλες τις τοπ. ρυθμ."</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Προβολή χρήσης CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Επικάλυψη οθόνης για προβολή τρέχουσας χρήσης CPU"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Αναγκαστική απόδοση GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Αναγκαστική χρήση του GPU για σχέδιο 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Αναγκαστικά 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 35ec15b..8ed7444 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Won\'t automatically connect"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"No Internet access"</string>
<string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Show clip bounds, margins, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout direction"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout direction to RTL for all locales"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Show CPU usage"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Screen overlay showing current CPU usage"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Force GPU rendering"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Force use of GPU for 2D drawing"</string>
<string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 35ec15b..8ed7444 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Won\'t automatically connect"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"No Internet access"</string>
<string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Show clip bounds, margins, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout direction"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout direction to RTL for all locales"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Show CPU usage"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Screen overlay showing current CPU usage"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Force GPU rendering"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Force use of GPU for 2D drawing"</string>
<string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 35ec15b..8ed7444 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Won\'t automatically connect"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"No Internet access"</string>
<string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Show clip bounds, margins, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout direction"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout direction to RTL for all locales"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Show CPU usage"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Screen overlay showing current CPU usage"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Force GPU rendering"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Force use of GPU for 2D drawing"</string>
<string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 2874e61..cdfbc01 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de conexión Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticación"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de alcance"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"No se conectará automáticamente"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"No se detectó acceso a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Guardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Conexión por asistente de Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conexión a través de %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar límites de recortes, márgenes, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forzar diseño der. a izq."</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forzar diseño pantalla der.>izq., cualquier idioma"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar el uso de CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Mostrar superposición en pantalla con uso actual de la CPU"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Forzar representación GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Forzar uso de GPU para dibujar en 2d"</string>
<string name="force_msaa" msgid="7920323238677284387">"Forzar MSAA 4x"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index 7d0097a..2a21d22 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de conexión Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Error de autenticación"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de rango"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"No se establecerá conexión automáticamente"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"No se ha detectado acceso a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Guardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Conectado a través de asistente Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar límites de vídeo, márgenes, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forzar dirección diseño RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forzar dirección (RTL) para todas configuraciones"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar uso de la CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Suporponer el uso de la CPU en la pantalla"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Forzar aceleración GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Forzar uso de GPU para dibujos en 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Forzar MSAA 4x"</string>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index 97fe73f..644bf59 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-ühenduse viga"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentimise probleem"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Pole vahemikus"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Automaatselt ei ühendata"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Interneti-ühendus puudub"</string>
<string name="saved_network" msgid="4352716707126620811">"Salvestas: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Ühendatud WiFi-abi kaudu"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Ühendatud üksuse %1$s kaudu"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Kuva klipi piirid, veerised jms"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Paremalt vasakule paig."</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Määra lokaatides ekraanipaig. paremalt vasakule"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-kasutuse kuvamine"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Praegust CPU-kasutust kuvav ekraani ülekate"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Jõusta GPU renderdamine"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Jõusta GPU kasutam. kahemõõtmeliste jooniste puhul"</string>
<string name="force_msaa" msgid="7920323238677284387">"Jõusta 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index 9234f24..2217611 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ezin izan da konektatu Wi-Fi sarera"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikazio-arazoa"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Urrunegi"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Ez da konektatuko automatikoki"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Ezin da konektatu Internetera"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioak gorde du"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi laguntzailearen bidez konektatuta"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s bidez konektatuta"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Erakutsi kliparen mugak, marjinak, etab."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Behartu eskuin-ezker norabidea."</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Behartu pantaila-diseinuaren norabidea eskuin-ezker izatera eskualdeko ezarpen guztiekin."</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Erakutsi PUZ erabilera"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"PUZ erabilera erakusten duen pantaila-gainjartzea"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Behartu GPU errendatzea"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Behartu GPUa erabiltzera 2 dimentsioko marrazkietan."</string>
<string name="force_msaa" msgid="7920323238677284387">"Behartu 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index bb2e166..88ed7fa 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"اتصال Wi-Fi برقرار نشد"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"مشکل احراز هویت"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"در محدوده نیست"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"اتصال بهصورت خودکار انجام نمیشود"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"دسترسی به اینترنت وجود ندارد"</string>
<string name="saved_network" msgid="4352716707126620811">"ذخیرهشده توسط <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"متصل شده از طریق دستیار Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"متصل از طریق %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"نمایش مرزها، حاشیهها و ویژگیهای دیگر کلیپ."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"اجباری کردن چیدمان RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"اجباری کردن چیدمان RTL صفحه برای همه زبانها"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"نمایش میزان استفاده از CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"همپوشانی صفحهنمایش میزان استفاده از CPU فعلی"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"پردازش اجباری GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"استفاده اجباری از GPU برای طراحی دوم"</string>
<string name="force_msaa" msgid="7920323238677284387">"اجبار 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index c04c970..d26fc05 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-yhteysvirhe"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Todennusvirhe"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ei kantoalueella"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Yhteyttä ei muodosteta automaattisesti"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Ei internetyhteyttä"</string>
<string name="saved_network" msgid="4352716707126620811">"Tallentaja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Yhteys muodostettu Wi‑Fi-apurin kautta"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Yhdistetty seuraavan kautta: %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Näytä leikkeiden rajat, marginaalit jne."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Pakota RTL-ulkoasun suunta"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Pakota kaikkien kielten näytön ulkoasun suunnaksi RTL"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Näytä suorittimen käyttö"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Näytön peittokuva näyttää nykyisen suoritinkäytön"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Pakota GPU-hahmonnus"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Käytä GPU:ta 2d-piirtämiseen"</string>
<string name="force_msaa" msgid="7920323238677284387">"Pakota 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 1b34904..caad889 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Échec de connexion Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problème d\'authentification"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Reconnexion automatique impossible"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Aucun accès à Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Enregistrés par <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Connecté à l\'aide de l\'assistant Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté par %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Afficher les limites, les marges de clip, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forcer orient. : g. à d."</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forcer l\'orientation: g. à droite (toutes langues)"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Afficher mém. CPU utilisée"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superposition écran indiquant mémoire CPU utilisée"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Forcer le rendu GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Forcer l\'utilisation du GPU pour le dessin 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Forcer MSAA 4x"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 07398f3..91bbaf0 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Échec de la connexion Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problème d\'authentification."</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Reconnexion automatique impossible"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Aucun accès à Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Enregistré par <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Connecté via l\'assistant Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté via %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Afficher les limites de coupe, les marges, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forcer droite à gauche"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forcer orient. droite à gauche pour toutes langues"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Afficher mém. CPU utilisée"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superposition écran indiquant mémoire CPU utilisée"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Forcer le rendu GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Forcer l\'utilisation du GPU pour le dessin 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Forcer MSAA 4x"</string>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index 5207a73..b717382 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Erro na conexión wifi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticación"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Non está dentro da zona de cobertura"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Non se conectará automaticamente"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Non hai acceso a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Redes gardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Conectado ao asistente de wifi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Mostra os límites dos clips, as marxes, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forzar dirección do deseño RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forza a dirección de pantalla a RTL (dereita a esquerda) para todas as configuración rexionais"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar uso da CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Superpoñer o uso da CPU na pantalla"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Forzar procesamento GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Forzar o uso de GPU para o debuxo en 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Forzar MSAA 4x"</string>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 3d0a02b..5605189 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi કનેક્શન નિષ્ફળ"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"પ્રમાણીકરણ સમસ્યા"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"રેન્જમાં નથી"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"આપમેળે કનેક્ટ કરશે નહીં"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા સચવાયું"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi સહાયક દ્વારા કનેક્ટ થયું"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"ક્લિપ બાઉન્ડ્સ, હાંસિયાં વગેરે બતાવો."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL લેઆઉટ દિશા નિર્દેશની ફરજ પાડો"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"તમામ લૉકેલ્સ માટે સ્ક્રીન લેઆઉટ દિશા નિર્દેશને RTL ની ફરજ પાડો"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU સંગ્રહ બતાવો"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"વર્તમાન CPU વપરાશ દર્શાવતું સ્ક્રીન ઓવરલે"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU રેન્ડરિંગની ફરજ પાડો"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2જા રેખાંકન માટે GPU ના ઉપયોગની ફરજ પાડો"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA ને ફરજ પાડો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 329a670..d579ec4 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"वाईफ़ाई कनेक्शन विफलता"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"रेंज में नहीं"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"अपने आप कनेक्ट नहीं होगा"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"कोई इंटरनेट एक्सेस नहीं"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> के द्वारा सहेजा गया"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"वाई-फ़ाई सहायक के द्वारा कनेक्ट है"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s के द्वारा उपलब्ध"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"क्लिप सीमाएं, मार्जिन, आदि दिखाएं."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL लेआउट दिशा लागू करें"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"सभी भाषाओं के लिए स्क्रीन लेआउट दिशा को RTL रखें"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU उपयोग दिखाएं"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"स्क्रीन ओवरले वर्तमान CPU उपयोग को दिखा रहा है"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"बलपूर्वक GPU रेंडर करें"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ड्रॉइंग के लिए GPU का बलपूर्वक उपयोग करें"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA को बाध्य करें"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 89b0653..94229b1 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Povezivanje s Wi-Fi-jem nije uspjelo"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem u autentifikaciji"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u rasponu"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Neće se povezati automatski"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Spremljeno: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Povezani putem pomoćnika za Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Povezano putem %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Prikazuju se obrubi, margine itd. isječaka."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Nametni zdesna ulijevo"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Nametni smjer zdesna ulijevo za sve zemlje/jezike"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Prikaži upotrebu procesora"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Na zaslonu se prikazuje iskorištenost procesora."</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Nametni GPU renderiranje"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Nametni upotrebu GPU-a za 2D crteže"</string>
<string name="force_msaa" msgid="7920323238677284387">"Nametni 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index c33943a..34f06e5 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-kapcsolati hiba"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Azonosítási probléma"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Hatókörön kívül"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nem csatlakozik automatikusan"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Nincs internet-hozzáférés"</string>
<string name="saved_network" msgid="4352716707126620811">"Mentette: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Csatlakozva Wi‑Fi-segéddel"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Csatlakozva a következőn keresztül: %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Kliphatárok, margók stb. megjelenítése."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Elrendezés jobbról balra"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Elrendezés jobbról balra minden nyelvnél"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-használat mutatása"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Képernyőfedvény a jelenlegi CPU-használattal"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU-megjelenítés"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"GPU használatának kényszerítése 2D rajzhoz"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA kényszerítése"</string>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index 32b0dd6..9428e17 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi կապի ձախողում"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Նույնականացման խնդիր"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ընդգրկույթից դուրս է"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Չի միանա ավտոմատ"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Ինտերնետ կապ չկա"</string>
<string name="saved_network" msgid="4352716707126620811">"Պահել է հետևյալ օգտվողը՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Կապակցված է Wi‑Fi Օգնականի միջոցով"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Կապակցված է %1$s-ի միջոցով"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Ցույց տալ կտրվածքի սահմանները, լուսանցքները և այլն"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Փոխել RTL-ի դասավորության ուղղությունը"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Դարձնել էկրանի դասավորության ուղղությունը դեպի RTL բոլոր լեզուների համար"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Ցույց տալ CPU-ի աշխատանքը"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Էկրանի վերադրումը ցույց է տալիս ընթացիկ CPU օգտագործումը"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Ստիպել GPU-ին մատուցել"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Ստիպողաբար GPU-ի օգտագործում 2-րդ պատկերի համար"</string>
<string name="force_msaa" msgid="7920323238677284387">"Ստիպել 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 33df1fe..a382e37 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kegagalan Sambungan Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Masalah autentikasi"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam jangkauan"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Tidak akan tersambung otomatis"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Tidak ada akses internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Disimpan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Terhubung melalui Asisten Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Terhubung melalui %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Tampilkan batas klip, margin, dll."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Paksa arah tata letak RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Paksa arah tata letak layar RTL untuk semua lokal"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Tampilkan penggunaan CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Hamparan layar menampilkan penggunaan CPU saat ini"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Paksa perenderan GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Paksa penggunaan GPU untuk gambar 2d"</string>
<string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index 8cc408f..44517a8 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-tengingarvilla"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Vandamál við auðkenningu"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ekkert samband"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Mun ekki tengjast sjálfkrafa"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Enginn netaðgangur"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> vistaði"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Tengt í gegnum Wi-Fi aðstoð"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Tengt í gegnum %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Sýna skurðlínur, spássíur o.s.frv."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Þvinga umbrot frá hægri til vinstri"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Þvinga umbrot skjás frá hægri til vinstri fyrir alla tungumálskóða"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Sýna örgjörvanotkun"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skjáyfirlögn sem sýnir núverandi örgjörvanotkun"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Þvinga skjákortsteiknun"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Þvinga notkun skjákorts fyrir tvívíða teikningu"</string>
<string name="force_msaa" msgid="7920323238677284387">"Þvinga 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 0bb26e1..7a32827 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Errore connessione Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema di autenticazione"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fuori portata"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Non verrà eseguita la connessione automatica"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Nessun accesso a Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Salvata da <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Connesso tramite assistente Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Collegato tramite %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Mostra limiti, margini dei clip e così via"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forza direzione layout RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Direzione layout schermo RTL per tutte le lingue"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Mostra utilizzo CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Overlay schermo che mostra l\'uso corrente della CPU"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Forza rendering GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Forza l\'uso della GPU per i disegni 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Forza MSAA 4x"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 7510911..2e85770 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"כשל בחיבור Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"בעיית אימות"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"מחוץ לטווח"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"לא יתבצע חיבור באופן אוטומטי"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"אין גישה לאינטרנט"</string>
<string name="saved_network" msgid="4352716707126620811">"נשמר על ידי <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"מחובר באמצעות אסיסטנט ה-Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"מחובר דרך %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"הצג גבולות קליפ, שוליים וכו\'"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"אלץ כיוון פריסה מימין לשמאל"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"אלץ כיוון פריסת מסך מימין לשמאל עבור כל השפות בכל המקומות"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"הצג את השימוש ב-CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"שכבת-על של מסך שמציגה את השימוש הנוכחי ב-CPU"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"אלץ עיבוד ב-GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"אכוף שימוש ב-GPU לשרטוט דו-מימדי"</string>
<string name="force_msaa" msgid="7920323238677284387">"אלץ הפעלת 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index f657c1e..00e323c 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -28,8 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi接続エラー"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"認証に問題"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"圏外"</string>
- <string name="wifi_no_internet_no_reconnect" msgid="2211781637653149657">"インターネット アクセスを検出できないため、自動的に再接続されません。"</string>
- <string name="wifi_no_internet" msgid="5011955173375805204">"インターネットに接続していません。"</string>
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"自動的に接続されません"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"インターネットに接続していません"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>で保存"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fiアシスタント経由で接続"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s経由で接続"</string>
@@ -234,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"クリップの境界線、マージンなどを表示"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTLレイアウト方向を使用"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"すべての言語/地域で画面レイアウト方向をRTLに設定"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU使用状況を表示"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"現在のCPU使用状況をオーバーレイ表示する"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPUレンダリングを使用"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2D描画にGPUを常に使用する"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAAを適用"</string>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index f349c4f..2b9e8cb 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi კავშირის შეფერხება"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ავთენტიკაციის პრობლემა"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"არ არის დიაპაზონში"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ავტომატურად დაკავშირება ვერ მოხერხდება"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"ინტერნეტთან კავშირი არ არის"</string>
<string name="saved_network" msgid="4352716707126620811">"შენახული <xliff:g id="NAME">%1$s</xliff:g>-ის მიერ"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"დაკავშირებულია Wi-Fi თანაშემწით"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-ით დაკავშირებული"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"კლიპის საზღვრების, მინდვრების ჩვენება და ა.შ."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"მარჯვნიდან მარცხნივ განლაგების მიმართულების იძულება"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ეკრანის RTL მიმართულებაზე იძულება ყველა ლოკალისათვის"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"ცენტრალური პროცესორის ჩატვირთვის ჩვენება"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ეკრანის გადაფარვა აჩვენებს CPU ამჟამინდელ გამოყენებას"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU-აჩქარება"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"GPU-ის ძალით გამოყენება 2d drawing-თვის"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA-ს ჩართვა"</string>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index 1141fca..0037c11 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi байланысының қатесі"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Растау мәселесі"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Аумақта жоқ"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Автоматты қосылмайды"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Интернетпен байланыс жоқ"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> сақтаған"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi көмекшісі арқылы қосылу орындалды"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s арқылы қосылған"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Қию шектерін, жиектерін, т.б көрсету."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Оңнан солға орналасу бағытына реттеу"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Экранның орналасу бағытын барлық тілдер үшін оңнан солға қарату"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU (орталық өңдеу бірлігі) қолданысы"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Экран бетіне ағымдағы CPU қолданысы көрсетіледі"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU рендерингін жылдамдату"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Графикалық процессорды 2d сызбаларына қолдану"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA қолдану"</string>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index 7d1c797..235ea6a 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"ការភ្ជាប់ WiFi បរាជ័យ"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"បញ្ហាក្នុងការផ្ទៀងផ្ទាត់"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"នៅក្រៅតំបន់"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"នឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិទេ"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"មិនមានអ៊ីនធឺណិតទេ"</string>
<string name="saved_network" msgid="4352716707126620811">"បានរក្សាទុកដោយ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"បានភ្ជាប់តាមរយៈជំនួយការ Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"បានភ្ជាប់តាមរយៈ %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"បង្ហាញការភ្ជាប់អត្ថបទសម្រង់ រឹម ។ល។"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"បង្ខំទិសប្លង់ RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"បង្ខំទិសប្លង់អេក្រង់ទៅកាន់ RTL សម្រាប់មូលដ្ឋានទាំងអស់"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"បង្ហាញការប្រើ CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"អេក្រង់ត្រួតគ្នាបង្ហាញការប្រើ CPU បច្ចុប្បន្ន"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"បង្ខំឲ្យបង្ហាញ GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"បង្ខំប្រើ GPU សម្រាប់ការគូរលើកទីពីរ"</string>
<string name="force_msaa" msgid="7920323238677284387">"បង្ខំ 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index 9039e25..b89bad8 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ಸಂಪರ್ಕ ವಿಫಲತೆ"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ಪ್ರಮಾಣೀಕರಣ ಸಮಸ್ಯೆ"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"ವ್ಯಾಪ್ತಿಯಲ್ಲಿಲ್ಲ"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವಿಲ್ಲ"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ರಿಂದ ಉಳಿಸಲಾಗಿದೆ"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi ಸಹಾಯಕದ ಮೂಲಕ ಸಂಪರ್ಕಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"ಕ್ಲಿಪ್ನ ಗಡಿಗಳು, ಅಂಚುಗಳು, ಇತ್ಯಾದಿ ತೋರಿಸು."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ಲೇಔಟ್ ಪರಿಮಿತಿ ಬಲಗೊಳಿಸಿ"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ಎಲ್ಲ ಸ್ಥಳಗಳಿಗಾಗಿ RTL ಗೆ ಸ್ಕ್ರೀನ್ ಲೇಔಟ್ ದಿಕ್ಕನ್ನು ಪ್ರಬಲಗೊಳಿಸಿ"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ಬಳಕೆಯನ್ನು ತೋರಿಸು"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ಪ್ರಸ್ತುತ CPU ಬಳಕೆಯನ್ನು ತೋರಿಸುತ್ತಿರುವ ಪರದೆಯ ಓವರ್ಲೇ"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU ನೀಡುವಿಕೆ ಬಲಗೊಳಿಸು"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ಚಿತ್ರಕಲೆಗಾಗಿ GPU ಬಳಕೆ ಬಲಗೊಳಿಸಿ"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA ಪ್ರಬಲಗೊಳಿಸಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index e33b989..21bbc3f 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi 연결 실패"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"인증 문제"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"범위 내에 없음"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"자동으로 연결되지 않습니다."</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"인터넷에 연결되어 있지 않습니다."</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>(으)로 저장됨"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi 도우미를 통해 연결됨"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s을(를) 통해 연결됨"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"클립 경계, 여백 등을 표시"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL 레이아웃 방향 강제 적용"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"모든 언어에 대해 화면 레이아웃 방향을 RTL로 강제 적용"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU 사용량 표시"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"현재 CPU 사용량 오버레이 표시"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU 렌더링 강제 설정"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2D 드로잉용으로 GPU 강제 사용"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA 강제 사용"</string>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index 22622dd..ca716cae 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi туташуусу бузулду"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Аутентификация маселеси бар"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Тейлөө аймагында эмес"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Автоматтык түрдө туташпайт"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Интернетке туташпай турат"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> тарабынан сакталды"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi жардамчысы аркылуу туташып турат"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s аркылуу жеткиликтүү"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Клиптин чектерин, талааларын ж.б. көргөзүү"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Солдон оңго багытына мажбурлоо"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Экрандын жайгашуу багытын бардык тилдер үчүн Оңдон-солго кылуу"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU колдонулушун көрсөтүү"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Учурдагы CPU колдонулушун көрсөтүүчү экран катмары"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU иштетүүсүн мажбурлоо"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2d тартуу үчүн GPU\'ну колдонууга мажбурлоо"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA мажбурлоо"</string>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index 716ee6f..0108c2c 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"ການເຊື່ອມຕໍ່ WiFi ລົ້ມເຫຼວ"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ບັນຫາການພິສູດຢືນຢັນ"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"ບໍ່ຢູ່ໃນໄລຍະທີ່ເຊື່ອມຕໍ່ໄດ້"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ຈະບໍ່ເຊື່ອມຕໍ່ອັດຕະໂນມັດ"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
<string name="saved_network" msgid="4352716707126620811">"ບັນທຶກໂດຍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"ເຊື່ອມຕໍ່ຜ່ານ Wi‑Fi ຕົວຊ່ວຍແລ້ວ"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"ເຊື່ອມຕໍ່ຜ່ານ %1$s ແລ້ວ"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"ສະແດງໜ້າປົກຄລິບ, ຂອບ ແລະອື່ນໆ."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"ບັງຄັບໃຫ້ຮູບຮ່າງຂຽນຈາກຂວາຫາຊ້າຍ"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ບັງຄັບໃຫ້ຮູບຮ່າງໜ້າຈໍ ຂຽນຈາກຂວາໄປຊ້າຍ ສຳລັບທຸກພາສາ"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"ສະແດງການນຳໃຊ້ CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ການວາງຊ້ອນໜ້າຈໍທີ່ສະແດງການນຳໃຊ້ CPU ໃນປັດຈຸບັນ"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"ບັງຄັບໃຊ້ GPU ປະມວນພາບ"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"ບັງຄັບໃຊ້ GPU ເພື່ອການແຕ້ມພາບ 2 ມິຕິ"</string>
<string name="force_msaa" msgid="7920323238677284387">"ບັງຄັບໃຊ້ 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 167e756..154864f 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"„Wi-Fi“ ryšio triktis"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikavimo problema"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ne diapazone"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nebus automatiškai prisijungiama"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Nėra interneto ryšio"</string>
<string name="saved_network" msgid="4352716707126620811">"Išsaugojo <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Prisijungta naudojant „Wi‑Fi“ pagelbiklį"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Prisijungta naudojant „%1$s“"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Rodyti iškarpų ribas, kraštines ir t. t."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Išdėst. iš dešin. į kairę"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Nust. visų lokalių ekran. išdėst. iš deš. į kairę"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Rodyti centr. proc. naud."</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ekrano perdanga rodo dabartinį centr. proc. naud."</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Priverst. GPU atvaizd."</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Priverstinai naudoti GPU atvaizduojant 2D formatą"</string>
<string name="force_msaa" msgid="7920323238677284387">"Priverst. vykdyti 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 7f5e111..df91cb1 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi savienojuma kļūme"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentificēšanas problēma"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nav diapazona ietvaros"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Savienojums netiks izveidots automātiski"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Nav piekļuves internetam"</string>
<string name="saved_network" msgid="4352716707126620811">"Saglabāja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Izveidots savienojums ar Wi‑Fi palīgu"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Savienots, izmantojot %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Rādīt klipu robežas, malas utt."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Virziens no labās uz kreiso (Obligāts) WL: 295"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Obl. izkārt. virz. no labās uz kr. pusi visām lok."</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Rādīt CPU lietojumu"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ekrāna pārklājums ar aktuālo CPU lietojumu"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Piespiedu GPU render."</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Izmantot GPU atveidi divdimensiju zīmējumiem"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA piespiedu palaiš."</string>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index 2a454d2..42bc33f 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Поврзувањето преку Wi-Fi не успеа"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем со автентикација"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Надвор од опсег"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Не може да се поврзе автоматски"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Нема пристап до Интернет"</string>
<string name="saved_network" msgid="4352716707126620811">"Зачувано од <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Поврзано преку помошник за Wi-Fismile"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Поврзано преку %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Прикажи граници на клип, маргини, итн."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Сила на RTL за насока на слој"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Присилно постави насока на распоред на екран во РТЛ за сите локални стандарди"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Прикажи употреба на ЦПУ"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Прекривка на екран прикаж. употреба на тековен ЦПУ"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Присили рендерирање на GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Присилно користење на GPU за цртеж 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Сила 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index 56d1477..a6017d5 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi കണക്ഷൻ പരാജയം"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ആധികാരികമാക്കുന്നതിലെ പ്രശ്നം"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"പരിധിയിലില്ല"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"സ്വയമേവ കണക്റ്റുചെയ്യില്ല"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"ഇന്റർനെറ്റ് ആക്സസ്സ് ഇല്ല"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> സംരക്ഷിച്ചത്"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"വൈഫൈ അസിസ്റ്റന്റ് മുഖേന കണക്റ്റുചെയ്തു"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s വഴി ബന്ധിപ്പിച്ചു"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"ക്ലിപ്പ് ബൗണ്ടുകൾ, മാർജിനുകൾ തുടങ്ങിയവ ദൃശ്യമാക്കുക"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ലേഔട്ട് ഡയറക്ഷൻ നിർബന്ധമാക്കുക"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"എല്ലാ ഭാഷകൾക്കുമായി സ്ക്രീൻ ലേഔട്ട് ഡയറക്ഷൻ RTL-ലേക്ക് നിർബന്ധമാക്കുക"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ഉപയോഗം ദൃശ്യമാക്കുക"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"സ്ക്രീൻ ഓവർലേ നിലവിലെ CPU ഉപയോഗം ദൃശ്യമാക്കുന്നു"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU റെൻഡറിംഗ് ഫോഴ്സ്ചെയ്യുക"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ഡ്രോയിംഗിനായുള്ള നിരബന്ധിത GPU ഉപയോഗം"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA നിർബന്ധമാക്കുക"</string>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index 9848cae..cb6327a 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi холболт амжилтгүй"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Гэрчлэлийн асуудал"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Хүрээнд байхгүй"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Автоматаар холбогдохгүй"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Интернэт холболт алга"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> хадгалсан"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi туслагчаар дамжуулан холбогдлоо"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-р холбогдсон"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Клипийн зах, хязгаар зэргийг харуулах"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL байрлалын чиглэлийг хүчээр тогтоох"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Бүх локалын хувьд дэлгэцийн байрлалын чиглэлийг хүчээр RTL болгох"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ашиглалтыг харуулах"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Дэлгэцийн давхцалаар одоогийн CPU ашиглалтыг харуулж байна"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Хүчээр GPU ашиглах"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"GPU-г 2d зурагт хүчээр ашиглах"</string>
<string name="force_msaa" msgid="7920323238677284387">"Хүчээр 4x MSAA ашиглах"</string>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index 83ae663..b6adb4f 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi कनेक्शन अयशस्वी"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"परिक्षेत्रामध्ये नाही"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"स्वयंचलितपणे कनेक्ट करणार नाही"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"इंटरनेट प्रवेश नाही"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे जतन केले"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi सहाय्यक द्वारे कनेक्ट केले"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s द्वारे कनेक्ट केले"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"क्लिप सीमा, समास इत्यादी दर्शवा."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL लेआउट दिशानिर्देशाची सक्ती करा"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"सर्व लोकॅलसाठी RTL स्क्रीन लेआउट दिशानिर्देशाची सक्ती करा"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU वापर दर्शवा"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"वर्तमान CPU वापर दर्शविणारे स्क्रीन आच्छादन"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU प्रस्तुतीस सक्ती करा"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2d रेखांकनासाठी GPU च्या वापराची सक्ती करा"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA ची सक्ती करा"</string>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index 217d82a..9886d3e 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kegagalan Sambungan WiFi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Masalah pengesahan"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam liputan"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Tidak akan menyambung secara automatik"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Tiada akses Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Diselamatkan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Disambungkan melalui Pembantu Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Disambungkan melalui %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Tunjukkan batas klip, margin dll."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Paksa arah reka letak RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Paksa arah reka letak skrin RTL bagi semua tempat peristiwa"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Tunjukkan penggunaan CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Tindihan skrin menunjukkan penggunaan semasa CPU"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Paksa pemaparan GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Paksa penggunaan GPU untuk lukisan 2d"</string>
<string name="force_msaa" msgid="7920323238677284387">"Paksa 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index fc977a9..935ad40 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ချိတ်ဆက်မှု မအောင်မြင်ပါ"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"စစ်မှန်ကြောင်းအတည်ပြုရန်၌ ပြသနာရှိခြင်း"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"စက်ကွင်းထဲတွင် မဟုတ်ပါ"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"အလိုအလျောက်ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"အင်တာနက် ချိတ်ဆက်မှု မရှိပါ"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> မှသိမ်းဆည်းခဲ့သည်"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"ကြိုးမဲ့ကူညီသူမှတဆင့် ချိတ်ဆက်၏"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"ဖြတ်ပိုင်းအနားသတ်များ၊ အနားများ စသဖြင့် ပြပါ။"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ဖွဲ့စည်းပုံအညွှန်း မဖြစ်မနေလုပ်ပါ"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"လိုကယ်လ်အားလုံးအတွက် မျက်နှာပြင် ဖွဲ့စည်းပုံအညွှန်း မဖြစ်မနေလုပ်ရန်"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPUအသုံးပြုမှုအား ပြသရန်"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"လက်ရှိCPUအသုံးပြုမှုအားလုံး မျက်နှာပြင်တွင်ပြသမှု"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPUအား အတင်းအကျပ်ဖြစ်စေမည်"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"GPUကို ၂ဖက်မြင်ပုံဆွဲခြင်းအတွက် မဖြစ်မနေအသုံးပြုစေရန်"</string>
<string name="force_msaa" msgid="7920323238677284387">"တွန်းအား ၄× MSAA"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index bd6ae05..18b6f60 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-tilkoblingsfeil"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentiseringsproblem"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Utenfor område"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Kobler ikke til automatisk"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Ingen Internett-tilgang"</string>
<string name="saved_network" msgid="4352716707126620811">"Lagret av <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Koblet til via en Wi-Fi-assistent"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Tilkoblet via %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Vis kanter, marger osv."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Tving layoutretning for RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tving RTL-retning på skjermen for alle språk"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Vis CPU-bruk"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Skjermoverlegg viser gjeldende CPU-bruk"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Tving GPU-gjengivelse"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Tving bruk av GPU for 2D-tegning"</string>
<string name="force_msaa" msgid="7920323238677284387">"Tving 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index c671f90..478e19d 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"वाईफाई जडान असफल"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"दायराभित्र छैन"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"स्वतः जडान हुने छैन"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"इन्टरनेट माथिको पहुँच छैन"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा सुरक्षित गरियो"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi सहायक द्वारा जोडिएको"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s मार्फत जडित"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"क्लिप सीमा, मार्जिन, इत्यादि देखाउनुहोस्।"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL लेआउट दिशामा जबर्जस्ती गर्नुहोस्"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"सबै लोकेलहरूको लागि RTLमा स्क्रिन लेआउट दिशामा जबर्जस्ती गर्नुहोस्"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU उपयोग देखाउनुहोस्"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"स्क्रिन ओभरले वर्तमान CPU प्रयोग देखाउँदै"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU रेन्डर गर्न जोड गर्नुहोस्"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2d चित्र कोर्नका लागि GPU को प्रयोगलाई जोड दिनुहोस्"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA जोड गर्नुहोस्"</string>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
index e1bc58d..8f73bf9 100644
--- a/packages/SettingsLib/res/values-nl/arrays.xml
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -50,12 +50,12 @@
</string-array>
<string-array name="hdcp_checking_titles">
<item msgid="441827799230089869">"Nooit controleren"</item>
- <item msgid="6042769699089883931">"Alleen controleren op DRM-inhoud"</item>
+ <item msgid="6042769699089883931">"Alleen controleren op DRM-content"</item>
<item msgid="9174900380056846820">"Altijd controleren"</item>
</string-array>
<string-array name="hdcp_checking_summaries">
<item msgid="505558545611516707">"HDCP-controle nooit gebruiken"</item>
- <item msgid="3878793616631049349">"HDCP-controle alleen voor DRM-inhoud gebruiken"</item>
+ <item msgid="3878793616631049349">"HDCP-controle alleen voor DRM-content gebruiken"</item>
<item msgid="45075631231212732">"HDCP-controle altijd gebruiken"</item>
</string-array>
<string-array name="select_logd_size_titles">
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 330eb30..78e1ee1 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wifi-verbinding mislukt"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authenticatieprobleem"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Niet binnen bereik"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Er wordt niet automatisch verbinding gemaakt"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Geen internettoegang"</string>
<string name="saved_network" msgid="4352716707126620811">"Opgeslagen door <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Verbonden via wifi-assistent"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Verbonden via %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Clipgrenzen, marges en meer weergeven"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"V.r.n.l.-indelingsrichting afdwingen"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Schermindelingsrichting geforceerd instellen op v.r.n.l. voor alle talen"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU-gebruik weergeven"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Schermoverlay met huidig CPU-gebruik"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU-rendering afdwingen"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Gebruik van GPU voor 2D-tekening forceren"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA forceren"</string>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index 9826023..b678aac 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ਕਨੈਕਸ਼ਨ ਅਸਫਲਤਾ"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ਪ੍ਰਮਾਣੀਕਰਨ ਸਮੱਸਿਆ"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"ਰੇਂਜ ਵਿੱਚ ਨਹੀਂ ਹੈ"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਕੀਤਾ"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi ਸਹਾਇਕ ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"ਕਲਿਪ ਬਾਊਂਡਸ, ਮਾਰਜਿਨ ਆਦਿ ਦਿਖਾਓ"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL ਲੇਆਉਟ ਦਿਸ਼ਾ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"ਸਾਰੇ ਸਥਾਨਾਂ ਲਈ RTL ਵੱਲ ਸਕ੍ਰੀਨ ਲੇਆਉਟ ਦਿਸ਼ਾ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU ਵਰਤੋਂ ਦਿਖਾਓ"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ਸਕ੍ਰੀਨ ਓਵਰਲੇ ਵਰਤਮਾਨ CPU ਵਰਤੋਂ ਦਿਖਾ ਰਿਹਾ ਹੈ"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU ਪ੍ਰਗਟਾਅ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ਡ੍ਰਾਇੰਗ ਲਈ GPU ਦੀ ਵਰਤੋਂ ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA ਤੇ ਜ਼ੋਰ ਪਾਓ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 4dce1a4..77a23f2 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Błąd połączenia Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem z uwierzytelnianiem"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Poza zasięgiem"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nie można połączyć automatycznie"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Brak dostępu do internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Zapisane przez: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Połączono przez Asystenta Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Połączono przez %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Pokaż granice przycięcia, marginesy itd."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Układ od prawej do lewej"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Wymuś wszędzie układ ekranu od prawej do lewej"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Pokaż użycie procesora"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Nakładka na ekranie pokazująca użycie procesora"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Renderowanie na GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Wymuszaj użycie GPU do rysowania 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Wymuś 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 27332f9..588ca67 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de conexão Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Não se conectará automaticamente"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Sem acesso à Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Salvas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Conectado via assistente de Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar limites de corte, margens, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. layout (RTL)"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar direção do layout (RTL) p/ todas as local."</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar o uso da CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Sobreposição de tela que mostra o uso da CPU atual"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Forçar renderização GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Forçar uso da GPU para desenho em 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index c48ccba..763cb70 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de ligação Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Não é efetuada uma ligação automaticamente"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Sem acesso à Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Ligado através do Assistente de Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Ligado através de %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Apresentar limites de clipes, margens, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. do esq. RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar dir. do esq. do ecrã p. RTL tds os locais"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar utilização da CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Sobrep. de ecrã que mostra a utiliz. atual da CPU"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Forçar composição GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Forçar a utilização de GPU para desenho 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 27332f9..588ca67 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de conexão Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Não se conectará automaticamente"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Sem acesso à Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Salvas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Conectado via assistente de Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Mostrar limites de corte, margens, etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Forçar dir. layout (RTL)"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Forçar direção do layout (RTL) p/ todas as local."</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Mostrar o uso da CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Sobreposição de tela que mostra o uso da CPU atual"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Forçar renderização GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Forçar uso da GPU para desenho em 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Forçar 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 8458557..6a2122a 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Eroare de conexiune Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problemă la autentificare"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"În afara ariei de acoperire"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nu se va conecta automat"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Nu există acces la internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Salvată de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Conexiune realizată printr-un asistent Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Conectată prin %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Afișați limitele clipului, marginile etc."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Direcție aspect dreapta - stânga"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Direcție obligatorie aspect ecran dreapta - stânga"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Afișați utiliz. procesor"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Suprapunere care indică utilizare curentă procesor"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Forțați redarea cu GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Forțați utilizarea GPU pentru desen în 2D"</string>
<string name="force_msaa" msgid="7920323238677284387">"Forțați MSAA 4x"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index a89c553..a6d0cba 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ошибка подключения Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Ошибка аутентификации"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Недоступна"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Подключение не будет выполняться автоматически"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Отсутствует подключение к Интернету"</string>
<string name="saved_network" msgid="4352716707126620811">"Кто сохранил: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Установлено подключение через Ассистента Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Подключено к %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Показывать границы клипа, поля и т. д."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Написание справа налево"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Включить написание справа налево для всех языков"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Показывать загрузку ЦП"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Экран, показывающий текущую загрузку ЦП"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU-ускорение"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Всегда использовать GPU для двухмерного рисования"</string>
<string name="force_msaa" msgid="7920323238677284387">"Включить 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index c8a0bad..e415544 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi සම්බන්ධතාව අසාර්ථකයි"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"සත්යාපනයේ ගැටලුවකි"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"පරාසයේ නැත"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"ස්වයංක්රිය නැවත සම්බන්ධ නොවනු ඇත"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"අන්තර්ජාල ප්රවේශය නැත"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> විසින් සුරකින ලදී"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi සහායක හරහා සම්බන්ධ කරන ලදි"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s හරහා සම්බන්ධ විය"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"ක්ලිප් සීමා, මායිම්, ආදිය පෙන්වන්න."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"බල RTL පිරිසැලසුම් දිශාව"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"සියලු පෙදෙසි සඳහා RTL වෙත බල තිර පිරිසැලසුම"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU භාවිතය පෙන්වන්න"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"තීර උඩැතිරිය වත්මන් CPU භාවිතය පෙන්නුම් කරයි"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU විදහාපෑම බලකරන්න"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2d ඇඳීම් සඳහා GPU බලයෙන් භාවිතා කරන්න"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA බල කරන්න"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 958bae6..7e636fe7 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Zlyhanie pripojenia Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problém s overením totožnosti"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nedôjde k automatickému pripojeniu"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Žiadny prístup k internetu"</string>
<string name="saved_network" msgid="4352716707126620811">"Uložil(a) <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Pripojené pomocou Asistenta Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Pripojené prostredníctvom %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Zobraziť vo výstrižku ohraničenie, okraje a pod."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Rozloženia sprava doľava"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Vynútiť pre všetky jazyky rozloženie obrazovky sprava doľava"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Zobraziť využitie CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Prekryvná vrstva s aktuálnym využitím procesora"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Vykresľovat pomocou GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Používať GPU na dvojrozmerné vykresľovanie"</string>
<string name="force_msaa" msgid="7920323238677284387">"Vynútiť 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index d4ad802..78fa3fd 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Povezava prek Wi-Fi-ja ni uspela"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Težava s preverjanjem pristnosti"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ni v obsegu"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Samodejna vnovična vzpostavitev povezave se ne bo izvedla"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Ni dostopa do interneta"</string>
<string name="saved_network" msgid="4352716707126620811">"Shranil(-a): <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Povezava vzpostavljena prek pomočnika za Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Vzpostavljena povezava prek: %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Pokaži meje obrezovanja, obrobe ipd."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Vsili od desne proti levi"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Vsili smer postavitve na zaslonu od desne proti levi za vse jezike"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Prikaži uporabo CPE-ja"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Prekrivanje zaslona prikazuje tren. uporabo CPE-ja"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Vsili upodabljanje z GPE-jem"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Za risanje 2D vsili uporabo grafičnega procesorja"</string>
<string name="force_msaa" msgid="7920323238677284387">"Vsili 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index ba5d2833..ad4cf61 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Dështim i lidhjes WiFi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem me vërtetimin"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Nuk është brenda rrezes"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nuk do të lidhet automatikisht"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Nuk ka qsaje në internet"</string>
<string name="saved_network" msgid="4352716707126620811">"E ruajtur nga <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"I lidhur nëpërmjet ndihmësit të Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"E lidhur përmes %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Shfaq konturet e klipit, hapësirat etj."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Detyro drejtimin e shkrimit nga e djathta në të majtë"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Ndrysho me detyrim drejtimin e planit të ekranit nga e djathta në të majtë për të gjitha vendet"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Shfaq përdorimin e CPU-së"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Mbivendosja e ekranit tregon përdorimin e CPU-së"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Detyro interpretimin e GPU-së"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Detyro përdorimin e GPU-së për vizatimin e dytë"</string>
<string name="force_msaa" msgid="7920323238677284387">"Detyro 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index b04a4c2..02eb615 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi веза је отказала"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем са потврдом аутентичности"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Није у опсегу"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Аутоматско повезивање није успело"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Нема приступа интернету"</string>
<string name="saved_network" msgid="4352716707126620811">"Сачувао/ла је <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Повезано преко Wi‑Fi помоћника"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Веза је успостављена преко приступне тачке %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Прикажи границе клипа, маргине итд."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Наметни смер распореда здесна налево"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Наметни смер распореда екрана здесна налево за све локалитете"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Прик. употребу процесора"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Постав. елемент са тренутном употребом процесора"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Принудни приказ пом. GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Принудно користи GPU за 2D цртање"</string>
<string name="force_msaa" msgid="7920323238677284387">"Наметни 4x MSAA"</string>
@@ -285,7 +281,7 @@
<string name="enable_webview_multiprocess_desc" msgid="2485604010404197724">"Покрећите WebView приказиваче засебно"</string>
<string name="select_webview_provider_title" msgid="4628592979751918907">"Примена WebView-а"</string>
<string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Подесите примену WebView-а"</string>
- <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Овај избор више није важећи. Покушајте поново."</string>
+ <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Овај избор више није важећи. Пробајте поново."</string>
<string name="convert_to_file_encryption" msgid="3060156730651061223">"Конвертуј у шифровање датотека"</string>
<string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Конвертуј..."</string>
<string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Већ се користи шифровање датотека"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 7562ee0..a936c3e 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-anslutningsfel"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentiseringsproblem"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Utom räckhåll"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Det går inte att ansluta automatiskt"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Ingen internetåtkomst"</string>
<string name="saved_network" msgid="4352716707126620811">"Sparades av <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Ansluten via Wi-Fi-assistent"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Anslutet via %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Visa gränser för videoklipp, marginaler m.m."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Tvinga fram RTL-layout"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tvinga fram RTL-skärmlayout (hö–vä) för alla språk"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Visa CPU-användning"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Överlägg på skärmen med aktuell CPU-användning"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Framtvinga GPU-rendering"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Tvingad användning av GPU för 2D-ritning"</string>
<string name="force_msaa" msgid="7920323238677284387">"Force 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 9e64b91..25f79b6 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Haikuweza Kuunganisha kwenye WiFi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tatizo la uthibitishaji"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Haiko karibu"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Haiwezi kuunganisha kiotomatiki"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Hakuna muunganisho wa Intaneti"</string>
<string name="saved_network" msgid="4352716707126620811">"Ilihifadhiwa na <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Imeunganishwa kupitia Kisaidizi cha Wi-Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Imeunganishwa kupitia %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Onyesha mipaka ya picha, kingo, nk."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Lazimisha uelekezaji wa muundo wa RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Lazimisha uelekezaji wa muundo wa skrini kwa RTL kwa lugha zote"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Onyesha matumizi ya CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Kuegeshwa kwa skrini ikionyesha matumizi ya sasa ya CPU"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Lazimisha kutungiliza GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Lazimisha matumizi ya GPU kwa uchoraji wa 2d"</string>
<string name="force_msaa" msgid="7920323238677284387">"Lazimisha 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index b9ff6bc..9e9e92c 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"வைஃபை இணைப்பில் தோல்வி"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"அங்கீகரிப்புச் சிக்கல்"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"தொடர்பு எல்லையில் இல்லை"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"தானாக இணைக்கப்படாது"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"இணைய அணுகல் இல்லை"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> சேமித்தது"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"வைஃபை அசிஸ்டண்ட் மூலம் இணைக்கப்பட்டது"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s வழியாக இணைக்கப்பட்டது"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"கிளிப் எல்லைகள், ஓரங்கள், மேலும் பலவற்றைக் காட்டு"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL தளவமைப்பின் திசையை வலியுறுத்து"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"எல்லா மொழிகளுக்கும் திரையின் தளவமைப்பு திசையை RTL க்கு மாற்று"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU பயன்பாட்டைக் காட்டு"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"தற்போதைய CPU பயன்பாட்டைக் காட்டும் திரை மேலடுக்கு"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU காட்சியாக்கத்தை வலியுறுத்து"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2d வரைபடத்திற்கு GPU பயன்பாட்டை வலியுறுத்து"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA ஐ வலியுறுத்து"</string>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index 08bcbda..27f8e09 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi కనెక్షన్ వైఫల్యం"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ప్రామాణీకరణ సమస్య"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"పరిధిలో లేదు"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"స్వయంచాలకంగా కనెక్ట్ కాదు"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"ఇంటర్నెట్ ప్రాప్యత లేదు"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా సేవ్ చేయబడింది"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi సహాయకం ద్వారా కనెక్ట్ చేయబడింది"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"క్లిప్ సరిహద్దులు, అంచులు మొ. చూపు"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL లేఅవుట్ దిశను నిర్భందం చేయండి"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"అన్ని లొకేల్ల కోసం RTLకి స్క్రీన్ లేఅవుట్ దిశను నిర్భందించు"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU వినియోగాన్ని చూపు"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"ప్రస్తుత CPU వినియోగాన్ని చూపేలా స్క్రీన్ అతివ్యాప్తి చేయబడుతుంది"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"నిర్బంధంగా GPU భాషాంతరీకరణ"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2d డ్రాయింగ్ కోసం GPU నిర్భంద వినియోగం"</string>
<string name="force_msaa" msgid="7920323238677284387">"నిర్భందం 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index bd9d8d5..6005972 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"การเชื่อมต่อ Wi-Fi ล้มเหลว"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ปัญหาในการตรวจสอบสิทธิ์"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"ไม่อยู่ในพื้นที่ให้บริการ"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"จะไม่เชื่อมต่อโดยอัตโนมัติ"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"ไม่สามารถเข้าถึงอินเทอร์เน็ต"</string>
<string name="saved_network" msgid="4352716707126620811">"บันทึกโดย <xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"เชื่อมต่อผ่านตัวช่วย Wi-Fi อยู่"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"เชื่อมต่อผ่าน %1$s แล้ว"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"แสดงหน้าปกคลิป ขอบ ฯลฯ"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"บังคับทิศทางการจัดวาง RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"บังคับทิศทางการจัดวางหน้าจอเป็น RTL สำหรับทุกภาษา"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"แสดงการใช้ CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"การวางซ้อนหน้าจอที่แสดงการใช้ CPU ในปัจจุบัน"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"เร่งการแสดงผลของ GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"ต้องใช้ GPU สำหรับการวาดภาพ 2 มิติ"</string>
<string name="force_msaa" msgid="7920323238677284387">"บังคับใช้ 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 9c952f5..e9feded 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Pagkabigo ng Koneksyon sa WiFi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema sa pagpapatotoo"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Wala sa sakop"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Hindi awtomatikong kokonekta"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Walang access sa Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Na-save ni <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Nakakonekta sa pamamagitan ng Wi‑Fi assistant"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Nakakonekta sa pamamagitan ng %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Ipakita ang mga hangganan ng clip, margin, atbp."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Force RTL layout dir."</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Force screen layout dir. sa RTL sa lahat ng lokal"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Ipakita paggamit ng CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Ipinapakita ng screen overlay ang paggamit ng CPU ngayon"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Ipilit ang pag-render ng GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Sapilitang paggamit sa GPU para sa 2d na pagguhit"</string>
<string name="force_msaa" msgid="7920323238677284387">"Puwersahin ang 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 889b631..0e73b7b 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kablosuz Bağlantı Hatası"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Kimlik doğrulama sorunu"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Kapsama alanı dışında"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Otomatik olarak bağlanma"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"İnternet erişimi yok"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tarafından kaydedildi"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Kablosuz bağlantı yardımcısıyla bağlandı"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s üzerinden bağlı"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Klip sınırlarını, kenar boşluklarını vb. göster"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Sağdan sola düzenini zorla"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Tüm yerel ayarlar için sağdan sola ekran düzenini zorlar"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU kullanımını göster"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Mevcut CPU kullanımını gösteren yer paylaşımı"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU oluşturmayı zorla"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2D çizimde GPU kullanımını zorla"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA\'yı zorla"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index cdf725f..1015e1c 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Помилка з’єднання Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблема з автентифікацією"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Не в діапазоні"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Не під’єднуватиметься автоматично"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Немає доступу до Інтернету"</string>
<string name="saved_network" msgid="4352716707126620811">"Збережено додатком <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Під’єднано через Диспетчер Wi-Fi-з’єднання"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Під’єднано через %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Показувати межі роликів, поля тощо"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Макет письма справа наліво"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Застосовувати макет письма справа наліво для всіх мов"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Показати використання ЦП"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Показувати на екрані поточне використання ЦП"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Примусова візуалізація GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Примусово використовувати GPU для 2D-малювання"</string>
<string name="force_msaa" msgid="7920323238677284387">"Примус. запустити 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index c5aaaab..61dc5ab 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi کنکشن کی ناکامی"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"توثیق کا مسئلہ"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"رینج میں نہیں ہے"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"خودکار طور پر منسلک نہیں ہو گا"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"انٹرنیٹ تک کوئی رسائی نہیں"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> کی جانب سے محفوظ کردہ"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi اسسٹنٹ کے ذریعے منسلک ہے"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"منسلک بذریعہ %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"کلپ باؤنڈز، حاشیے وغیرہ دکھائیں"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"RTL لے آؤٹ سمت زبردستی نافذ کریں"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"سبھی زبانوں کیلئے اسکرین لے آؤٹ کی سمت کو RTL پر مجبور کریں"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"CPU استعمال دکھائیں"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"موجودہ CPU استعمال دکھانے والا اسکرین اوورلے"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU رینڈرنگ زبردستی نافذ کریں"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"2D ڈرائنگ کیلئے GPU کا استعمال زبردستی نافذ کریں"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAA زبردستی نافذ کریں"</string>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index e2c58a4..a6f9ab8 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi ulanishini o‘rnatib bo‘lmadi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tasdiqdan o‘tishda muammo"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Aloqada emas"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Avtomatik ravishda ulanilmaydi"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Internet aloqasi yo‘q"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tomonidan saqlangan"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi yordamchisi orqali ulangan"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s orqali ulangan"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Klip, maydon va h.k. chegaralarini ko‘rsatish"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"O‘ngdan chapga qarab yozish"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Barcha tillarda o‘ngdan chapga qarab yozish"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"MP yuklanishini ko‘rsatish"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Joriy MP yuklanishini ko‘rsatuvchi ekran"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"GPU yordamida tezlatish"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Ikki o‘lchamli chizma uchun doim GPU ishlatilsin"</string>
<string name="force_msaa" msgid="7920323238677284387">"4x MSAAni yoqish"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index fa4174b..f09e0e5 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Lỗi kết nối WiFi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Sự cố xác thực"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ngoài vùng phủ sóng"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Sẽ không tự động kết nối"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Không có quyền truy cập Internet"</string>
<string name="saved_network" msgid="4352716707126620811">"Được lưu bởi <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Được kết nối qua trình hỗ trợ Wi‑Fi"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Được kết nối qua %1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Hiển thị viền đoạn video, lề, v.v.."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Buộc hướng bố cục RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Buộc hướng bố cục màn hình RTL cho tất cả ngôn ngữ"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Hiển thị mức sử dụng CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Lớp phủ màn hình hiển thị mức sử dụng CPU hiện tại"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Bắt buộc kết xuất GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Bắt buộc sử dụng GPU cho bản vẽ 2d"</string>
<string name="force_msaa" msgid="7920323238677284387">"Bắt buộc 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 63199e8..7268dcd 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WLAN 连接失败"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"身份验证出现问题"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"不在范围内"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"无法自动连接"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"无法连接到互联网"</string>
<string name="saved_network" msgid="4352716707126620811">"已通过<xliff:g id="NAME">%1$s</xliff:g>保存"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"已连接(通过 WLAN 助手)"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"已通过%1$s连接"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"显示剪辑边界、边距等。"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"强制使用从右到左的布局方向"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"强制将所有语言区域的屏幕布局方向改为从右到左"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"显示 CPU 使用情况"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"屏幕叠加层显示当前 CPU 使用情况"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"强制进行 GPU 渲染"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"强制使用 GPU 进行 2D 绘图"</string>
<string name="force_msaa" msgid="7920323238677284387">"强制启用 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index edbffc1..ac9de74 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi 連線失敗"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"驗證問題"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"超出可用範圍"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"不會自動連線"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"無法偵測互聯網連線"</string>
<string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> 的儲存"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"已透過 Wi-Fi 小幫手連線"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"顯示剪輯範圍、邊界等"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"強制使用從右至左的版面配置方向"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"強制將所有語言代碼的畫面配置方向改為從右至左"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"顯示 CPU 使用量"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"在螢幕上重疊顯示目前的 CPU 使用量"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"強制使用 GPU 轉譯"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"強制使用 GPU 進行 2D 繪圖"</string>
<string name="force_msaa" msgid="7920323238677284387">"強制 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index b1c5f06..f17b523 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi 連線失敗"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"驗證問題"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"不在有效範圍內"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"無法自動連線"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"沒有可用的網際網路連線"</string>
<string name="saved_network" msgid="4352716707126620811">"由<xliff:g id="NAME">%1$s</xliff:g>儲存"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"已透過 Wi‑Fi 小幫手連線"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"顯示剪輯範圍、邊界等。"</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"強制使用從右至左版面配置方向"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"強制將所有語言代碼的畫面配置方向改為從右至左"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"顯示 CPU 使用量"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"在螢幕上方顯示目前的 CPU 使用量"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"強制使用 GPU 轉譯"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"強制使用 GPU 進行 2D 繪圖"</string>
<string name="force_msaa" msgid="7920323238677284387">"強制 4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index e4f0d59..1fc551f 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -28,10 +28,8 @@
<string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ukwehlulekla koxhumo le-WiFi"</string>
<string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Inkinga yokufakazela ubuqiniso"</string>
<string name="wifi_not_in_range" msgid="1136191511238508967">"Ayikho ebubanzini"</string>
- <!-- no translation found for wifi_no_internet_no_reconnect (2211781637653149657) -->
- <skip />
- <!-- no translation found for wifi_no_internet (5011955173375805204) -->
- <skip />
+ <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Ngeke ize ixhumeke ngokuzenzakalela"</string>
+ <string name="wifi_no_internet" msgid="3880396223819116454">"Akukho ukufinyelela ku-inthanethi"</string>
<string name="saved_network" msgid="4352716707126620811">"Kulondolozwe ngu-<xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_via_wfa" msgid="3805736726317410714">"Ixhunywe ngomsizi we-Wi-FI"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"Kuxhumeke nge-%1$s"</string>
@@ -236,8 +234,6 @@
<string name="debug_layout_summary" msgid="2001775315258637682">"Bonisa imikhawulo, imiphetho, njll, yesiqeshana."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Phoqelela isikhombisi-ndlela sesakhiwo se-RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Phoqelela isikhombisi-ndlela sesikrini ku-RTL kuzo zonke izifunda"</string>
- <string name="show_cpu_usage" msgid="2389212910758076024">"Bonisa ukusebenzisa i-CPU"</string>
- <string name="show_cpu_usage_summary" msgid="2113341923988958266">"Imbondela yesikrini ibonisa ukusetshenziswa kwe-CPU okwamanje"</string>
<string name="force_hw_ui" msgid="6426383462520888732">"Phoqa ukunikeza i-GPU"</string>
<string name="force_hw_ui_summary" msgid="5535991166074861515">"Phoqelela ukusetshenziswa kwe-GPU ngomdwebo we-2d"</string>
<string name="force_msaa" msgid="7920323238677284387">"Phoqelela i-4x MSAA"</string>
diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
index 0cf4a41..e2e721c 100755
--- a/packages/SettingsLib/res/values/config.xml
+++ b/packages/SettingsLib/res/values/config.xml
@@ -37,4 +37,7 @@
<!-- Intent key for package name values -->
<string name="config_helpIntentNameKey" translatable="false"></string>
-</resources>
+
+ <!-- The apps that need to be hided when they are disabled -->
+ <string-array name="config_hideWhenDisabled_packageNames"></string-array>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 1a1aa57..972fc73 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -582,11 +582,6 @@
<!-- UI debug setting: force right to left layout summary [CHAR LIMIT=100] -->
<string name="force_rtl_layout_all_locales_summary">Force screen layout direction to RTL for all locales</string>
- <!-- UI debug setting: show how CPU is being used? [CHAR LIMIT=25] -->
- <string name="show_cpu_usage">Show CPU usage</string>
- <!-- UI debug setting: show cpu usage summary [CHAR LIMIT=50] -->
- <string name="show_cpu_usage_summary">Screen overlay showing current CPU usage</string>
-
<!-- UI debug setting: force hardware acceleration to render apps [CHAR LIMIT=25] -->
<string name="force_hw_ui">Force GPU rendering</string>
<!-- UI debug setting: force hardware acceleration summary [CHAR LIMIT=50] -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index a22a051..f0ec1078 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -47,6 +47,7 @@
import android.util.SparseArray;
import com.android.internal.util.ArrayUtils;
+import com.android.settingslib.R;
import java.io.File;
import java.text.Collator;
@@ -621,7 +622,7 @@
}
if (filter != null) {
- filter.init();
+ filter.init(mContext);
}
List<AppEntry> apps;
@@ -1280,6 +1281,9 @@
public interface AppFilter {
void init();
+ default void init(Context context) {
+ init();
+ }
boolean filterApp(AppEntry info);
}
@@ -1398,6 +1402,33 @@
}
};
+ public static final AppFilter FILTER_NOT_HIDE = new AppFilter() {
+ private String[] mHidePackageNames;
+
+ public void init(Context context) {
+ mHidePackageNames = context.getResources()
+ .getStringArray(R.array.config_hideWhenDisabled_packageNames);
+ }
+
+ @Override
+ public void init() {
+ }
+
+ @Override
+ public boolean filterApp(AppEntry entry) {
+ if (ArrayUtils.contains(mHidePackageNames, entry.info.packageName)) {
+ if (!entry.info.enabled) {
+ return false;
+ } else if (entry.info.enabledSetting ==
+ PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ };
+
public static class VolumeFilter implements AppFilter {
private final String mVolumeUuid;
@@ -1425,6 +1456,12 @@
}
@Override
+ public void init(Context context) {
+ mFirstFilter.init(context);
+ mSecondFilter.init(context);
+ }
+
+ @Override
public void init() {
mFirstFilter.init();
mSecondFilter.init();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 4bcbea7..a332332 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -268,16 +268,16 @@
if (cachedDevice == null) {
Log.w(TAG, "CachedBluetoothDevice for device " + device +
" not found, calling readPairedDevices().");
- if (!readPairedDevices()) {
- Log.e(TAG, "Got bonding state changed for " + device +
- ", but we have no record of that device.");
- return;
+ if (readPairedDevices()) {
+ cachedDevice = mDeviceManager.findDevice(device);
}
- cachedDevice = mDeviceManager.findDevice(device);
+
if (cachedDevice == null) {
- Log.e(TAG, "Got bonding state changed for " + device +
- ", but device not added in cache.");
- return;
+ Log.w(TAG, "Got bonding state changed for " + device +
+ ", but we have no record of that device.");
+
+ cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
+ dispatchDeviceAdded(cachedDevice);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index a879d16f..52e686c9b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -102,9 +102,6 @@
private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
- /** Auto-connect after pairing only if locally initiated. */
- private boolean mConnectAfterPairing;
-
/**
* Describes the current device and profile for logging.
*
@@ -300,7 +297,6 @@
return false;
}
- mConnectAfterPairing = true; // auto-connect after pairing
return true;
}
@@ -309,7 +305,7 @@
* slightly different for local vs. remote initiated pairing dialogs.
*/
boolean isUserInitiatedPairing() {
- return mConnectAfterPairing;
+ return mDevice.isBondingInitiatedLocally();
}
public void unpair() {
@@ -549,7 +545,6 @@
void onBondingStateChanged(int bondState) {
if (bondState == BluetoothDevice.BOND_NONE) {
mProfiles.clear();
- mConnectAfterPairing = false; // cancel auto-connect
setPhonebookPermissionChoice(ACCESS_UNKNOWN);
setMessagePermissionChoice(ACCESS_UNKNOWN);
setSimPermissionChoice(ACCESS_UNKNOWN);
@@ -562,10 +557,9 @@
if (bondState == BluetoothDevice.BOND_BONDED) {
if (mDevice.isBluetoothDock()) {
onBondingDockConnect();
- } else if (mConnectAfterPairing) {
+ } else if (mDevice.isBondingInitiatedLocally()) {
connect(false);
}
- mConnectAfterPairing = false;
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 26e8303..857ca49 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -40,23 +40,47 @@
import java.util.Set;
import java.util.TimeZone;
+/**
+ * ZoneGetter is the utility class to get time zone and zone list, and both of them have display
+ * name in time zone. In this class, we will keep consistency about display names for all
+ * the methods.
+ *
+ * The display name chosen for each zone entry depends on whether the zone is one associated
+ * with the country of the user's chosen locale. For "local" zones we prefer the "long name"
+ * (e.g. "Europe/London" -> "British Summer Time" for people in the UK). For "non-local"
+ * zones we prefer the exemplar location (e.g. "Europe/London" -> "London" for English
+ * speakers from outside the UK). This heuristic is based on the fact that people are
+ * typically familiar with their local timezones and exemplar locations don't always match
+ * modern-day expectations for people living in the country covered. Large countries like
+ * China that mostly use a single timezone (olson id: "Asia/Shanghai") may not live near
+ * "Shanghai" and prefer the long name over the exemplar location. The only time we don't
+ * follow this policy for local zones is when Android supplies multiple olson IDs to choose
+ * from and the use of a zone's long name leads to ambiguity. For example, at the time of
+ * writing Android lists 5 olson ids for Australia which collapse to 2 different zone names
+ * in winter but 4 different zone names in summer. The ambiguity leads to the users
+ * selecting the wrong olson ids.
+ *
+ */
public class ZoneGetter {
private static final String TAG = "ZoneGetter";
- private static final String XMLTAG_TIMEZONE = "timezone";
-
public static final String KEY_ID = "id"; // value: String
public static final String KEY_DISPLAYNAME = "name"; // value: String
public static final String KEY_GMT = "gmt"; // value: String
public static final String KEY_OFFSET = "offset"; // value: int (Integer)
- private ZoneGetter() {}
+ private static final String XMLTAG_TIMEZONE = "timezone";
- public static String getTimeZoneOffsetAndName(TimeZone tz, Date now) {
- Locale locale = Locale.getDefault();
- String gmtString = getGmtOffsetString(locale, tz, now);
- TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
- String zoneNameString = getZoneLongName(timeZoneNames, tz, now);
+ public static String getTimeZoneOffsetAndName(Context context, TimeZone tz, Date now) {
+ final Locale locale = Locale.getDefault();
+ final String gmtString = getGmtOffsetString(locale, tz, now);
+ final TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
+ final ZoneGetterData data = new ZoneGetterData(context);
+
+ final boolean useExemplarLocationForLocalNames =
+ shouldUseExemplarLocationForLocalNames(data, timeZoneNames);
+ final String zoneNameString = getTimeZoneDisplayName(data, timeZoneNames,
+ useExemplarLocationForLocalNames, tz, tz.getID());
if (zoneNameString == null) {
return gmtString;
}
@@ -69,82 +93,20 @@
final Locale locale = Locale.getDefault();
final Date now = new Date();
final TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
-
- // The display name chosen for each zone entry depends on whether the zone is one associated
- // with the country of the user's chosen locale. For "local" zones we prefer the "long name"
- // (e.g. "Europe/London" -> "British Summer Time" for people in the UK). For "non-local"
- // zones we prefer the exemplar location (e.g. "Europe/London" -> "London" for English
- // speakers from outside the UK). This heuristic is based on the fact that people are
- // typically familiar with their local timezones and exemplar locations don't always match
- // modern-day expectations for people living in the country covered. Large countries like
- // China that mostly use a single timezone (olson id: "Asia/Shanghai") may not live near
- // "Shanghai" and prefer the long name over the exemplar location. The only time we don't
- // follow this policy for local zones is when Android supplies multiple olson IDs to choose
- // from and the use of a zone's long name leads to ambiguity. For example, at the time of
- // writing Android lists 5 olson ids for Australia which collapse to 2 different zone names
- // in winter but 4 different zone names in summer. The ambiguity leads to the users
- // selecting the wrong olson ids.
-
- // Get the list of olson ids to display to the user.
- List<String> olsonIdsToDisplayList = readTimezonesToDisplay(context);
-
- // Store the information we are going to need more than once.
- final int zoneCount = olsonIdsToDisplayList.size();
- final String[] olsonIdsToDisplay = new String[zoneCount];
- final TimeZone[] timeZones = new TimeZone[zoneCount];
- final String[] gmtOffsetStrings = new String[zoneCount];
- for (int i = 0; i < zoneCount; i++) {
- String olsonId = olsonIdsToDisplayList.get(i);
- olsonIdsToDisplay[i] = olsonId;
- TimeZone tz = TimeZone.getTimeZone(olsonId);
- timeZones[i] = tz;
- gmtOffsetStrings[i] = getGmtOffsetString(locale, tz, now);
- }
-
- // Create a lookup of local zone IDs.
- Set<String> localZoneIds = new HashSet<String>();
- for (String olsonId : libcore.icu.TimeZoneNames.forLocale(locale)) {
- localZoneIds.add(olsonId);
- }
+ final ZoneGetterData data = new ZoneGetterData(context);
// Work out whether the display names we would show by default would be ambiguous.
- Set<String> localZoneNames = new HashSet<String>();
- boolean useExemplarLocationForLocalNames = false;
- for (int i = 0; i < zoneCount; i++) {
- String olsonId = olsonIdsToDisplay[i];
- if (localZoneIds.contains(olsonId)) {
- TimeZone tz = timeZones[i];
- String displayName = getZoneLongName(timeZoneNames, tz, now);
- if (displayName == null) {
- displayName = gmtOffsetStrings[i];
- }
- boolean nameIsUnique = localZoneNames.add(displayName);
- if (!nameIsUnique) {
- useExemplarLocationForLocalNames = true;
- break;
- }
- }
- }
+ final boolean useExemplarLocationForLocalNames =
+ shouldUseExemplarLocationForLocalNames(data, timeZoneNames);
// Generate the list of zone entries to return.
List<Map<String, Object>> zones = new ArrayList<Map<String, Object>>();
- for (int i = 0; i < zoneCount; i++) {
- String olsonId = olsonIdsToDisplay[i];
- TimeZone tz = timeZones[i];
- String gmtOffsetString = gmtOffsetStrings[i];
+ for (int i = 0; i < data.zoneCount; i++) {
+ TimeZone tz = data.timeZones[i];
+ String gmtOffsetString = data.gmtOffsetStrings[i];
- boolean isLocalZoneId = localZoneIds.contains(olsonId);
- boolean preferLongName = isLocalZoneId && !useExemplarLocationForLocalNames;
- String displayName;
- if (preferLongName) {
- displayName = getZoneLongName(timeZoneNames, tz, now);
- } else {
- displayName = timeZoneNames.getExemplarLocationName(tz.getID());
- if (displayName == null || displayName.isEmpty()) {
- // getZoneExemplarLocation can return null. Fall back to the long name.
- displayName = getZoneLongName(timeZoneNames, tz, now);
- }
- }
+ String displayName = getTimeZoneDisplayName(data, timeZoneNames,
+ useExemplarLocationForLocalNames, tz, data.olsonIdsToDisplay[i]);
if (displayName == null || displayName.isEmpty()) {
displayName = gmtOffsetString;
}
@@ -198,28 +160,103 @@
return olsonIds;
}
+ private static boolean shouldUseExemplarLocationForLocalNames(ZoneGetterData data,
+ TimeZoneNames timeZoneNames) {
+ final Set<String> localZoneNames = new HashSet<String>();
+ final Date now = new Date();
+ for (int i = 0; i < data.zoneCount; i++) {
+ final String olsonId = data.olsonIdsToDisplay[i];
+ if (data.localZoneIds.contains(olsonId)) {
+ final TimeZone tz = data.timeZones[i];
+ String displayName = getZoneLongName(timeZoneNames, tz, now);
+ if (displayName == null) {
+ displayName = data.gmtOffsetStrings[i];
+ }
+ final boolean nameIsUnique = localZoneNames.add(displayName);
+ if (!nameIsUnique) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private static String getTimeZoneDisplayName(ZoneGetterData data, TimeZoneNames timeZoneNames,
+ boolean useExemplarLocationForLocalNames, TimeZone tz, String olsonId) {
+ final Date now = new Date();
+ final boolean isLocalZoneId = data.localZoneIds.contains(olsonId);
+ final boolean preferLongName = isLocalZoneId && !useExemplarLocationForLocalNames;
+ String displayName;
+
+ if (preferLongName) {
+ displayName = getZoneLongName(timeZoneNames, tz, now);
+ } else {
+ displayName = timeZoneNames.getExemplarLocationName(tz.getID());
+ if (displayName == null || displayName.isEmpty()) {
+ // getZoneExemplarLocation can return null. Fall back to the long name.
+ displayName = getZoneLongName(timeZoneNames, tz, now);
+ }
+ }
+
+ return displayName;
+ }
+
/**
* Returns the long name for the timezone for the given locale at the time specified.
* Can return {@code null}.
*/
private static String getZoneLongName(TimeZoneNames names, TimeZone tz, Date now) {
- TimeZoneNames.NameType nameType =
+ final TimeZoneNames.NameType nameType =
tz.inDaylightTime(now) ? TimeZoneNames.NameType.LONG_DAYLIGHT
- : TimeZoneNames.NameType.LONG_STANDARD;
+ : TimeZoneNames.NameType.LONG_STANDARD;
return names.getDisplayName(tz.getID(), nameType, now.getTime());
}
private static String getGmtOffsetString(Locale locale, TimeZone tz, Date now) {
// Use SimpleDateFormat to format the GMT+00:00 string.
- SimpleDateFormat gmtFormatter = new SimpleDateFormat("ZZZZ");
+ final SimpleDateFormat gmtFormatter = new SimpleDateFormat("ZZZZ");
gmtFormatter.setTimeZone(tz);
String gmtString = gmtFormatter.format(now);
// Ensure that the "GMT+" stays with the "00:00" even if the digits are RTL.
- BidiFormatter bidiFormatter = BidiFormatter.getInstance();
+ final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
boolean isRtl = TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL;
gmtString = bidiFormatter.unicodeWrap(gmtString,
isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR);
return gmtString;
}
-}
+
+ private static final class ZoneGetterData {
+ public final String[] olsonIdsToDisplay;
+ public final String[] gmtOffsetStrings;
+ public final TimeZone[] timeZones;
+ public final Set<String> localZoneIds;
+ public final int zoneCount;
+
+ public ZoneGetterData(Context context) {
+ final Locale locale = Locale.getDefault();
+ final Date now = new Date();
+ final List<String> olsonIdsToDisplayList = readTimezonesToDisplay(context);
+
+ // Load all the data needed to display time zones
+ zoneCount = olsonIdsToDisplayList.size();
+ olsonIdsToDisplay = new String[zoneCount];
+ timeZones = new TimeZone[zoneCount];
+ gmtOffsetStrings = new String[zoneCount];
+ for (int i = 0; i < zoneCount; i++) {
+ final String olsonId = olsonIdsToDisplayList.get(i);
+ olsonIdsToDisplay[i] = olsonId;
+ final TimeZone tz = TimeZone.getTimeZone(olsonId);
+ timeZones[i] = tz;
+ gmtOffsetStrings[i] = getGmtOffsetString(locale, tz, now);
+ }
+
+ // Create a lookup of local zone IDs.
+ localZoneIds = new HashSet<String>();
+ for (String olsonId : libcore.icu.TimeZoneNames.forLocale(locale)) {
+ localZoneIds.add(olsonId);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
index 9821fb8..4ec4f4f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java
@@ -18,17 +18,17 @@
public final class CategoryKey {
// Activities in this category shows up in Settings homepage.
- public static final String CATEGORY_HOMEPAGE = "com.android.settings.category.homepage";
+ public static final String CATEGORY_HOMEPAGE = "com.android.settings.category.ia.homepage";
- // Top level categor.
- public static final String CATEGORY_NETWORK = "com.android.settings.category.wireless";
- public static final String CATEGORY_DEVICE = "com.android.settings.category.device";
- public static final String CATEGORY_APPS = "com.android.settings.category.apps";
- public static final String CATEGORY_BATTERY = "com.android.settings.category.battery";
- public static final String CATEGORY_DISPLAY = "com.android.settings.category.display";
- public static final String CATEGORY_SOUND = "com.android.settings.category.sound";
- public static final String CATEGORY_STORAGE = "com.android.settings.category.storage";
- public static final String CATEGORY_SECURITY = "com.android.settings.category.security";
- public static final String CATEGORY_ACCOUNT = "com.android.settings.category.accounts";
- public static final String CATEGORY_SYSTEM = "com.android.settings.category.system";
+ // Top level category.
+ public static final String CATEGORY_NETWORK = "com.android.settings.category.ia.wireless";
+ public static final String CATEGORY_DEVICE = "com.android.settings.category.ia.device";
+ public static final String CATEGORY_APPS = "com.android.settings.category.ia.apps";
+ public static final String CATEGORY_BATTERY = "com.android.settings.category.ia.battery";
+ public static final String CATEGORY_DISPLAY = "com.android.settings.category.ia.display";
+ public static final String CATEGORY_SOUND = "com.android.settings.category.ia.sound";
+ public static final String CATEGORY_STORAGE = "com.android.settings.category.ia.storage";
+ public static final String CATEGORY_SECURITY = "com.android.settings.category.ia.security";
+ public static final String CATEGORY_ACCOUNT = "com.android.settings.category.ia.accounts";
+ public static final String CATEGORY_SYSTEM = "com.android.settings.category.ia.system";
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
index a8f286d..a51ad76 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/CategoryManager.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -32,7 +32,6 @@
private static final String TAG = "CategoryManager";
private static CategoryManager sInstance;
-
private final InterestingConfigChanges mInterestingConfigChanges;
// Tile cache (key: <packageName, activityName>, value: tile)
@@ -43,42 +42,39 @@
private List<DashboardCategory> mCategories;
- public static CategoryManager get() {
+ public static CategoryManager get(Context context) {
if (sInstance == null) {
- sInstance = new CategoryManager();
+ sInstance = new CategoryManager(context);
}
return sInstance;
}
- CategoryManager() {
- mInterestingConfigChanges = new InterestingConfigChanges();
+ CategoryManager(Context context) {
mTileByComponentCache = new ArrayMap<>();
mCategoryByKeyMap = new ArrayMap<>();
+ mInterestingConfigChanges = new InterestingConfigChanges();
+ mInterestingConfigChanges.applyNewConfig(context.getResources());
}
- public DashboardCategory getTilesByCategory(Context context, String categoryKey) {
+ public synchronized DashboardCategory getTilesByCategory(Context context, String categoryKey) {
tryInitCategories(context);
- final DashboardCategory category = mCategoryByKeyMap.get(categoryKey);
- if (category == null) {
- throw new IllegalStateException("Can't find category with key " + categoryKey);
- }
- return category;
+ return mCategoryByKeyMap.get(categoryKey);
}
- public List<DashboardCategory> getCategories(Context context) {
+ public synchronized List<DashboardCategory> getCategories(Context context) {
tryInitCategories(context);
return mCategories;
}
- public void reloadAllCategoriesForConfigChange(Context context) {
- if (mInterestingConfigChanges.applyNewConfig(context.getResources())) {
- mCategories = null;
- tryInitCategories(context);
- }
+ public synchronized void reloadAllCategories(Context context) {
+ final boolean forceClearCache = mInterestingConfigChanges.applyNewConfig(
+ context.getResources());
+ mCategories = null;
+ tryInitCategories(context, forceClearCache);
}
- public void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) {
+ public synchronized void updateCategoryFromBlacklist(Set<ComponentName> tileBlacklist) {
if (mCategories == null) {
Log.w(TAG, "Category is null, skipping blacklist update");
}
@@ -93,9 +89,17 @@
}
}
- private void tryInitCategories(Context context) {
+ private synchronized void tryInitCategories(Context context) {
+ // Keep cached tiles by default. The cache is only invalidated when InterestingConfigChange
+ // happens.
+ tryInitCategories(context, false /* forceClearCache */);
+ }
+
+ private synchronized void tryInitCategories(Context context, boolean forceClearCache) {
if (mCategories == null) {
- mTileByComponentCache.clear();
+ if (forceClearCache) {
+ mTileByComponentCache.clear();
+ }
mCategoryByKeyMap.clear();
mCategories = TileUtils.getCategories(context, mTileByComponentCache,
false /* categoryDefinedInManifest */);
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 50867eb..bad7ba4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -185,7 +185,7 @@
return false;
}
if (isDashboardFeatureEnabled()) {
- final DashboardCategory homepageCategories = CategoryManager.get()
+ final DashboardCategory homepageCategories = CategoryManager.get(this)
.getTilesByCategory(this, CategoryKey.CATEGORY_HOMEPAGE);
return homepageCategories.containsComponent(componentName);
} else {
@@ -429,12 +429,12 @@
private final CategoryManager mCategoryManager;
public CategoriesUpdateTask() {
- mCategoryManager = CategoryManager.get();
+ mCategoryManager = CategoryManager.get(SettingsDrawerActivity.this);
}
@Override
protected Void doInBackground(Void... params) {
- mCategoryManager.reloadAllCategoriesForConfigChange(SettingsDrawerActivity.this);
+ mCategoryManager.reloadAllCategories(SettingsDrawerActivity.this);
return null;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
index e1216a1..602d135 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
@@ -69,8 +69,8 @@
}
public void updateHomepageCategories() {
- DashboardCategory category =
- CategoryManager.get().getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE);
+ final DashboardCategory category = CategoryManager.get(mActivity)
+ .getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE);
mItems.clear();
// Spacer.
mItems.add(null);
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 81f0e84..b2ce13f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -94,13 +94,6 @@
private static final String EXTRA_CATEGORY_KEY = "com.android.settings.category";
/**
- * The key used to get the category from metadata of activities of action
- * {@link #EXTRA_SETTINGS_ACTION}
- * The value must be one of constants defined in {@code CategoryKey}.
- */
- private static final String EXTRA_IA_CATEGORY_KEY = "com.android.settings.iacategory";
-
- /**
* Name of the meta-data item that should be set in the AndroidManifest.xml
* to specify the icon that should be displayed for the preference.
*/
@@ -240,20 +233,18 @@
ActivityInfo activityInfo = resolved.activityInfo;
Bundle metaData = activityInfo.metaData;
String categoryKey = defaultCategory;
- if (metaData != null && categoryKey == null) {
- // categoryKey is null, try to get it from metadata.
- if (metaData.containsKey(EXTRA_IA_CATEGORY_KEY)) {
- categoryKey = metaData.getString(EXTRA_IA_CATEGORY_KEY);
- } else if (metaData.containsKey(EXTRA_CATEGORY_KEY)) {
- categoryKey = metaData.getString(EXTRA_CATEGORY_KEY);
- }
- }
- if (checkCategory && categoryKey == null) {
+
+ // Load category
+ if (checkCategory && ((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY))
+ && categoryKey == null) {
Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for intent "
+ intent + " missing metadata "
+ (metaData == null ? "" : EXTRA_CATEGORY_KEY));
continue;
+ } else {
+ categoryKey = metaData.getString(EXTRA_CATEGORY_KEY);
}
+
Pair<String, String> key = new Pair<String, String>(activityInfo.packageName,
activityInfo.name);
Tile tile = addedCache.get(key);
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index a514ebb..c6b9c1a0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -288,7 +288,7 @@
public boolean matches(WifiConfiguration config) {
if (config.isPasspoint() && mConfig != null && mConfig.isPasspoint()) {
- return config.FQDN.equals(mConfig.providerFriendlyName);
+ return config.FQDN.equals(mConfig.FQDN);
} else {
return ssid.equals(removeDoubleQuotes(config.SSID))
&& security == getSecurity(config)
diff --git a/packages/SettingsLib/tests/AndroidManifest.xml b/packages/SettingsLib/tests/AndroidManifest.xml
index 18bbbed..9fd5a41 100644
--- a/packages/SettingsLib/tests/AndroidManifest.xml
+++ b/packages/SettingsLib/tests/AndroidManifest.xml
@@ -20,6 +20,7 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY"/>
+ <uses-permission android:name="android.permission.SET_TIME_ZONE" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/utils/ZoneGetterTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/utils/ZoneGetterTest.java
new file mode 100644
index 0000000..57e06dd
--- /dev/null
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/utils/ZoneGetterTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.settingslib.utils;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.*;
+import com.android.settingslib.datetime.ZoneGetter;
+
+import static junit.framework.Assert.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ZoneGetterTest {
+ private static final String TIME_ZONE_LONDON_ID = "Europe/London";
+ private static final String TIME_ZONE_LA_ID = "America/Los_Angeles";
+ private Locale mLocaleEnUs;
+ private Calendar mCalendar;
+
+ @Before
+ public void setUp() {
+ mLocaleEnUs = new Locale("en", "us");
+ Locale.setDefault(mLocaleEnUs);
+ mCalendar = new GregorianCalendar(2016, 9, 1);
+ }
+
+ @Test
+ public void getTimeZoneOffsetAndName_setLondon_returnLondon() {
+ // Check it will ends with 'London', not 'British Summer Time' or sth else
+ testTimeZoneOffsetAndNameInner(TIME_ZONE_LONDON_ID, "London");
+ }
+
+ @Test
+ public void getTimeZoneOffsetAndName_setLosAngeles_returnPacificDaylightTime() {
+ // Check it will ends with 'Pacific Daylight Time', not 'Los_Angeles'
+ testTimeZoneOffsetAndNameInner(TIME_ZONE_LA_ID, "Pacific Daylight Time");
+ }
+
+ private void testTimeZoneOffsetAndNameInner(String timeZoneId, String expectedName) {
+ final Context context = InstrumentationRegistry.getContext();
+ final TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
+
+ String timeZoneString = ZoneGetter.getTimeZoneOffsetAndName(context, timeZone,
+ mCalendar.getTime());
+
+ assertTrue(timeZoneString.endsWith(expectedName));
+ }
+
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 7338a9c..c1a1f84 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1483,7 +1483,6 @@
Settings.Global.CALL_AUTO_RETRY,
Settings.Global.DEBUG_APP,
Settings.Global.WAIT_FOR_DEBUGGER,
- Settings.Global.SHOW_PROCESSES,
Settings.Global.ALWAYS_FINISH_ACTIVITIES,
};
String[] secureToGlobal = {
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index dde71eb..b4bfb01 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -201,7 +201,12 @@
@After
public void tearDown() throws Exception {
Log.i(TAG, getName() + ".tearDown()");
- cancelExistingNotifications();
+ try {
+ cancelExistingNotifications();
+ } finally {
+ // Collapses just in case, so a failure here does not compromise tests on other classes.
+ mUiBot.collapseStatusBar();
+ }
}
@Test
@@ -362,7 +367,7 @@
detailsUi.assertName(NAME); // Sanity check
cancelFromNotification();
- mUiBot.closeNotifications();
+ mUiBot.collapseStatusBar();
assertDetailsUiClosed();
assertServiceNotRunning();
diff --git a/packages/Shell/tests/src/com/android/shell/UiBot.java b/packages/Shell/tests/src/com/android/shell/UiBot.java
index deab7da..e839765 100644
--- a/packages/Shell/tests/src/com/android/shell/UiBot.java
+++ b/packages/Shell/tests/src/com/android/shell/UiBot.java
@@ -62,7 +62,7 @@
return getObject(text);
}
- public void closeNotifications() throws Exception {
+ public void collapseStatusBar() throws Exception {
// TODO: mDevice should provide such method..
StatusBarManager sbm =
(StatusBarManager) mInstrumentation.getContext().getSystemService("statusbar");
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 71bfe85..ffddf02 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -2,10 +2,9 @@
include $(CLEAR_VARS)
-LOCAL_MODULE := SystemUI-proto-tags
+LOCAL_MODULE := SystemUI-proto
-LOCAL_SRC_FILES := $(call all-proto-files-under,src) \
- src/com/android/systemui/EventLogTags.logtags
+LOCAL_SRC_FILES := $(call all-proto-files-under,src)
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
@@ -33,7 +32,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
framework-protos \
- SystemUI-proto-tags
+ SystemUI-proto
LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_JAVA_LIBRARIES += android.car
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 8ed1be5..02518f2 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -219,19 +219,10 @@
</intent-filter>
</receiver>
- <service android:name=".LoadAverageService"
- android:exported="true" />
-
<service android:name=".ImageWallpaper"
android:permission="android.permission.BIND_WALLPAPER"
android:exported="true" />
- <receiver android:name=".BootReceiver" androidprv:systemUserOnly="true">
- <intent-filter android:priority="1000">
- <action android:name="android.intent.action.BOOT_COMPLETED" />
- </intent-filter>
- </receiver>
-
<activity android:name=".tuner.TunerActivity"
android:enabled="false"
android:icon="@drawable/tuner"
@@ -247,6 +238,18 @@
android:value="com.android.settings.category.system" />
</activity>
+ <activity-alias android:name=".tuner.TunerSettingLink"
+ android:targetActivity=".tuner.TunerActivity"
+ android:enabled="false"
+ android:process=":tuner">
+ <intent-filter android:priority="1">
+ <action android:name="com.android.settings.action.EXTRA_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.category"
+ android:value="com.android.settings.category.ia.system" />
+ </activity-alias>
+
<activity-alias android:name=".DemoMode"
android:targetActivity=".tuner.TunerActivity"
android:icon="@drawable/tuner"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
index 495771a..75a5434 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -14,12 +14,10 @@
package com.android.systemui.plugins;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -33,12 +31,10 @@
import com.android.internal.annotations.VisibleForTesting;
-import dalvik.system.PathClassLoader;
-
import java.util.ArrayList;
import java.util.List;
-public class PluginInstanceManager<T extends Plugin> extends BroadcastReceiver {
+public class PluginInstanceManager<T extends Plugin> {
private static final boolean DEBUG = false;
@@ -57,20 +53,21 @@
final PluginHandler mPluginHandler;
private final boolean isDebuggable;
private final PackageManager mPm;
- private final ClassLoaderFactory mClassLoaderFactory;
+ private final PluginManager mManager;
PluginInstanceManager(Context context, String action, PluginListener<T> listener,
- boolean allowMultiple, Looper looper, int version) {
+ boolean allowMultiple, Looper looper, int version, PluginManager manager) {
this(context, context.getPackageManager(), action, listener, allowMultiple, looper, version,
- Build.IS_DEBUGGABLE, new ClassLoaderFactory());
+ manager, Build.IS_DEBUGGABLE);
}
@VisibleForTesting
PluginInstanceManager(Context context, PackageManager pm, String action,
PluginListener<T> listener, boolean allowMultiple, Looper looper, int version,
- boolean debuggable, ClassLoaderFactory classLoaderFactory) {
+ PluginManager manager, boolean debuggable) {
mMainHandler = new MainHandler(Looper.getMainLooper());
mPluginHandler = new PluginHandler(looper);
+ mManager = manager;
mContext = context;
mPm = pm;
mAction = action;
@@ -78,44 +75,29 @@
mAllowMultiple = allowMultiple;
mVersion = version;
isDebuggable = debuggable;
- mClassLoaderFactory = classLoaderFactory;
}
- public void startListening() {
+ public void loadAll() {
if (DEBUG) Log.d(TAG, "startListening");
mPluginHandler.sendEmptyMessage(PluginHandler.QUERY_ALL);
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- mContext.registerReceiver(this, filter);
- filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
- mContext.registerReceiver(this, filter);
}
- public void stopListening() {
+ public void destroy() {
if (DEBUG) Log.d(TAG, "stopListening");
ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins);
for (PluginInfo plugin : plugins) {
mMainHandler.obtainMessage(MainHandler.PLUGIN_DISCONNECTED,
plugin.mPlugin).sendToTarget();
}
- mContext.unregisterReceiver(this);
}
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) Log.d(TAG, "onReceive " + intent);
- if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
- mPluginHandler.sendEmptyMessage(PluginHandler.QUERY_ALL);
- } else {
- Uri data = intent.getData();
- String pkgName = data.getEncodedSchemeSpecificPart();
- mPluginHandler.obtainMessage(PluginHandler.REMOVE_PKG, pkgName).sendToTarget();
- if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
- mPluginHandler.obtainMessage(PluginHandler.QUERY_PKG, pkgName).sendToTarget();
- }
- }
+ public void onPackageRemoved(String pkg) {
+ mPluginHandler.obtainMessage(PluginHandler.REMOVE_PKG, pkg).sendToTarget();
+ }
+
+ public void onPackageChange(String pkg) {
+ mPluginHandler.obtainMessage(PluginHandler.REMOVE_PKG, pkg).sendToTarget();
+ mPluginHandler.obtainMessage(PluginHandler.QUERY_PKG, pkg).sendToTarget();
}
public boolean checkAndDisable(String className) {
@@ -132,7 +114,9 @@
public void disableAll() {
ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins);
- plugins.forEach(this::disable);
+ for (int i = 0; i < plugins.size(); i++) {
+ disable(plugins.get(i));
+ }
}
private void disable(PluginInfo info) {
@@ -179,12 +163,6 @@
}
}
- static class ClassLoaderFactory {
- public ClassLoader createClassLoader(String path, ClassLoader base) {
- return new PathClassLoader(path, base);
- }
- }
-
private class PluginHandler extends Handler {
private static final int QUERY_ALL = 1;
private static final int QUERY_PKG = 2;
@@ -279,8 +257,7 @@
return null;
}
// Create our own ClassLoader so we can use our own code as the parent.
- ClassLoader classLoader = mClassLoaderFactory.createClassLoader(info.sourceDir,
- getClass().getClassLoader());
+ ClassLoader classLoader = mManager.getClassLoader(info.sourceDir, info.packageName);
Context pluginContext = new PluginContextWrapper(
mContext.createApplicationContext(info, 0), classLoader);
Class<?> pluginClass = Class.forName(cls, true, classLoader);
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
index 4bf6494..686b4d4 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginManager.java
@@ -14,7 +14,11 @@
package com.android.systemui.plugins;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
import android.os.Build;
import android.os.HandlerThread;
import android.os.Looper;
@@ -22,26 +26,31 @@
import com.android.internal.annotations.VisibleForTesting;
+import dalvik.system.PathClassLoader;
+
import java.lang.Thread.UncaughtExceptionHandler;
+import java.util.Map;
/**
* @see Plugin
*/
-public class PluginManager {
+public class PluginManager extends BroadcastReceiver {
private static PluginManager sInstance;
private final HandlerThread mBackgroundThread;
private final ArrayMap<PluginListener<?>, PluginInstanceManager> mPluginMap
= new ArrayMap<>();
+ private final Map<String, ClassLoader> mClassLoaders = new ArrayMap<>();
private final Context mContext;
private final PluginInstanceManagerFactory mFactory;
private final boolean isDebuggable;
private final PluginPrefs mPluginPrefs;
+ private ClassLoaderFilter mParentClassLoader;
private PluginManager(Context context) {
- this(context, new PluginInstanceManagerFactory(), Build.IS_DEBUGGABLE,
- Thread.getDefaultUncaughtExceptionHandler());
+ this(context, new PluginInstanceManagerFactory(),
+ Build.IS_DEBUGGABLE, Thread.getDefaultUncaughtExceptionHandler());
}
@VisibleForTesting
@@ -72,9 +81,12 @@
}
mPluginPrefs.addAction(action);
PluginInstanceManager p = mFactory.createPluginInstanceManager(mContext, action, listener,
- allowMultiple, mBackgroundThread.getLooper(), version);
- p.startListening();
+ allowMultiple, mBackgroundThread.getLooper(), version, this);
+ p.loadAll();
mPluginMap.put(listener, p);
+ if (mPluginMap.size() == 1) {
+ startListening();
+ }
}
public void removePluginListener(PluginListener<?> listener) {
@@ -83,7 +95,68 @@
return;
}
if (!mPluginMap.containsKey(listener)) return;
- mPluginMap.remove(listener).stopListening();
+ mPluginMap.remove(listener).destroy();
+ if (mPluginMap.size() == 0) {
+ stopListening();
+ }
+ }
+
+ private void startListening() {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiver(this, filter);
+ filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
+ mContext.registerReceiver(this, filter);
+ }
+
+ private void stopListening() {
+ mContext.unregisterReceiver(this);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
+ for (PluginInstanceManager manager : mPluginMap.values()) {
+ manager.loadAll();
+ }
+ } else {
+ Uri data = intent.getData();
+ String pkg = data.getEncodedSchemeSpecificPart();
+ clearClassLoader(pkg);
+ if (!Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+ for (PluginInstanceManager manager : mPluginMap.values()) {
+ manager.onPackageChange(pkg);
+ }
+ } else {
+ for (PluginInstanceManager manager : mPluginMap.values()) {
+ manager.onPackageRemoved(pkg);
+ }
+ }
+ }
+ }
+
+ public ClassLoader getClassLoader(String sourceDir, String pkg) {
+ if (mClassLoaders.containsKey(pkg)) {
+ return mClassLoaders.get(pkg);
+ }
+ ClassLoader classLoader = new PathClassLoader(sourceDir, getParentClassLoader());
+ mClassLoaders.put(pkg, classLoader);
+ return classLoader;
+ }
+
+ private void clearClassLoader(String pkg) {
+ mClassLoaders.remove(pkg);
+ }
+
+ ClassLoader getParentClassLoader() {
+ if (mParentClassLoader == null) {
+ // Lazily load this so it doesn't have any effect on devices without plugins.
+ mParentClassLoader = new ClassLoaderFilter(getClass().getClassLoader(),
+ "com.android.systemui.plugin");
+ }
+ return mParentClassLoader;
}
public static PluginManager getInstance(Context context) {
@@ -97,9 +170,29 @@
public static class PluginInstanceManagerFactory {
public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
String action, PluginListener<T> listener, boolean allowMultiple, Looper looper,
- int version) {
+ int version, PluginManager manager) {
return new PluginInstanceManager(context, action, listener, allowMultiple, looper,
- version);
+ version, manager);
+ }
+ }
+
+
+ // This allows plugins to include any libraries or copied code they want by only including
+ // classes from the plugin library.
+ private static class ClassLoaderFilter extends ClassLoader {
+ private final String mPackage;
+ private final ClassLoader mBase;
+
+ public ClassLoaderFilter(ClassLoader base, String pkg) {
+ super(ClassLoader.getSystemClassLoader());
+ mBase = base;
+ mPackage = pkg;
+ }
+
+ @Override
+ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (!name.startsWith(mPackage)) super.loadClass(name, resolve);
+ return mBase.loadClass(name);
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
index 3270587..a616369 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSContainer.java
@@ -31,7 +31,7 @@
// This should be incremented any time this class or ActivityStarter or BaseStatusBarHeader
// change in incompatible ways.
- public static final int VERSION = 1;
+ public static final int VERSION = 2;
public QSContainer(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -40,6 +40,7 @@
public abstract void setPanelView(HeightListener notificationPanelView);
public abstract BaseStatusBarHeader getHeader();
+ public abstract void hideImmediately();
public abstract int getQsMinExpansionHeight();
public abstract int getDesiredHeight();
public abstract void setHeightOverride(int desiredHeight);
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_0.xml b/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
index f63dfb12..b78d3bf 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,17 +15,15 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
- android:width="32dp"
- android:height="32dp"
+ android:width="32.0dp"
+ android:height="32.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+ android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
- <path
- android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
- android:fillColor="#4DFFFFFF"/>
+ android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml b/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
index 7fb423e..e055de7 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,20 +15,18 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
- android:width="32dp"
- android:height="32dp"
+ android:width="32.0dp"
+ android:height="32.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.7,20.0l2.0,0.0l0.0,2.0l-2.0,0.0z"/>
+ android:pathData="M10.0,14.6l-8.0,8.0l8.0,0.0l0,-8z"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.7,10.0l2.0,0.0l0.0,8.1l-2.0,0.0z"/>
+ android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#4DFFFFFF"
- android:pathData="M17.7,8.0l4.299999,0.0 0.0,-6.0 -20.0,20.0 15.700001,0.0z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
+ android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_2.xml b/packages/SystemUI/res/drawable/ic_qs_signal_2.xml
index 3358d65..8a48817 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_2.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_2.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,20 +15,18 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
- android:width="32dp"
- android:height="32dp"
+ android:width="32.0dp"
+ android:height="32.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+ android:pathData="M14.0,10.6l-12.0,12.0l12.0,0.0L14.0,10.6z"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M13.900000,10.000000l-11.900000,12.000000 11.900000,0.000000z"/>
- <path
- android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
- android:fillColor="#4DFFFFFF"/>
+ android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_3.xml b/packages/SystemUI/res/drawable/ic_qs_signal_3.xml
index 63838a9..39cc94c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_3.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_3.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,20 +15,18 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
- android:width="32dp"
- android:height="32dp"
+ android:width="32.0dp"
+ android:height="32.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.700001,19.900000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+ android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.700001,9.900000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M16.700001,7.200000l-14.700001,14.700000 14.700001,0.000000z"/>
- <path
- android:pathData="M17.700001,7.900000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
- android:fillColor="#4DFFFFFF"/>
+ android:pathData="M14.1,14.1l2.9,0.0 0.0,-6.5 -15.0,15.0 12.1,0.0z"
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4.xml
index 76690cc..012e95e 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_4.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,17 +15,14 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
- android:width="32dp"
- android:height="32dp"
+ android:width="32.0dp"
+ android:height="32.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+ android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M2.000000,22.000000l15.700001,0.000000 0.000000,-14.000000 4.299999,0.000000 0.000000,-6.000000z"/>
+ android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml
index 50c427e..e6f9292 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,17 +14,15 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
- android:height="29.5dp"
- android:viewportWidth="26.0"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#4DFFFFFF"
- android:pathData="M19.000000,8.000000l5.300000,0.000000l1.200000,-1.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.799999,-1.800001z"
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
index a2d11a0..d423ccb 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,20 +14,18 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
- android:height="29.5dp"
- android:viewportWidth="26.0"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#4DFFFFFF"
- android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+ android:pathData="M13.8,13.2c-0.1,0.0 -0.3,-0.1 -0.4,-0.1c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,0.0 -0.6,-0.1 -0.9,-0.1c0.0,0.0 0.0,0.0 -0.1,0.0c0.0,0.0 0.0,0.0 0.0,0.0s0.0,0.0 0.0,0.0c0.0,0.0 0.0,0.0 -0.1,0.0c-0.3,0.0 -0.6,0.0 -0.9,0.1c-0.1,0.0 -0.3,0.0 -0.4,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.1,0.0 -0.1,0.0 -0.2,0.1c-1.6,0.5 -2.7,1.3 -2.8,1.5l5.3,6.6l0.0,0.0l0.0,0.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.700002,13.2z"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M13.000000,22.000000l5.500000,-6.800000c-0.200000,-0.200000 -2.300000,-1.900000 -5.500000,-1.900000s-5.300000,1.800000 -5.500000,1.900000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.799999,-1.800001z"
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
index f2043fc..1982130 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,20 +14,18 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
- android:height="29.5dp"
- android:viewportWidth="26.0"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#4DFFFFFF"
- android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+ android:pathData="M13.8,12.2l4.9,0.0c-1.0,-0.7 -3.4,-2.2 -6.7,-2.2c-4.1,0.0 -6.9,2.2 -7.2,2.5l7.2,9.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.800001,12.2z"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.000000,11.600000c-1.300000,-0.700000 -3.400000,-1.600000 -6.000000,-1.600000c-4.400000,0.000000 -7.300000,2.400000 -7.600000,2.700000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,11.600000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.800001,1.9 -1.800001,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
index b7a4f4c..b350111 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,20 +14,18 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
- android:height="29.5dp"
- android:viewportWidth="26.0"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#4DFFFFFF"
- android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0l1.0,-1.2C20.0,10.6 16.8,8.0 12.0,8.0s-8.0,2.6 -8.5,3.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.000000,8.600000c-1.600000,-0.700000 -3.600000,-1.300000 -6.000000,-1.300000c-5.300000,0.000000 -8.900000,3.000000 -9.200000,3.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.600000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillAlpha="0.3"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
index 35a9138..136a004 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -14,17 +14,14 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="32.0dp"
- android:height="29.5dp"
- android:viewportWidth="26.0"
+ android:width="24.0dp"
+ android:height="24.0dp"
+ android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillColor="#FFFFFF"/>
<path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+ android:fillColor="#FFFFFF"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_0.xml b/packages/SystemUI/res/drawable/stat_sys_signal_0.xml
index 643c4f9..8bc872a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_0.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_0.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,17 +15,14 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
+ android:width="17.0dp"
+ android:height="17.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
- <path
- android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
+ android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
android:fillColor="?attr/backgroundColor"/>
+ <path
+ android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+ android:fillColor="?attr/fillColor"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml b/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
index 64781c3..8fa7630 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,20 +15,17 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
+ android:width="17.0dp"
+ android:height="17.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M19.7,20.0l2.0,0.0l0.0,2.0l-2.0,0.0z"/>
+ android:pathData="M10.0,14.6l-8.0,8.0l8.0,0.0l0,-8z"
+ android:fillColor="?attr/fillColor"/>
<path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M19.7,10.0l2.0,0.0l0.0,8.1l-2.0,0.0z"/>
+ android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+ android:fillColor="?attr/backgroundColor"/>
<path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M17.7,8.0l4.299999,0.0 0.0,-6.0 -20.0,20.0 15.700001,0.0z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
+ android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+ android:fillColor="?attr/fillColor"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_2.xml b/packages/SystemUI/res/drawable/stat_sys_signal_2.xml
index eb2be08..2a660a3 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_2.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_2.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,20 +15,17 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
+ android:width="17.0dp"
+ android:height="17.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+ android:pathData="M14.0,10.6l-12.0,12.0l12.0,0.0L14.0,10.6z"
+ android:fillColor="?attr/fillColor"/>
<path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M13.900000,10.000000l-11.900000,12.000000 11.900000,0.000000z"/>
- <path
- android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
+ android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
android:fillColor="?attr/backgroundColor"/>
+ <path
+ android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+ android:fillColor="?attr/fillColor"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_3.xml b/packages/SystemUI/res/drawable/stat_sys_signal_3.xml
index 22afad0..9e0a433 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_3.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_3.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,20 +15,17 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
+ android:width="17.0dp"
+ android:height="17.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M19.700001,19.900000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M19.700001,9.900000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M16.700001,7.200000l-14.700001,14.700000 14.700001,0.000000z"/>
- <path
- android:pathData="M17.700001,7.900000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
+ android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
android:fillColor="?attr/backgroundColor"/>
+ <path
+ android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+ android:fillColor="?attr/fillColor"/>
+ <path
+ android:pathData="M14.1,14.1l2.9,0.0 0.0,-6.5 -15.0,15.0 12.1,0.0z"
+ android:fillColor="?attr/fillColor"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_4.xml b/packages/SystemUI/res/drawable/stat_sys_signal_4.xml
index d1e866d..01f6703 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_4.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_4.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,18 +15,14 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:autoMirrored="true"
- android:width="17dp"
- android:height="17dp"
+ android:width="17.0dp"
+ android:height="17.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
-
<path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+ android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+ android:fillColor="?attr/fillColor"/>
<path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
- <path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M2.000000,22.000000l15.700001,0.000000 0.000000,-14.000000 4.299999,0.000000 0.000000,-6.000000z"/>
+ android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+ android:fillColor="?attr/fillColor"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
index 7f1b715e..2de2e36 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,16 +15,13 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18.41dp"
- android:height="17dp"
- android:viewportWidth="26.0"
+ android:height="18.41dp"
+ android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M19.000000,8.000000l5.300000,0.000000l1.200000,-1.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillColor="?attr/backgroundColor"/>
<path
- android:fillColor="?attr/fillColor"
- android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.799999,-1.800001z"
+ android:fillColor="?attr/fillColor"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
index acd89be..144a7c1 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,19 +15,16 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18.41dp"
- android:height="17dp"
- android:viewportWidth="26.0"
+ android:height="18.41dp"
+ android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+ android:pathData="M13.8,13.2c-0.1,0.0 -0.3,-0.1 -0.4,-0.1c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,0.0 -0.6,-0.1 -0.9,-0.1c0.0,0.0 0.0,0.0 -0.1,0.0c0.0,0.0 0.0,0.0 0.0,0.0s0.0,0.0 0.0,0.0c0.0,0.0 0.0,0.0 -0.1,0.0c-0.3,0.0 -0.6,0.0 -0.9,0.1c-0.1,0.0 -0.3,0.0 -0.4,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.1,0.0 -0.1,0.0 -0.2,0.1c-1.6,0.5 -2.7,1.3 -2.8,1.5l5.3,6.6l0.0,0.0l0.0,0.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.700002,13.2z"
+ android:fillColor="?attr/fillColor"/>
<path
- android:fillColor="?attr/fillColor"
- android:pathData="M13.000000,22.000000l5.500000,-6.800000c-0.200000,-0.200000 -2.300000,-1.900000 -5.500000,-1.900000s-5.300000,1.800000 -5.500000,1.900000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillColor="?attr/backgroundColor"/>
<path
- android:fillColor="?attr/fillColor"
- android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.799999,-1.800001z"
+ android:fillColor="?attr/fillColor"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
index f33b25c..6b7f712 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,19 +15,16 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18.41dp"
- android:height="17dp"
- android:viewportWidth="26.0"
+ android:height="18.41dp"
+ android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+ android:pathData="M13.8,12.2l4.9,0.0c-1.0,-0.7 -3.4,-2.2 -6.7,-2.2c-4.1,0.0 -6.9,2.2 -7.2,2.5l7.2,9.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.800001,12.2z"
+ android:fillColor="?attr/fillColor"/>
<path
- android:fillColor="?attr/fillColor"
- android:pathData="M19.000000,11.600000c-1.300000,-0.700000 -3.400000,-1.600000 -6.000000,-1.600000c-4.400000,0.000000 -7.300000,2.400000 -7.600000,2.700000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,11.600000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillColor="?attr/backgroundColor"/>
<path
- android:fillColor="?attr/fillColor"
- android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.800001,1.9 -1.800001,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+ android:fillColor="?attr/fillColor"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
index 09d2e50..d34b4de 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,19 +15,16 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18.41dp"
- android:height="17dp"
- android:viewportWidth="26.0"
+ android:height="18.41dp"
+ android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?attr/backgroundColor"
- android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0l1.0,-1.2C20.0,10.6 16.8,8.0 12.0,8.0s-8.0,2.6 -8.5,3.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillColor="?attr/fillColor"/>
<path
- android:fillColor="?attr/fillColor"
- android:pathData="M19.000000,8.600000c-1.600000,-0.700000 -3.600000,-1.300000 -6.000000,-1.300000c-5.300000,0.000000 -8.900000,3.000000 -9.200000,3.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.600000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillColor="?attr/backgroundColor"/>
<path
- android:fillColor="?attr/fillColor"
- android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="?attr/fillColor"
- android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+ android:fillColor="?attr/fillColor"/>
</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
index fb1f584..5701356 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
@@ -1,7 +1,7 @@
<!--
-Copyright (C) 2014 The Android Open Source Project
+ Copyright (C) 2016 The Android Open Source Project
- Licensed under the Apache License, Version 2.0 (the "License");
+ 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
@@ -15,16 +15,13 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18.41dp"
- android:height="17dp"
- android:viewportWidth="26.0"
+ android:height="18.41dp"
+ android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+ android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+ android:fillColor="?attr/fillColor"/>
<path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
- <path
- android:fillColor="?attr/singleToneColor"
- android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+ android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+ android:fillColor="?attr/fillColor"/>
</vector>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 9fc0b6e..82229e3 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data is laat wag"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sellulêre data is onderbreek"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is onderbreek"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Jy het die datalimiet wat jy gestel het, bereik. Jy gebruik nie meer sellulêre data nie.\n\nAs jy voortgaan, kan heffings vir datagebruik geld."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervat"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding nie"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi gekoppel"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> waarskuwing"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Werkmodus"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Aandbeligting"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Aandbeligting is aan, tik om af te skakel"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Aandbeligting is af, tik om aan te skakel"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Geen onlangse items nie"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Jy het alles toegemaak"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Programinligting"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 0e49ab96..35ed921 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4ጂ ውሂብ ላፍታ ቆሟል"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"የተንቀሳቃሽ ስልክ ውሂብ ላፍታ ቆሟል"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ውሂብ ላፍታ ቆሟል"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"እርስዎ ያስቀመጡት የውሂብ ገደብ ላይ ተደርሷል። ከእንግዲህ ተንቀሳቃሽ ውሂብ እየተጠቀሙ አይደለም ያሉት።\n\nከቆመበት ከቀጠሉ የውሂብ አጠቃቀም ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ከቆመበት ቀጥል"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ምንም በይነመረብ ተያያዥ የለም።"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ተያይዟል"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"የ<xliff:g id="DATA_LIMIT">%s</xliff:g> ማስጠንቀቂያ"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"የሥራ ሁነታ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"የምሽት ብርሃን"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"የምሽት ብርሃን በርቷል፣ ለማጥፋት መታ ያድርጉ"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"የምሽት ብርሃን ጠፍቷል፣ ለማብራት መታ ያድርጉ"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ሁሉንም ነገር አጽድተዋል"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"የመተግበሪያ መረጃ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index abd32b7..5fc9976 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -241,8 +241,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"تم إيقاف بيانات شبكة الجيل الرابع مؤقتًا"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"تم إيقاف بيانات شبكة الجوّال مؤقتًا"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"تم إيقاف البيانات مؤقتًا"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"تم الوصول إلى حد البيانات الذي عيَّنته، ولم يعد بإمكانك استخدام بيانات شبكة الجوّال.\n\nعند الاستئناف، قد يتم تحصيل رسوم مقابل استخدام البيانات."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"استئناف"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"لا يوجد اتصال إنترنت"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi متصل"</string>
@@ -328,8 +327,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"تحذير <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"وضع العمل"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"إضاءة ليلية"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"الإضاءة الليلية قيد العمل، انقر لإيقافها."</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"الإضاءة الليلية قيد الإيقاف، انقر لتشغيلها."</string>
<string name="recents_empty_message" msgid="808480104164008572">"ليست هناك عناصر تم استخدامها مؤخرًا"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"لقد محوتَ كل شيء"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"معلومات التطبيق"</string>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index ca54794..451f205 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G məlumatlarına fasilə verildi"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil məlumatlara fasilə verildi"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Məlumatlara fasilə verildi"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Daha limitini keçdiniz. Artıq mobil data istifadə etmirsiniz.\n\nDavam etsəniz, data istifadəsi üçün ödəniş tətbiq oluna bilər."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davam et"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yoxdur"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi qoşulub"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> xəbərdarlığı"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"İş rejimi"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Gecə işığı"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Gecə işığı aktivdir, deaktiv etmək üçün tıklayın"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Gecə işığı deaktivdir, aktiv etmək üçün tıklayın"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Son elementlər yoxdur"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hərşeyi təmizlədiniz"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Tətbiq haqqında"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index d22928d..a64028d 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -238,8 +238,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci su pauzirani"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ograničenje potrošnje podataka koje ste podesili je dostignuto. Više ne koristite mobilne podatke.\n\nAko nastavite, možda će biti naplaćeni troškovi za potrošnju podataka."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi je povezan"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje za <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Režim rada"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noćno svetlo"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Noćno svetlo je uključeno, dodirnite da biste ga isključili"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Noćno svetlo je isključeno, dodirnite da biste ga uključili"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Obrisali ste sve"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
index c215680..81d3e8f 100644
--- a/packages/SystemUI/res/values-be-rBY/strings.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -241,8 +241,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Перадача даных 4G прыпынена"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мабільная перадача даных прыпынена"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Перадача даных прыпынена"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ліміт даных, які вы задалі, быў дасягнуты. Вы больш не выкарыстоўваеце сотавую перадачу даных.\n\nКалі вы ўзновіце карыстанне, можа спаганяцца плата за выкарыстанне трафіка."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Узнавіць"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма падключэння да Iнтэрнэту"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi падключаны"</string>
@@ -326,8 +325,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Папярэджанне: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Рэжым працы"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Начная падсветка"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"\"Начная падсветка\" ўключана; дакраніцеся, каб выключыць"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"\"Начная падсветка\" выключана; дакраніцеся, каб уключыць"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Няма нядаўніх элементаў"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Вы ачысцілі усё"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Звесткі аб праграме"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c2a2a92..c70a377 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Данните от 4G са поставени на пауза"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните данни са поставени на пауза"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Данните са поставени на пауза"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Достигнахте зададеното от вас ограничение за данните. Вече не използвате мобилната мрежа.\n\nАко възобновите връзката с нея, може да бъдете таксувани за пренос на данни."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Възобновяване"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма връзка с интернет"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: Има връзка"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Работен режим"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Нощно осветление"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Функцията за нощно осветление е включена. Докоснете, за да я изключите"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Функцията за нощно осветление е изключена. Докоснете, за да я включите"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Няма скорошни елементи"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Изчистихте всичко"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информация за приложението"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 5ed264e..7bd6193 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ডেটা বিরতি দেওয়া হয়েছে"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"সেলুলার ডেটা বিরতি দেওয়া হয়েছে"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ডেট বিরতি দেওয়া হয়েছে"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"আপনার সেটা করা ডেটা সীমা ছাড়িয়ে গেছে৷ আপনি আর সেলুলার ডেটা ব্যবহার করতে পারবেন না৷\n\nআপনি যদি আবার ব্যবহার করতে শুরু করেন তাহলে ডেটা ব্যবহারের জন্য চার্জ লাগতে পারে৷"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"পুনঃসূচনা করুন"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"কোনো ইন্টারনেট সংযোগ নেই"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ওয়াই-ফাই সংযুক্ত হয়েছে"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> সতর্কতা"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"কাজের মোড"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"নাইট লাইট"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"নাইট লাইট চালু আছে, বন্ধ করতে আলতো চাপুন"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"নাইট লাইট বন্ধ আছে, চালু করতে আলতো চাপুন"</string>
<string name="recents_empty_message" msgid="808480104164008572">"কোনো সাম্প্রতিক আইটেম নেই"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"আপনি সবকিছু সাফ করেছেন"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"অ্যাপ্লিকেশানের তথ্য"</string>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index c621ecd..1699581 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -238,8 +238,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G prijenos podataka je pauzirano"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci su pauzirani"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prijenos podataka je pauziran"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dostigli ste ograničenje za prijenos podataka koje ste postavili. Više ne koristite mobilne podatke.\n\nUkoliko nastavite koristiti mobilne podatke, mogući su troškovi za prijenos podataka."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internet veze"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi veza aktivna"</string>
@@ -314,7 +313,7 @@
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"Obavještenja"</string>
<string name="quick_settings_flashlight_label" msgid="2133093497691661546">"Svjetiljka"</string>
<string name="quick_settings_cellular_detail_title" msgid="8575062783675171695">"Mobilni podaci"</string>
- <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Korištenje podataka"</string>
+ <string name="quick_settings_cellular_detail_data_usage" msgid="1964260360259312002">"Prijenos podataka"</string>
<string name="quick_settings_cellular_detail_remaining_data" msgid="722715415543541249">"Preostala količina podataka"</string>
<string name="quick_settings_cellular_detail_over_limit" msgid="967669665390990427">"Prekoračeno"</string>
<string name="quick_settings_cellular_detail_data_used" msgid="1476810587475761478">"Iskorišteno <xliff:g id="DATA_USED">%s</xliff:g>"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Poslovni režim"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noćno svjetlo"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Noćno svjetlo je uključeno, dodirnite da isključite"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Noćno svjetlo je isključeno, dodirnite da uključite"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Sve ste obrisali"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 882c8e3..260be35 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Les dades 4G estan aturades"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Les dades mòbils estan aturades"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Les dades estan aturades"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"S\'ha assolit el límit de dades establert. Ja no estàs utilitzant dades mòbils. \n\n Si reprens l\'ús de les dades, es poden aplicar càrrecs."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprèn"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No hi ha connexió a Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: connectada"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertiment: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode de feina"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Llum nocturna"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"La llum nocturna està encesa; toca aquí per apagar-la"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"La llum nocturna està apagada; toca aquí per encendre-la"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No hi ha cap element recent"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ho has esborrat tot"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informació de l\'aplicació"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 216e763..87fb004 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -241,8 +241,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G jsou pozastavena"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilní data jsou pozastavena"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data jsou pozastavena"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Byl dosažen limit dat. Používání mobilních dat bylo vypnuto.\n\nPokud jej obnovíte, mohou vám být účtovány poplatky za využití dat."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Pokračovat"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Žádné přip. k internetu"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: připojeno"</string>
@@ -326,8 +325,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozornění při <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Pracovní režim"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noční režim"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Noční režim je zapnut, klepnutím jej vypnete"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Noční režim je vypnut, klepnutím jej zapnete"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Žádné nedávné položky"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vše je vymazáno"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informace o aplikaci"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 77727bb..fb3e16b 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er sat på pause"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er sat på pause"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er sat på pause"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Du har nået den angivne datagrænse. Du vil ikke længere bruge mobildata.\n\nHvis du fortsætter, vil du muligvis blive opkrævet betaling for dit dataforbrug."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Genoptag"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen internetforb."</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi er forbundet"</string>
@@ -304,7 +303,7 @@
<string name="quick_settings_inversion_label" msgid="8790919884718619648">"Byt om på farver"</string>
<string name="quick_settings_color_space_label" msgid="853443689745584770">"Farvekorrigeringstilstand"</string>
<string name="quick_settings_more_settings" msgid="326112621462813682">"Flere indstillinger"</string>
- <string name="quick_settings_done" msgid="3402999958839153376">"Udført"</string>
+ <string name="quick_settings_done" msgid="3402999958839153376">"Udfør"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"Tilsluttet"</string>
<string name="quick_settings_connecting" msgid="47623027419264404">"Opretter forbindelse…"</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"Netdeling"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel ved <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbejdstilstand"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nattelys"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Nattelys er tændt. Tryk for at slukke"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Nattelys er slukket. Tryk for at tænde"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Ingen nye elementer"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har ryddet alt"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Oplysninger om applikationen"</string>
@@ -521,7 +518,7 @@
<string name="notification_importance_high" msgid="1729480727023990427">"Se altid smugkig. Ingen afbrydelse af fuld skærm."</string>
<string name="notification_importance_max" msgid="2508384624461849111">"Se altid smugkig, og tillad afbrydelse af fuld skærm."</string>
<string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
- <string name="notification_done" msgid="5279426047273930175">"Færdig"</string>
+ <string name="notification_done" msgid="5279426047273930175">"Udfør"</string>
<string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolelementer til underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="battery_panel_title" msgid="7944156115535366613">"Batteriforbrug"</string>
<string name="battery_detail_charging_summary" msgid="1279095653533044008">"Batterisparefunktionen er ikke tilgængelig under opladning"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 5aa99a1..68af5e5 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-Daten pausiert"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilfunkdaten pausiert"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Daten pausiert"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Das von dir festgelegte Datenlimit wurde erreicht. Die mobile Datennutzung wurde deaktiviert.\n\nWenn du weiterhin mobile Daten nutzt, können Gebühren anfallen."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Fortsetzen"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
@@ -271,7 +270,7 @@
<string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
<string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Geräte)"</string>
<string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"Bluetooth aus"</string>
- <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Keine Pairing-Geräte verfügbar"</string>
+ <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Keine gekoppelten Geräte verfügbar"</string>
<string name="quick_settings_brightness_label" msgid="6968372297018755815">"Helligkeit"</string>
<string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatisch drehen"</string>
<string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Bildschirm automatisch drehen"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Warnung für <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbeitsmodus"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nachtlicht"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Nachtlicht an, zum Deaktivieren tippen"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Nachtlicht aus, zum Aktivieren tippen"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Keine kürzlich verwendeten Elemente"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du hast alles gelöscht"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"App-Info"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 4c5718b..d8d5e09 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Τα δεδομένα 4G τέθηκαν σε παύση"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Τα δεδομένα κινητής τηλεφωνίας τέθηκαν σε παύση"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Τα δεδομένα τέθηκαν σε παύση"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Το όριο δεδομένων που ορίσατε έχει εξαντληθεί. Δεν χρησιμοποιείτε πλέον δεδομένα κινητής τηλεφωνίας.\n\nΑν συνεχίσετε, ενδέχεται να ισχύσουν χρεώσεις για τη χρήση δεδομένων."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Συνέχιση"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Χωρ. σύνδ. στο Διαδ."</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi συνδεδεμένο"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Προειδοποίηση για <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Λειτουργία εργασίας"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Νυχτερινός φωτισμός"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Ο Νυχτερινός φωτισμός είναι ενεργοποιημένος. Πατήστε για απενεργοποίηση."</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Ο Νυχτερινός φωτισμός είναι απενεργοποιημένος. Πατήστε για ενεργοποίηση."</string>
<string name="recents_empty_message" msgid="808480104164008572">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Έχει γίνει εκκαθάριση όλων των στοιχείων"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Πληροφορίες εφαρμογής"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index d12b448..570ee82 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Night Light on, tap to turn off"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Night Light off, tap to turn on"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index d12b448..570ee82 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Night Light on, tap to turn off"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Night Light off, tap to turn on"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index d12b448..570ee82 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"The data limit you have set has been reached. You are no longer using mobile data.\n\nIf you resume, charges may apply for data usage."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> warning"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Night Light on, tap to turn off"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Night Light off, tap to turn on"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No recent items"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"You\'ve cleared everything"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Application Info"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 45198cf..7b09b25 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Se alcanzó el límite de datos que estableciste. Ya no estás usando datos móviles.\n\nSi reanudas el uso de datos, es posible que se apliquen cargos."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabajo"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz nocturna"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Presiona para desactivar la Luz nocturna"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Presiona para activar la Luz nocturna"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No hay elementos recientes"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Todo borrado"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 3d69e5e..004a2b4 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -232,15 +232,14 @@
<string name="accessibility_quick_settings_work_mode_on" msgid="7650588553988014341">"Modo de trabajo activado."</string>
<string name="accessibility_quick_settings_work_mode_changed_off" msgid="5605534876107300711">"Modo de trabajo desactivado."</string>
<string name="accessibility_quick_settings_work_mode_changed_on" msgid="249840330756998612">"Modo de trabajo activado."</string>
- <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Economizador de Datos desactivado."</string>
- <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Economizador de Datos activado."</string>
+ <string name="accessibility_quick_settings_data_saver_changed_off" msgid="650231949881093289">"Ahorro de datos desactivado."</string>
+ <string name="accessibility_quick_settings_data_saver_changed_on" msgid="4218725402373934151">"Ahorro de datos activado."</string>
<string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de la pantalla"</string>
<string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Datos 2G-3G pausados"</string>
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Se ha alcanzado el límite de datos establecido. Ya no estás utilizando datos móviles.\n\nSi vuelves a activar el uso de datos, es posible que se apliquen cargos."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Con conexión Wi-Fi"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabajo"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz nocturna"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Luz nocturna activada; toca aquí para desactivarla"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Luz nocturna desactivada; toca aquí para activarla"</string>
<string name="recents_empty_message" msgid="808480104164008572">"No hay elementos recientes"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Has rechazado todo"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información de la aplicación"</string>
@@ -580,9 +577,9 @@
<string name="headset" msgid="4534219457597457353">"Auriculares"</string>
<string name="accessibility_status_bar_headphones" msgid="9156307120060559989">"Auriculares conectados"</string>
<string name="accessibility_status_bar_headset" msgid="8666419213072449202">"Auriculares conectados"</string>
- <string name="data_saver" msgid="5037565123367048522">"Economizador de Datos"</string>
- <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Economizador de Datos activado"</string>
- <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Economizador de Datos desactivado"</string>
+ <string name="data_saver" msgid="5037565123367048522">"Ahorro de datos"</string>
+ <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Ahorro de datos activado"</string>
+ <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Ahorro de datos desactivado"</string>
<string name="switch_bar_on" msgid="1142437840752794229">"Sí"</string>
<string name="switch_bar_off" msgid="8803270596930432874">"No"</string>
<string name="nav_bar" msgid="1993221402773877607">"Barra de navegación"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 17cbc13..10be679 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G andmekasutus on peatatud"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilse andmeside kasutus on peatatud"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Andmekasutus on peatatud"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Olete jõudnud enda määratud andmemahupiiranguni. Te ei kasuta enam mobiilset andmesidet.\n\nKui jätkate, võivad rakenduda andmekasutustasud."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jätka"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Interneti-ühendus puudub"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WiFi on ühendatud"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> hoiatus"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Töörežiim"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Öövalgus"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Öövalgus on sees, puudutage väljalülitamiseks"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Öövalgus on väljas, puudutage sisselülitamiseks"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Hiljutisi üksusi pole"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Olete kõik ära kustutanud"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Rakenduste teave"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 5715c506..7514e8e 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datuen erabilera eten da"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sare mugikorreko datuen erabilera eten da"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datuen erabilera eten da"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Gainditu egin da ezarri duzun datu-muga. Datu-konexioa erabiltzeari utzi diozu.\n\nBerriro hasten bazara erabiltzen, baliteke datuen erabileraren kostua ordaindu behar izatea."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jarraitu erabiltzen"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ez duzu Interneteko konexiorik"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi konektatuta"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Abisua: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Lan modua"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Gaueko argia"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Aktibatuta dago gaueko argia. Sakatu desaktibatzeko."</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Desaktibatuta dago gaueko argia. Sakatu aktibatzeko."</string>
<string name="recents_empty_message" msgid="808480104164008572">"Ez dago azkenaldi honetako ezer"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Dena garbitu duzu"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Aplikazioaren informazioa"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d92b4c0..a4b9798 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"داده 4G موقتاً متوقف شده است"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"داده شبکه همراه موقتاً متوقف شده است"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"داده موقتاً متوقف شده است"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"به حداکثر محدودیت دادهای که تنظیم کردید رسیدید. دیگر از داده شبکه تلفن همراه استفاده نمیکنید.\n\nدر صورت ازسرگیری، ممکن است مصرف داده هزینههایی دربرداشته باشد."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"از سرگیری"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"اتصال اینترنتی ندارید"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi متصل شد"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"هشدار <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"حالت کار"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"نور شب"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"نور شب روشن است، برای خاموشکردن آن ضربه بزنید"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"نور شب خاموش است، برای روشنشدن آن ضربه بزنید"</string>
<string name="recents_empty_message" msgid="808480104164008572">"بدون موارد اخیر"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"همهچیز را پاک کردهاید"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"اطلاعات برنامه"</string>
@@ -484,7 +481,7 @@
<string name="accessibility_managed_profile" msgid="6613641363112584120">"نمایه کاری"</string>
<string name="tuner_warning_title" msgid="7094689930793031682">"برای بعضی افراد سرگرمکننده است اما نه برای همه"</string>
<string name="tuner_warning" msgid="8730648121973575701">"«تنظیمکننده واسط کاربری سیستم» روشهای بیشتری برای تنظیم دقیق و سفارشی کردن واسط کاربری Android در اختیار شما قرار میدهد. ممکن است این ویژگیهای آزمایشی تغییر کنند، خراب شوند یا در نسخههای آینده جود نداشته باشند. با احتیاط ادامه دهید."</string>
- <string name="tuner_persistent_warning" msgid="8597333795565621795">"ممکن است این ویژگیهای آزمایشی تغییر کنند، خراب شوند یا در نسخههای آینده وجود نداشته باشند. با احتیاط ادامه دهید."</string>
+ <string name="tuner_persistent_warning" msgid="8597333795565621795">"ممکن است این قابلیتهای آزمایشی تغییر کنند، خراب شوند یا در نسخههای آینده وجود نداشته باشد. بااحتیاط ادامه دهید."</string>
<string name="got_it" msgid="2239653834387972602">"متوجه شدم"</string>
<string name="tuner_toast" msgid="603429811084428439">"تبریک میگوییم! «تنظیمکننده واسط کاربری سیستم» به «تنظیمات» اضافه شد"</string>
<string name="remove_from_settings" msgid="8389591916603406378">"حذف از تنظیمات"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 7bb7dd6..42c8ae0 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-tiedonsiirto keskeytettiin"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilitiedonsiirto keskeytettiin"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Tiedonsiirto keskeytettiin"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Määrittämäsi datankäyttöraja on täynnä. Mobiilidata poistettiin käytöstä.\n\nOperaattorisi voi veloittaa sinua, jos jatkat mobiilidatan käyttöä."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jatka"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ei internetyhteyttä"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi yhdistetty"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> – varoitus"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Työtila"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Yövalo"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Yövalo on käytössä. Poista se käytöstä koskettamalla."</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Yövalo ei ole käytössä. Ota se käyttöön koskettamalla."</string>
<string name="recents_empty_message" msgid="808480104164008572">"Ei viimeaikaisia kohteita"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Kaikki on hoidettu."</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Sovellustiedot"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index b0215bd..8b4faef 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données cellulaires désactivées"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"La limite de données que vous avez définie a été atteinte. Vous n\'utilisez plus les données cellulaires.\n\nSi vous rétablissez la connexion de données cellulaires, des frais peuvent s\'appliquer."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprendre"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode Travail"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Éclairage nocturne"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Le mode Éclairage nocturne est activé. Touchez ici pour le désactiver."</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Le mode Éclairage nocturne est désactivé. Touchez ici pour l\'activer."</string>
<string name="recents_empty_message" msgid="808480104164008572">"Aucun élément récent"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vous avez tout effacé"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Détails de l\'application"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 2a37637..52728bd 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données mobiles désactivées"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"La limite de consommation des données que vous avez définie a été atteinte. Vous n\'utilisez plus les données mobiles.\n\nSi vous les réactivez, des frais pourront être facturés."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Réactiver"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertissement : <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode Travail"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Éclairage nocturne"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Éclairage nocturne activé, appuyer pour désactiver"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Éclairage nocturne désactivé, appuyer pour activer"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Aucun élément récent"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vous avez tout effacé."</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Infos application"</string>
@@ -448,7 +445,7 @@
<string-array name="volume_stream_titles">
<item msgid="5841843895402729630">"Appeler"</item>
<item msgid="5997713001067658559">"Système"</item>
- <item msgid="7858983209929864160">"Faire sonner"</item>
+ <item msgid="7858983209929864160">"Sonnerie"</item>
<item msgid="1850038478268896762">"Multimédia"</item>
<item msgid="8265110906352372092">"Alarme"</item>
<item msgid="5339394737636839168"></item>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 40c5ca7..d489a64 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os datos 4G están en pausa"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os datos de móbiles están en pausa"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os datos están en pausa"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Alcanzouse o límite de datos establecido e xa non utilizas datos móbiles.\n\nSe continúas, é posible que se apliquen cargos por uso de datos."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sen Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectada"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advertencia <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de traballo"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz nocturna"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"A función Luz nocturna está activada. Toca para desactivala"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"A función Luz nocturna está desactivada. Toca para activala"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Non hai elementos recentes"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Borraches todo"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Información da aplicación"</string>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 5b3c9c2..42546f6e 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ડેટા થોભાવ્યો છે"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"સેલ્યુલર ડેટા થોભાવ્યો છે"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ડેટા થોભાવ્યો છે"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"તમારા દ્વારા સેટ કરેલ ડેટા મર્યાદા પર તમે પહોંચી ગયાં છો. તમે હવે સેલ્યુલર ડેટાનો ઉપયોગ કરી રહ્યાં નથી.\n\nજો તમે ફરી શરૂ કરો છો, તો ડેટા વપરાશ માટે શુલ્ક લાગુ થઈ શકે છે."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ફરી શરૂ કરો"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"કોઈ ઇન્ટરનેટ કનેક્શન નથી"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi કનેક્ટ કર્યું"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ચેતવણી"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"કાર્ય મોડ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"રાત્રિ પ્રકાશ"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"રાત્રિ પ્રકાશ ચાલુ છે, બંધ કરવા માટે ટપ કરો"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"રાત્રિ પ્રકાશ બંધ છે, ચાલુ કરવા માટે ટૅપ કરો"</string>
<string name="recents_empty_message" msgid="808480104164008572">"કોઇ તાજેતરની આઇટમ્સ નથી"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"તમે બધું સાફ કર્યું"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ઍપ્લિકેશન માહિતી"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 217a5f1..49a4650 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोक दिया गया है"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटा रोक दिया गया है"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोक दिया गया है"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"आपकी सेट की हुई डेटा सीमा समाप्त हो गई है. अब आप सेल्युलर डेटा का उपयोग नहीं कर रहे हैं.\n\nयदि आप फिर से शुरू करते हैं, तो डेटा उपयोग के लिए शुल्क लग सकता है."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"फिर से शुरू करें"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"कोई इंटरनेट कनेक्शन नहीं"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाई-फ़ाई कनेक्ट किया गया"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"नाइट लाइट"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"नाइट लाइट चालू है, बंद करने के लिए टैप करें"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"नाइट लाइट बंद है, चालू करने के लिए टैप करें"</string>
<string name="recents_empty_message" msgid="808480104164008572">"हाल ही का कोई आइटम नहीं"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"आपने सब कुछ साफ़ कर दिया है"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"एप्लिकेशन जानकारी"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index a9815d5..1bbae8b 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -238,8 +238,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci pauzirani"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci pauzirani"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosegnuto je vaše ograničenje podataka. Više ne upotrebljavate mobilne podatke.\n\nAko nastavite, moguća je naplata za potrošnju podataka."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internetske veze"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozorenje <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Način rada"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Noćno svjetlo"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Noćno je svjetlo uključeno, dodirnite da biste ga isključili"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Noćno je svjetlo isključeno, dodirnite da biste ga uključili"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nema nedavnih stavki"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Izbrisali ste sve"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacije o aplikaciji"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 9fd4eb7..7792ac1 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"A 4G adatforgalom szünetel"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"A mobilhálózati adatforgalom szünetel"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Az adatforgalom szünetel"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Elérte a beállított adatkorlátot. A továbbiakban nem használ mobiladat-forgalmat.\n\nHa a folytatást választja, szolgáltatója adathasználati díjat számíthat fel."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Folytatás"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nincs internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi csatlakoztatva"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Figyelem! <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Munka mód"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Éjszakai fény"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Éjszakai fény bekapcsolva, koppintson a kikapcsoláshoz"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Éjszakai fény kikapcsolva, koppintson a bekapcsoláshoz"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nincsenek mostanában használt elemek"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Mindent törölt"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Az alkalmazás adatai"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 236663d..9d07927 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Գ տվյալների օգտագործումը դադարեցված է"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Բջջային տվյալների օգտագործումը դադարեցված է"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Տվյալների օգտագործումը դադարեցված է"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Տվյալների օգտագործման համար նշված սահմանաչափը լրացել է: Դուք բջջային տվյալներ այլևս չեք օգտագործում:\n\nԵթե վերսկսեք բջջային տվյալների օգտագործումը, դրա համար կարող են վճարներ գանձվել:"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Վերսկսել"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ինտերնետ կապ չկա"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ը միացված է"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> զգուշացում"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Աշխատանքային ռեժիմ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Գիշերային լույս"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Գիշերային լույսը միացված է, հպեք՝ անջատելու համար"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Գիշերային լույսն անջատված է, հպեք՝ միացնելու համար"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Վերջին տարրեր չկան"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Դուք ջնջել եք ամենը"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Հավելվածի մասին"</string>
@@ -644,7 +641,7 @@
<string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Բացել կարգավորումները:"</string>
<string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Բացել արագ կարգավորումները:"</string>
<string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Փակել արագ կարգավորումները:"</string>
- <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Զարթուցիչը կարգավորված է:"</string>
+ <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Զարթուցիչը դրված է:"</string>
<string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Մուտք է գործել որպես <xliff:g id="ID_1">%s</xliff:g>"</string>
<string name="accessibility_quick_settings_no_internet" msgid="31890692343084075">"Ինտերնետ կապ չկա:"</string>
<string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Բացել մանրամասները:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 5e26008..20ef37d 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data seluler dijeda"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Batas data yang disetel telah tercapai. Anda tidak menggunakan data seluler lagi.\n\nJika Anda melanjutkan, biaya penggunaan data mungkin berlaku."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Lanjutkan"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tidak ada sambungan internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tersambung"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Peringatan <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mode kerja"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Cahaya Malam"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Cahaya Malam hidup, ketuk untuk mematikan"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Cahaya Malam mati, ketuk untuk menyalakan"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Tidak ada item baru-baru ini"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Anda sudah menghapus semua"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Info Aplikasi"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 02b59b6..6a5de8a 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Slökkt er á 4G-gögnum"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Slökkt er á farsímagögnum"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Slökkt er á gagnanotkun"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Gagnamörkunum sem þú stilltir hefur verið náð. Þú ert ekki lengur að nota farsímagögn.\n\nEf þú heldur áfram gætu gjöld fyrir gagnanotkun átt við."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Halda áfram"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Engin nettenging"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tengt"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> viðvörun"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Vinnustilling"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Næturljós"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Kveikt á næturljósi, ýttu til að slökkva"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Slökkt á næturljósi, ýttu til að kveikja"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Engin nýleg atriði"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Þú hefur hreinsað allt"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Forritsupplýsingar"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 9d76477..39221ad 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dati 4G sospesi"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dati cellulari sospesi"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dati sospesi"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"È stato raggiunto il limite di dati impostato. La rete dati è stata disattivata.\n\nSe la riattivi, potrebbero essere applicati costi per l\'utilizzo dei dati."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Riprendi"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nessuna connessione"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connesso"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avviso <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modalità Lavoro"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luminosità notturna"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Luminosità notturna attiva, tocca per disattivarla"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Luminosità notturna disattivata, tocca per attivarla"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nessun elemento recente"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hai cancellato tutto"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informazioni sull\'applicazione"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 3429497..43eeae4 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"השימוש בנתוני 4G מושהה"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"השימוש בנתונים סלולריים מושהה"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"השימוש בנתונים מושהה"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"הגעת למגבלת הנתונים שהגדרת. אתה כבר לא משתמש בנתונים סלולריים.\n\nאם תמשיך, ייתכנו חיובים לשימוש בנתונים."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"המשך"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"אין חיבור לאינטרנט"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi מחובר"</string>
@@ -324,8 +323,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"אזהרה - <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"מצב עבודה"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"תאורת לילה"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"תאורת לילה פועלת, הקש כדי לכבות"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"תאורת לילה כבויה, הקש כדי להפעיל"</string>
<string name="recents_empty_message" msgid="808480104164008572">"אין פריטים אחרונים"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"מחקת הכול"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"מידע על האפליקציה"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index bbd8033..7df0a9e 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Gデータは一時停止中です"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"モバイルデータは一時停止中です"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"データの一時停止"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"設定されたデータの上限に達しているため、モバイルデータの使用を停止しました。\n\n再開すると、携帯通信会社からデータ使用量に応じた通信料を課金される可能性があります。"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"再開"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"インターネット未接続"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi接続済み"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"警告: 上限は<xliff:g id="DATA_LIMIT">%s</xliff:g>です"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work モード"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"読書灯"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"読書灯 ON: タップすると OFF になります"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"読書灯 OFF: タップすると ON になります"</string>
<string name="recents_empty_message" msgid="808480104164008572">"最近のタスクはありません"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"すべてのタスクを消去しました"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"アプリ情報"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index c00c54c..a63de78 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G მონაცემები შეჩერებულია"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ფიჭური მონაცემები შეჩერებულია"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"მონაცემები შეჩერებულია"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"მიღწეულია მონაცემთა მოხმარების თქვენ მიერ მითითებული ლიმიტი. ამიტომ, მობილური ინტერნეტის გამოყენება აღარ ხდება.\n\nგანახლების შემთხვევაში, შეიძლება მობილური ინტერნეტის საფასურის გადახდა მოგიწიოთ."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"გაგრძელება"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ინტერნეტ კავშირი არ არის"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi დაკავშირებულია"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> გაფრთხილება"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"სამსახურის რეჟიმი"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ღამის განათება"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"ღამის განათება ჩართულია, შეეხეთ გამოსართავად"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"ღამის განათება გამორთულია, შეეხეთ ჩასართავად"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ყველაფერი გასუფთავდა"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"აპლიკაციის შესახებ"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 8051cd8..f39e44a 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G деректері кідіртілді"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Ұялы деректер кідіртілді"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Деректер кідіртілді"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Белгіленген деректер шегіне жеттіңіз. Ұялы деректер енді пайдаланылмайды.\n\nЕгер жалғастырсаңыз, деректер трафигі үшін ақы алынуы мүмкін."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Жалғастыру"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланысы жоқ"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi қосулы"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> туралы ескерту"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Жұмыс режимі"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Түнгі жарық"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Түнгі жарық қосулы, өшіру үшін оны түртіңіз"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Түнгі жарық өшірулі, қосу үшін оны түртіңіз"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Жақындағы элементтер жоқ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Сіз барлығын өшірдіңіз"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Қолданба туралы ақпарат"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index c0d002c..36d0e44 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ទិន្នន័យ 4G ត្រូវបានផ្អាក"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ទិន្នន័យចល័តត្រូវបានផ្អាក"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ទិន្នន័យត្រូវបានផ្អាក"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"បានឈានដល់កម្រិតទិន្នន័យដែលអ្នកបានកំណត់ហើយ។ ឥឡូវអ្នកមិនប្រើទិន្នន័យចល័តទៀតទេ។\n\nអាចនឹងគិតថ្លៃលើការប្រើទិន្នន័យ ប្រសិនបើអ្នកបន្តប្រើឡើងវិញ។"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"បន្ត"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"គ្មានការតភ្ជាប់អ៊ីនធឺណិត"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"បានភ្ជាប់វ៉ាយហ្វាយ"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ការព្រមាន"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"របៀបការងារ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ពន្លឺពេលយប់"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"ពន្លឺពេលយប់បើកហើយ ប៉ះដើម្បីបិទ"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"ពន្លឺពេលយប់បិទហើយ ប៉ះដើម្បីបើក"</string>
<string name="recents_empty_message" msgid="808480104164008572">"មិនមានធាតុថ្មីៗទេ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"អ្នកបានជម្រះអ្វីៗទាំងអស់"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ព័ត៌មានកម្មវិធី"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index e1c42d7..3f74b1d 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -84,7 +84,7 @@
<string name="accessibility_home" msgid="8217216074895377641">"ಮುಖಪುಟ"</string>
<string name="accessibility_menu" msgid="316839303324695949">"ಮೆನು"</string>
<string name="accessibility_recent" msgid="5208608566793607626">"ಸಮಗ್ರ ನೋಟ"</string>
- <string name="accessibility_search_light" msgid="1103867596330271848">"ಹುಡುಕು"</string>
+ <string name="accessibility_search_light" msgid="1103867596330271848">"ಹುಡುಕಿ"</string>
<string name="accessibility_camera_button" msgid="8064671582820358152">"ಕ್ಯಾಮರಾ"</string>
<string name="accessibility_phone_button" msgid="6738112589538563574">"ಫೋನ್"</string>
<string name="accessibility_voice_assist_button" msgid="487611083884852965">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ನೀವು ಹೊಂದಿಸಿರುವ ಡೇಟಾ ಮಿತಿ ತಲುಪಿದೆ. ನೀವು ಎಂದಿಗೂ ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾವನ್ನು ಬಳಸದೆ ಇರಬಹುದು.\n\nನೀವು ಮುಂದುವರಿಸಿದರೆ, ಡೇಟಾ ಬಳಕೆಗೆ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ಮುಂದುವರಿಸು"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ವೈ-ಫೈ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ಎಚ್ಚರಿಕೆ"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ಕೆಲಸದ ಮೋಡ್"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ನೈಟ್ ಲೈಟ್"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"ನೈಟ್ ಲೈಟ್ ಆನ್ ಆಗಿದೆ, ಆಫ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"ನೈಟ್ ಲೈಟ್ ಆಫ್ ಆಗಿದೆ, ಆನ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ನೀವು ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿರುವಿರಿ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 1c97212..5f1f5cd 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 데이터 사용 중지됨"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"모바일 데이터 사용 중지됨"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"데이터 사용 중지됨"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"설정한 데이터 한도에 도달했습니다. 더 이상 모바일 데이터를 사용하지 않습니다.\n\n계속 사용하면 데이터 사용 요금이 부과될 수 있습니다."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"재개"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"인터넷에 연결되지 않음"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 경고"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"작업 모드"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"야간 조명"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"야간 조명 사용 설정됨, 사용 중지하려면 탭"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"야간 조명 사용 중지됨, 사용 설정하려면 탭"</string>
<string name="recents_empty_message" msgid="808480104164008572">"최근 항목이 없습니다."</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"모든 항목을 삭제했습니다."</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"애플리케이션 정보"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index b17f523..9b35ef7 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дайындары тындырылды"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Уюлдук дайындар тындырылды"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дайындар тындырылды"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Трафик сиз койгон чекке жетти. Эми мобилдик дайындарды колдоно албайсыз.\n\nЭгер улантсаңыз, мобилдик дайындарды колдонгонуңуз үчүн акы алынышы мүмкүн."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Улантуу"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланыш жок"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi байланышта"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> эскертүү"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Иштөө режими"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Түнкү жарык"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Түнкү жарык күйүк, өчүрүү үчүн таптап коюңуз"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Түнкү жарык өчүк, күйгүзүү үчүн таптап коюңуз"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Акыркы колдонмолор жок"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Баарын тазаладыңыз"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Колдонмо жөнүндө маалымат"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 0dc3d50..d4acc77 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ຂໍ້ມູນ 4G ຢຸດຊົ່ວຄາວແລ້ວ"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ຂໍ້ມູນເຊວລູລາຢຸດຊົ່ວຄາວແລ້ວ"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ຂໍ້ມູນຢຸດຊົ່ວຄາວແລ້ວ"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ທ່ານໃຊ້ອິນເຕີເນັດຮອດຈຳນວນທີ່ທ່ານຈຳກັດປະລິມານໄວ້ແລ້ວ. ທ່ານຈະບໍ່ນຳໃຊ້ການເຊື່ອມຕໍ່ຜ່ານເຄືອຂ່າຍມືຖືອີກຕໍ່ໄປ.\n\nຫາກທ່ານສືບຕໍ່ໃຊ້ໄປອີກ, ທ່ານອາດຖືກຮຽກເກັບເງິນຄ່າບໍລິການໄດ້."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ເລີ່ມຕໍ່"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ເຊື່ອມຕໍ່ Wi--Fi ແລ້ວ"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"ຄຳເຕືອນ <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ໂໝດການເຮັດວຽກ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ແສງກາງຄືນ"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"ເປີດແສງກາງຄືນຢູ່, ແຕະເພື່ອປິດໄວ້"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"ປິດແສງກາງຄືນຢູ່, ແຕະເພື່ອເປີດໃຊ້"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ທ່ານລຶບລ້າງທຸກຢ່າງແລ້ວ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ຂໍ້ມູນແອັບພລິເຄຊັນ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index dd2f198..5de6b7f 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G duomenys pristabdyti"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Korinio ryšio duomenys pristabdyti"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Duomenys pristabdyti"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Pasiektas nustatytas duomenų apribojimas. Nebenaudojate mobiliojo ryšio duomenų.\n\nJei atnaujinsite, gali būti taikomi mokesčiai už duomenų naudojimą."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atnaujinti"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nėra interneto ryš."</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Prisij. prie „Wi-Fi“"</string>
@@ -324,8 +323,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> įspėjimas"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Darbo režimas"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nakties šviesa"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Nakties šviesa įjungta. Palieskite, kad išjungtumėte"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Nakties šviesa išjungta. Palieskite, kad įjungtumėte"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nėra jokių naujausių elementų"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Viską išvalėte"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Programos informacija"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 4242497..091c47f 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -238,8 +238,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datu lietojums ir apturēts"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilo datu lietojums ir apturēts"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datu lietojums ir apturēts"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ir sasniegts jūsu iestatītais datu ierobežojums. Jūs vairs neizmantojat mobilos datus.\n\nJa atsāksiet, var tikt piemērota maksa par datu lietojumu."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atsākt"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nav interneta sav."</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Izv. sav. ar Wi-Fi"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> brīdinājums"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Darba režīms"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nakts režīms"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Nakts režīms ir ieslēgts. Pieskarieties, lai to izslēgtu."</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Nakts režīms ir izslēgts. Pieskarieties, lai to ieslēgtu."</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nav nesenu vienumu"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Visi uzdevumi ir notīrīti"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informācija par lietojumprogrammu"</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 4091bbe..020118b 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Податоците 4G се паузирани"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните податоци се паузирани"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Податоците се паузирани"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Го достигнавте ограничувањето за сообраќај на податоци што сте го поставиле. Веќе не користите мобилен интернет.\n\nДоколку продолжите, ќе ви биде наплатено за потрошениот сообраќај."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Продолжи"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Поврзано на Wi-Fi"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупредување за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Режим на работа"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ноќно светло"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Ноќното светло е вклучено, допрете за да се исклучи"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Ноќното светло е исклучено, допрете за да се вклучи"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Нема неодамнешни ставки"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Исчистивте сѐ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информации за апликацијата"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 6ae547e..e07a758 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"സെല്ലുലാർ ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"നിങ്ങൾ സജ്ജമാക്കിയ ഡാറ്റ പരിധി എത്തിക്കഴിഞ്ഞു. ഇനിയങ്ങോട്ട് നിങ്ങൾ സെല്ലുലാർ ഡാറ്റ ഉപയോഗിക്കില്ല.\n\nതുടരുകയാണെങ്കിൽ, ഡാറ്റാ ഉപയോഗത്തിന് നിരക്കുകൾ ബാധകമായേക്കാം."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"പുനരാരംഭിക്കുക"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ഇന്റർനെറ്റ് കണക്ഷൻ ഇല്ല"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"വൈഫൈ കണക്റ്റുചെയ്തു"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> മുന്നറിയിപ്പ്"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"പ്രവർത്തന മോഡ്"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"നൈറ്റ് ലൈറ്റ്"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"നൈറ്റ് ലൈറ്റ് ഓണാണ്, ഓഫാക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"നൈറ്റ് ലൈറ്റ് ഓഫാണ്, ഓണാക്കുന്നതിന് ടാപ്പുചെയ്യുക"</string>
<string name="recents_empty_message" msgid="808480104164008572">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"നിങ്ങൾ എല്ലാം മായ്ച്ചിരിക്കുന്നു"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ആപ്പ് വിവരം"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 95cbcae..fcd39d9 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -235,8 +235,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дата-г түр зогсоосон байна"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Гар утасны дата-г түр зогсоосон байна"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дата-г түр зогсоосон байна"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Таны тогтоосон дата хэмжээний хязгаарт хүрсэн байна. Та одоогоор мобайл датаг ашиглаагүй байна.\n\nҮргэлжлүүлсэн тохиолдолд төлбөр гарах болно."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Үргэлжлүүлэх"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет холболт байхгүй"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi холбогдсон"</string>
@@ -318,8 +317,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> анхааруулга"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Ажлын горим"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Шөнийн гэрэл"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Шөнийн гэрэл асаалттай байна. Унтраахын тулд товшино уу"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Шөнийн гэрэл унтраалттай байна. Асаахын тулд товшино уу"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Сүүлийн үеийн зүйл байхгүй"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Та бүгдийг нь устгасан"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Аппликешны мэдээлэл"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 830cda4..285fd57 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटास विराम दिला आहे"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटास विराम दिला आहे"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटास विराम दिला आहे"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"आपण सेट केलेली डेटा मर्यादा गाठली आहे. आपण यापुढे मोबाइल डेटा वापरणार नाही.\n\nआपण पुन: सुरु केल्यास, डेटा वापरासाठी शुल्क आकारले जाऊ शकतात."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुन्हा सुरु करा"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इंटरनेट कनेक्शन नाही"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाय-फाय कनेक्ट केले"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावणी"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"रात्रीचा प्रकाश"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"रात्रीचा प्रकाश चालू आहे, बंद करण्यासाठी टॅप करा"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"रात्रीचा प्रकाश बंद आहे, चालू करण्यासाठी टॅप करा"</string>
<string name="recents_empty_message" msgid="808480104164008572">"अलीकडील कोणतेही आयटम नाहीत"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"आपण सर्वकाही साफ केले"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"अनुप्रयोग माहिती"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 82de7a3..88894b5 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data selular dijeda"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Had data yang anda tetapkan telah dicapai. Anda tidak lagi menggunakan data selular.\n\nJika anda menyambung semula, caj mungkin dikenakan untuk penggunaan data."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Sambung semula"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tiada smbg Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi disambungkan"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Amaran <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Mod kerja"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Cahaya Malam"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Cahaya Malam dihidupkan, ketik untuk mematikannya"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Cahaya Malam dimatikan, ketik untuk menghidupkannya"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Tiada item terbaharu"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Anda telah mengetepikan semua item"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Maklumat Aplikasi"</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 3899b00..a79c1ae 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data ခေတ္တရပ်တန့်သည်"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"cellular data ခေတ္တရပ်တန့်သည်"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ဒေတာ ခေတ္တရပ်တန့်သည်"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"သင်သတ်မှတ်ထားသော ဒေတာကန့်သတ်ချက်သို့ ရောက်နေပါပြီ။ သင်သည် ဆယ်လူလာဒေတာကို အသုံးမပြုတော့ပါ။\n\nသင်ဆက်လုပ်မည်ဆိုလျှင် ဒေတာသုံးစွဲမှုအတွက် အခငွေ ကျသင့်မှုရှိနိုင်ပါသည်။"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ပြန်ဆက်လုပ်ရန်"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"အင်တာနက်မရှိ"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ကြိုးမဲ့ဆက်သွယ်မှု"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> သတိပေးချက်"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"အလုပ် မုဒ်"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ညအလင်းရောင်"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"ညအလင်းရောင်ကို ဖွင့်ထားသည်၊ ပိတ်ရန်တို့ပါ"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"ညအလင်းရောင်ကို ပိတ်ထားသည်၊ ဖွင့်ရန်တို့ပါ"</string>
<string name="recents_empty_message" msgid="808480104164008572">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"သင်အားလုံးကို ရှင်းလင်းပြီးပါပြီ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"အပလီကေးရှင်းအင်ဖို"</string>
@@ -588,7 +585,7 @@
<string name="center" msgid="4327473927066010960">"ဌာန"</string>
<string name="end" msgid="125797972524818282">"ပြီးပါပြီ"</string>
<string name="space" msgid="804232271282109749">"နေရာလွတ်ခြားစနစ်"</string>
- <string name="menu_ime" msgid="4943221416525250684">"မန်နယူး / ကီးဘုတ်ပြောင်းစနစ်"</string>
+ <string name="menu_ime" msgid="4943221416525250684">"မီနူး / ကီးဘုတ်ပြောင်းစနစ်"</string>
<string name="select_button" msgid="1597989540662710653">"ပေါင်းထည့်ရန် ခလုတ်ကိုရွေးပါ"</string>
<string name="add_button" msgid="4134946063432258161">"ခလုတ်ပေါင်းထည့်ပါ"</string>
<string name="save" msgid="2311877285724540644">"သိမ်းရန်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 0a4e045..1784641 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er satt på pause"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er satt på pause"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er satt på pause"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Datagrensen du satte, er nådd. Du bruker ikke mobildata lenger.\n\nHvis du gjenopptar bruk av mobildata, kan gebyrer for databruk påløpe."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Gjenoppta"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen Internett-forbindelse"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tilkoblet"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Advarsel for <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbeidsmodus"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nattlys"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Nattlys er på, trykk for å slå av"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Nattlys er av, trykk for å slå på"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Ingen nylige elementer"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har fjernet alt"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformasjon"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 47d326c..625f959 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोकिएको छ"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्यूलर डेटा रोकिएको छ"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोकिएको छ"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"तपाईँले सेट गर्नुभएको डेटाको सीमामा पुगिएको छ। अबदेखि तपाईँ सेलुलर डेटाको प्रयोग गर्नुहुने छैन। \n\nतपाईँले प्रयोग जारी राख्नुभयो भने डेटा प्रयोगका शुल्कहरू लाग्न सक्छन्।"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुनः सुरु गर्नुहोस्"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi जडित"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> चेतावनी दिँदै"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"कार्य मोड"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"रात्रिको प्रकाश"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"रात्रिको प्रकाश सक्रिय छ, निष्क्रिय पार्न ट्याप गर्नुहोस्"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"रात्रिको प्रकाश निष्क्रिय छ, सक्रिय गर्न ट्याप गर्नुहोस्"</string>
<string name="recents_empty_message" msgid="808480104164008572">"हालका कुनै पनि वस्तुहरू छैनन्"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"तपाईँले सबै कुरा खाली गर्नुभएको छ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"अनुप्रयोग जानकारी"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 49319d1..f7e180f 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele gegevens zijn onderbroken"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"De ingestelde datalimiet is bereikt. Je gebruikt geen mobiele data meer.\n\nAls je hervat, kunnen er kosten voor datagebruik in rekening worden gebracht."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Verbonden via wifi"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Waarschuwing voor <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Werkmodus"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nachtverlichting"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Nachtverlichting is ingeschakeld. Tik om deze uit te schakelen."</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Nachtverlichting is uitgeschakeld. Tik om deze in te schakelen."</string>
<string name="recents_empty_message" msgid="808480104164008572">"Geen recente items"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Je hebt alles gewist"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"App-informatie"</string>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 082ff3a..0587023 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ਸੈਲਿਊਲਰ ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ਡੈਟਾ ਰੁਕ ਗਿਆ ਹੈ"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ਤੁਸੀਂ ਤੁਹਾਡੇ ਵੱਲੋਂ ਸੈੱਟ ਕੀਤੀ ਗਈ ਡੈਟਾ ਸੀਮਾ \'ਤੇ ਪਹੁੰਚ ਚੁੱਕੇ ਹੋ। ਤੁਸੀਂ ਹੁਣ ਸੈਲਿਊਲਰ ਡੈਟੇ ਦੀ ਵਰਤੋਂ ਨਹੀਂ ਕਰ ਰਹੇ ਹੋ।\n\nਜੇਕਰ ਤੁਸੀਂ ਮੁੜ-ਸ਼ੁਰੂ ਕਰਦੇ ਹੋ, ਤਾਂ ਡੈਟਾ ਵਰਤੋਂ ਲਈ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ਕੋਈ ਇੰਟਰਨੈਟ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ਕਨੈਕਟ ਕੀਤਾ"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> ਚਿਤਾਵਨੀ"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"ਕੰਮ ਮੋਡ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"ਰਾਤਰੀ ਲਾਈਟ"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"ਰਾਤਰੀ ਲਾਈਟ ਚਾਲੂ ਹੈ, ਬੰਦ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"ਰਾਤਰੀ ਲਾਈਟ ਬੰਦ ਹੈ, ਚਾਲੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮਾਂ ਨਹੀਂ"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ਤੁਸੀਂ ਸਭ ਕੁਝ ਸਾਫ਼ ਕਰ ਦਿੱਤਾ ਹੈ"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ਐਪਲੀਕੇਸ਼ਨ ਜਾਣਕਾਰੀ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 52bce7c..5bf6a99 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Transmisja danych 4G została wstrzymana"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Komórkowa transmisja danych została wstrzymana"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Transmisja danych została wstrzymana"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Osiągnięto ustawiony limit danych. Nie korzystasz już z komórkowej transmisji danych.\n\nJeśli włączysz ją ponownie, może zostać naliczona opłata za transmisję danych."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Wznów"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Brak internetu"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string>
@@ -324,8 +323,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ostrzeżenie: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Tryb pracy"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Podświetlenie nocne"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Podświetlenie nocne włączone – kliknij, by wyłączyć"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Podświetlenie nocne wyłączone – kliknij, by włączyć"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Brak ostatnich elementów"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Wszystko zostało wyczyszczone"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacje o aplikacji"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 5ecf074..aa1e718 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados que você definiu foi atingido. Você não está mais usando os dados da rede celular.\n\nSe retomar o uso de dados, cobranças poderão ser aplicadas."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Modo noturno"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Modo noturno ativado. Toque para desativar"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Modo noturno desativado. Toque para ativar"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Você limpou tudo"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do app"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index c1e662c..6037da1 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dados 4G em pausa"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dados de redes móveis em pausa"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dados em pausa"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados definido foi atingido. Já não está a utilizar dados móveis.\n\nSe retomar, podem aplicar-se custos relativos à utilização de dados."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem ligação internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ligado"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Luz noturna"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Luz noturna ativada; toque para desativar"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Luz noturna desativada; toque para ativar"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Limpou tudo"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações da aplicação"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 5ecf074..aa1e718 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O limite de dados que você definiu foi atingido. Você não está mais usando os dados da rede celular.\n\nSe retomar o uso de dados, cobranças poderão ser aplicadas."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Aviso de <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modo de trabalho"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Modo noturno"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Modo noturno ativado. Toque para desativar"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Modo noturno desativado. Toque para ativar"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nenhum item recente"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Você limpou tudo"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informações do app"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index bedb7d0..da6a32d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -240,8 +240,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Conexiunea de date 4G este întreruptă"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Conexiunea de date mobile este întreruptă"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Conexiunea de date este întreruptă"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"A fost atinsă limita de date setată. Datele mobile nu mai sunt folosite \n\nDacă reluați, este posibil să se aplice taxe pentru utilizarea datelor."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reluați"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Fără conex. internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string>
@@ -324,12 +323,10 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Avertizare: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modul de lucru"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Lumină de noapte"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Lumina de noapte este activată; atingeți pentru a o dezactiva"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Lumina de noapte este dezactivată; atingeți pentru a o activa"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Niciun element recent"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ați șters tot"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informații despre aplicație"</string>
- <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixare pe ecran"</string>
+ <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"fixarea ecranului"</string>
<string name="recents_search_bar_label" msgid="8074997400187836677">"căutare"</string>
<string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> nu a putut porni."</string>
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplicația <xliff:g id="APP">%s</xliff:g> este dezactivată în modul sigur."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a155104..8257b87 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -241,8 +241,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передача данных 4G приостановлена"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передача мобильных данных приостановлена"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передача данных приостановлена"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Достигнут установленный вами лимит на передачу мобильных данных.\n\nЕсли вы продолжите, может взиматься дополнительная плата."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Возобновить"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нет интернет-подключения"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string>
@@ -326,8 +325,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Предупреждение: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Рабочий режим"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ночной режим"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Ночной режим включен. Нажмите, чтобы отключить."</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Ночной режим отключен. Нажмите, чтобы включить."</string>
<string name="recents_empty_message" msgid="808480104164008572">"Недавних приложений нет"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Вы очистили всё"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Сведения о приложении"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 567d9e9..7ee1e6b 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G දත්ත විරාම කර ඇත"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"සෙලියුලර් දත්ත විරාම කර ඇත"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"දත්ත විරාම කර ඇත"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"ඔබ සැකසූ දත්ත සීමාව ළඟා වී ඇත. ඔබ තවදුරටත් සෙලියුලර් දත්ත භාවිත නොකරයි. \n\nඔබ නැවත ආරම්භ කළහොත්, දත්ත භාවිතය සඳහා ගාස්තු අදාළ විය හැකිය."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"නැවත පටන්ගන්න"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"අන්තර්ජාල සම්බන්ධතාවයක් නැත"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi සම්බන්ධිතයි"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> අවවාද කිරීම"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"වැඩ ප්රකාරය"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"රාත්රී ආලෝකය"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"රාත්රී ආලෝකය ක්රියාත්මකයි, ක්රියාවිරහිත කිරීමට තට්ටු කරන්න"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"රාත්රී ආලෝකය ක්රියාවිරහිතයි, ක්රියාත්මක කිරීමට තට්ටු කරන්න"</string>
<string name="recents_empty_message" msgid="808480104164008572">"මෑත අයිතම නැත"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"ඔබ සියලු දේ හිස් කර ඇත"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"යෙදුම් තොරතුරු"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 527a1fc..9b68465 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -241,8 +241,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dátové prenosy 4G sú pozastavené"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilné dáta sú pozastavené"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dáta sú pozastavené"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosiahli ste nastavený limit dát. Už nepoužívate mobilné dátové pripojenie.\n\nAk ho však obnovíte, môžu vám byť účtované poplatky za spotrebu dát."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Znova spustiť"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Bez prip. na Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: pripojené"</string>
@@ -326,8 +325,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Upozornenie pri <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Pracovný režim"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nočný režim"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Nočný režim je zapnutý (vypnete ho klepnutím)"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Nočný režim je vypnutý (zapnete ho klepnutím)"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Žiadne nedávne položky"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vymazali ste všetko"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informácie o aplikácii"</string>
@@ -571,7 +568,7 @@
<string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"Prehliadač"</string>
<string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"Kontakty"</string>
<string name="keyboard_shortcut_group_applications_email" msgid="6257036897441939004">"E-mail"</string>
- <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Okamžité správy"</string>
+ <string name="keyboard_shortcut_group_applications_im" msgid="1892749399083161405">"Čet"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="4775559515850922780">"Hudba"</string>
<string name="keyboard_shortcut_group_applications_youtube" msgid="6555453761294723317">"YouTube"</string>
<string name="keyboard_shortcut_group_applications_calendar" msgid="9043614299194991263">"Kalendár"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 3134962..fccd6f9 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -241,8 +241,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Prenos podatkov v omrežju 4G je zaustavljen"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Prenos mobilnih podatkov je zaustavljen"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prenos podatkov je zaustavljen"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Dosegli ste nastavljeno omejitev porabe podatkov. Prenosa podatkov v mobilnih omrežjih ne uporabljate več.\n\nČe nadaljujete, lahko nastanejo stroški prenosa podatkov."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nadaljuj"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ni internetne povez."</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
@@ -326,8 +325,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Opozorilo – <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Način za delo"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nočna svetloba"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Nočna svetloba je vklopljena. Dotaknite se, če jo želite izklopiti."</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Nočna svetloba je izklopljena. Dotaknite se, če jo želite vklopiti."</string>
<string name="recents_empty_message" msgid="808480104164008572">"Ni nedavnih elementov"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Vse te počistili"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Podatki o aplikaciji"</string>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index afa7694..855c96c 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Të dhënat 4G janë ndërprerë"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Të dhënat celulare janë ndërprerë"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Të dhënat janë ndërprerë"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Kufiri i të dhënave që ke caktuar është arritur. Nuk po përdor më të dhënat celulare.\n\nNëse vazhdon, mund të zbatohen tarifa për përdorimin e të dhënave."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Rifillo"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nuk ka lidhje interneti"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi është i lidhur"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Paralajmërim për kufirin prej <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Modaliteti i punës"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Drita e natës"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Drita e natës është joaktive, trokit për ta çaktivizuar"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Drita e natës është joaktive, trokit për ta aktivizuar"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Nuk ka asnjë artikull të fundit"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"I ke pastruar të gjitha"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Informacioni i aplikacionit"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 06fabee..22b0ba1 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -238,8 +238,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G подаци су паузирани"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилни подаци су паузирани"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Подаци су паузирани"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ограничење потрошње података које сте подесили је достигнуто. Више не користите мобилне податке.\n\nАко наставите, можда ће бити наплаћени трошкови за потрошњу података."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Настави"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет везе"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi је повезан"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Упозорење за <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Режим рада"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ноћно светло"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Ноћно светло је укључено, додирните да бисте га искључили"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Ноћно светло је искључено, додирните да бисте га укључили"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Нема недавних ставки"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Обрисали сте све"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Информације о апликацији"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 8b110c5..830df0c 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data har pausats"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata har pausats"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dataanvändningen har pausats"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Den angivna datagränsen har uppnåtts. Du använder inte längre mobildata.\n\nOm du fortsätter kan avgifter för dataanvändning tillkomma."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Återuppta"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen anslutning"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ansluten"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Varning <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Arbetsläge"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Nattljus"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Nattljus har aktiverats. Tryck för att inaktivera"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Nattljus har inaktiverats. Tryck för att aktivera"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Listan med de senaste åtgärderna är tom"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Du har tömt listan"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Appinformation"</string>
@@ -331,7 +328,7 @@
<string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> är inaktiverad i säkert läge."</string>
<string name="recents_stack_action_button_label" msgid="6593727103310426253">"Rensa alla"</string>
<string name="recents_incompatible_app_message" msgid="5075812958564082451">"Appen har inte stöd för delad skärm."</string>
- <string name="recents_drag_hint_message" msgid="2649739267073203985">"Dra här om du vill dela upp skärmen"</string>
+ <string name="recents_drag_hint_message" msgid="2649739267073203985">"Dra hit för att dela upp skärmen"</string>
<string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Dela horisontellt"</string>
<string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Dela vertikalt"</string>
<string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Dela anpassad"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index be91af3..9ec6ca8 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data ya 4G imesitishwa"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data ya simu ya mkononi imesitishwa"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data imesitishwa"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Umefikia kikomo cha data ulichoweka. Hutaweza kutumia tena data ya simu ya mkononi.\n\nIkiwa utaendelea, huenda ukatozwa ada za matumizi ya data."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Endelea"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Hakuna muunganisho wa mtandao"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Mtandao-hewa umeunganishwa"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Onyo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Hali ya kazi"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Mwanga wa Usiku"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Umewasha hali ya Mwanga wa Usiku, gonga ili uizime"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Umezima hali ya Mwanga wa Usiku, gonga ili uiwashe"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Hakuna vipengee vya hivi karibuni"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Umeondoa vipengee vyote"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Maelezo ya Programu"</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 799d628..30223c7 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G டேட்டா இடைநிறுத்தப்பட்டது"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"செல்லுலார் தரவு இடைநிறுத்தப்பட்டது"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"தரவு இடைநிறுத்தப்பட்டது"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"நீங்கள் அமைத்த தரவு வரம்பை அடைந்துவிட்டீர்கள். இப்போது செல்லுலார் தரவைப் பயன்படுத்த முடியாது.\n\nமீண்டும் தொடங்கினால், தரவுப் பயன்பாட்டிற்குக் கட்டணங்கள் விதிக்கப்படலாம்."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"மீண்டும் தொடங்கு"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"இணைய இணைப்பு இல்லை"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"வைஃபை இணைக்கப்பட்டது"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> எச்சரிக்கை"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"பணிப் பயன்முறை"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"இரவு ஒளி"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"இரவு ஒளி இயக்கப்பட்டுள்ளது. முடக்க, தட்டவும்"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"இரவு ஒளி முடக்கப்பட்டுள்ளது. இயக்க, தட்டவும்"</string>
<string name="recents_empty_message" msgid="808480104164008572">"சமீபத்திய பணிகள் இல்லை"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"எல்லாவற்றையும் அழித்துவிட்டீர்கள்"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"பயன்பாட்டு தகவல்"</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index f6e3ee2..4613354 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G డేటా పాజ్ చేయబడింది"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"సెల్యులార్ డేటా పాజ్ చేయబడింది"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"డేటా పాజ్ చేయబడింది"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"మీరు సెట్ చేసిన డేటా పరిమితిని చేరుకున్నారు. మీరు ఇప్పుడు సెల్యులార్ డేటాను ఉపయోగించడం లేదు.\n\nమీరు పునఃప్రారంభిస్తే, డేటా వినియోగానికి ఛార్జీలు వర్తించవచ్చు."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"పునఃప్రారంభించు"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ఇంటర్నెట్ కనెక్షన్ లేదు"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi కనెక్ట్ చేయబడింది"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> హెచ్చరిక"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"పని మోడ్"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"రాత్రి కాంతి"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"రాత్రి కాంతి ఆన్లో ఉంది, ఆఫ్ చేయడానికి నొక్కండి"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"రాత్రి కాంతి ఆఫ్లో ఉంది, ఆన్ చేయడానికి నొక్కండి"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ఇటీవలి అంశాలు ఏవీ లేవు"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"మీరు అన్నింటినీ తీసివేసారు"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"అనువర్తన సమాచారం"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0482e3b..804bdef 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"หยุดการใช้ข้อมูล 4G ชั่วคราวแล้ว"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"หยุดการใช้ข้อมูลมือถือชั่วคราวแล้ว"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"หยุดการใช้ข้อมูลชั่วคราวแล้ว"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"คุณใช้อินเทอร์เน็ตเกินปริมาณที่กำหนดไว้ ระบบจะไม่ใช้เครือข่ายมือถือต่อไป\n\nหากใช้ต่อ อาจมีค่าบริการตามปริมาณการใช้อินเทอร์เน็ต"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ทำต่อ"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ไม่มีอินเทอร์เน็ต"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"เชื่อมต่อ WiFi แล้ว"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"คำเตือน <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"โหมดการทำงาน"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"แสงตอนกลางคืน"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"แสงตอนกลางคืนเปิดอยู่ แตะเพื่อปิด"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"แสงตอนกลางคืนปิดอยู่ แตะเพื่อเปิด"</string>
<string name="recents_empty_message" msgid="808480104164008572">"ไม่มีรายการล่าสุด"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"คุณได้ล้างทุกอย่างแล้ว"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ข้อมูลแอปพลิเคชัน"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 9b104f5..e2e8c27 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Naka-pause ang 4G data"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Naka-pause ang cellular data"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Naka-pause ang data"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Naabot na ang limitasyon sa data na itinakda mo. Hindi ka na gumagamit ng cellular data.\n\nKung magpapatuloy ka, maaari kang masingil para sa paggamit ng data."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Ipagpatuloy"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Walang koneksyon sa Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"nakakonekta ang Wi-Fi"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Babala sa <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Work mode"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Night Light"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Naka-on ang Night Light, i-tap upang i-off"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Naka-off ang Night Light, i-tap upang i-on"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Walang mga kamakailang item"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Na-clear mo ang lahat"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Impormasyon ng Application"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index e655cd6..8ee4e1f 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G veri kullanımı duraklatıldı"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Hücresel veri kullanımı duraklatıldı"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Veri kullanımı duraklatıldı"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ayarladığınız veri limitine ulaşıldı. Artık hücresel verilerinizi kullanmıyorsunuz.\n\nHücresel veri kullanımını devam ettirirseniz veri kullanım ücretleri ödemeniz gerekebilir."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Devam ettir"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yok"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Kablosuz bağlandı"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> uyarısı"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Çalışma modu"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Gece Işığı"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Geçe Işığı açık, kapatmak için dokunun"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Gece Işığı kapalı, açmak için dokunun"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Yeni öğe yok"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Her şeyi sildiniz"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Uygulama Bilgileri"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index eccc4a2..7327a08 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -241,8 +241,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передавання даних 4G призупинено"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передавання мобільних даних призупинено"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передавання даних призупинено"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Ви досягнули вказаного ліміту даних. Мобільний трафік вимкнено.\n\nЯкщо продовжите, може стягуватися плата за використання трафіку."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Відновити"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Немає з’єднання"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string>
@@ -326,8 +325,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Застереження: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Робочий режим"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Нічний режим"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Нічний режим увімкнено. Торкніться, щоб вимкнути його"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Нічний режим вимкнено. Торкніться, щоб увімкнути його"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Немає нещодавніх завдань"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Ви очистили все"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Інформація про додаток"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index dc177d1..8048289 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ڈیٹا موقوف کر دیا گیا"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"سیلولر ڈیٹا موقوف کر دیا گیا"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ڈیٹا موقوف کر دیا گیا"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"آپ کی سیٹ کردہ ڈیٹا کی حد پوری ہو گئی ہے۔ آپ اب سیلولر ڈیٹا استعمال نہیں کر رہے۔\n\nاگر آپ دوبارہ شروع کرتے ہیں تو ڈیٹا کے استعمال کے چارجز لاگو ہو سکتے ہیں۔"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"دوبارہ شروع کریں"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"کوئی انٹرنیٹ کنکشن نہیں"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi مربوط ہے"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> وارننگ"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"کام موڈ"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"نائٹ لائٹ"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"نائٹ لائٹ آن ہے، آف کرنے کیلئے تھپتھپائیں"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"نائٹ لائٹ آف ہے، آن کرنے کیلئے تھپتھپائیں"</string>
<string name="recents_empty_message" msgid="808480104164008572">"کوئی حالیہ آئٹم نہیں"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"آپ نے سب کچھ صاف کر دیا ہے"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"ایپلیکیشن کی معلومات"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 32fb303..c14ad93 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G internet to‘xtatib qo‘yildi"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil internetdan foydalanish to‘xtatib qo‘yildi"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Internetdan foydalanish to‘xtatib qo‘yildi"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"O‘rnatilgan trafik sarflab bo‘lindi. Endi mobil internetdan foydalana olmaysiz.\n\nDavom ettiradigan bo‘lsangiz, trafik uchun to‘lov olinishi mumkin."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davom etish"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Internetga ulanmagan"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ulandi"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Ogohlantirish: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Ish rejimi"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Tungi rejim"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Tunji rejim yoniq, o‘chirish uchun bosing"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Tunji rejim o‘chiq, yoqish uchun bosing"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Hozircha hech narsa yo‘q"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Hammasi o‘chirildi"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Ilova haqida ma’lumot"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 4146796..062c6c2 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Đã tạm dừng dữ liệu 4G"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Đã tạm dừng dữ liệu di động"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Đã tạm dừng dữ liệu"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Đã đạt đến giới hạn dữ liệu mà bạn đặt. Bạn hiện không còn sử dụng dữ liệu di động.\n\nNếu tiếp tục, bạn có thể bị tính phí khi sử dụng dữ liệu."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Tiếp tục"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ko có k.nối Internet"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Cảnh báo <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Chế độ làm việc"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Đèn đọc sách"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Đèn đọc sách được bật, nhấn để tắt"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Đèn đọc sách bị tắt, nhấn để bật"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Không có mục gần đây nào"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Bạn đã xóa mọi nội dung"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Thông tin ứng dụng"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 30f6245..b98bf14 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 数据网络已暂停使用"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"移动数据网络已暂停使用"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"数据网络已暂停使用"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"您的数据用量已达到设置的上限。您无法再使用移动数据网络。\n\n如果您继续操作,可能需要支付相应的数据流量费用。"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢复"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"已连接到WLAN网络"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g>警告"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"夜间模式"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"夜间模式已开启,点按即可关闭"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"夜间模式已关闭,点按即可开启"</string>
<string name="recents_empty_message" msgid="808480104164008572">"近期没有任何内容"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有内容"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"应用信息"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index f00a30b..d581592 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -239,8 +239,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停流動數據"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停使用數據"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"已達到您設定的數據上限。系統將停止使用流動數據網絡。\n\n如果您恢復使用流動數據網絡,可能需要支付數據費用。"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有互聯網連線"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
@@ -322,8 +321,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"夜燈模式"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"夜燈模式已開啟,輕按即可關閉"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"夜燈模式已關閉,輕按即可開啟"</string>
<string name="recents_empty_message" msgid="808480104164008572">"沒有最近項目"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有項目"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資料"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 34d12ff..fa4cacb 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據連線"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停行動數據連線"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停數據連線"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"你的數據用量已達設定的用量上限,因此系統已停止使用行動數據連線。\n\n如果你繼續使用行動數據連線,可能需要支付相關的數據傳輸費用。"</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復連線"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有網際網路連線"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> 警告"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"工作模式"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"夜燈"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"夜燈功能已開啟,輕觸即可關閉"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"夜燈功能已關閉,輕觸即可開啟"</string>
<string name="recents_empty_message" msgid="808480104164008572">"最近沒有任何項目"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"您已清除所有工作"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"應用程式資訊"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 1b2794e..97aa758 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -237,8 +237,7 @@
<string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G idatha imisiwe"</string>
<string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Idatha yeselula imisiwe"</string>
<string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Idatha imisiwe"</string>
- <!-- no translation found for data_usage_disabled_dialog (1841738975235283398) -->
- <skip />
+ <string name="data_usage_disabled_dialog" msgid="1841738975235283398">"Umkhawulo wedatha owusethayo ufikiwe. Awusasebenzisi idatha yeselula.\n\nUma uqalisa kabusha, izindleko zingasebenza ekusetshenzisweni kwedatha."</string>
<string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Qalisa kabusha"</string>
<string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Alukho uxhumano lwe-Inthanethi"</string>
<string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"I-Wi-Fi ixhunyiwe"</string>
@@ -320,8 +319,6 @@
<string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"<xliff:g id="DATA_LIMIT">%s</xliff:g> isexwayiso"</string>
<string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Imodi yomsebenzi"</string>
<string name="quick_settings_night_display_label" msgid="3577098011487644395">"Ukukhanya kwasebusuku"</string>
- <string name="quick_settings_night_display_summary_on" msgid="1814901757887526769">"Ukukhanya kwasebusuku kuvuliwe, thepha ukuze uvale"</string>
- <string name="quick_settings_night_display_summary_off" msgid="7892102914128777905">"Ukukhanya kwasebusuku kuvaliwe, thepha ukuze uvule"</string>
<string name="recents_empty_message" msgid="808480104164008572">"Azikho izinto zakamuva"</string>
<string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Usule yonke into"</string>
<string name="recents_app_info_button_label" msgid="2890317189376000030">"Ulwazi lohlelo lokusebenza"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3f485c3..92e10d2 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -755,10 +755,6 @@
<string name="quick_settings_work_mode_label">Work mode</string>
<!-- QuickSettings: Label for the toggle to activate Night display (renamed "Night Light" with title caps). [CHAR LIMIT=20] -->
<string name="quick_settings_night_display_label">Night Light</string>
- <!-- QuickSettings: Summary for the toggle to deactivate Night display when it's on (renamed "Night Light" with title caps). [CHAR LIMIT=NONE] -->
- <string name="quick_settings_night_display_summary_on">Night Light on, tap to turn off</string>
- <!-- QuickSettings: Label for the toggle to activate Night display when it's off (renamed "Night Light" with title caps). [CHAR LIMIT=NONE] -->
- <string name="quick_settings_night_display_summary_off">Night Light off, tap to turn on</string>
<!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
<string name="recents_empty_message">No recent items</string>
@@ -1438,8 +1434,8 @@
<string name="keyboard_shortcut_group_applications_contacts">Contacts</string>
<!-- User visible title for the keyboard shortcut that takes the user to the email app. -->
<string name="keyboard_shortcut_group_applications_email">Email</string>
- <!-- User visible title for the keyboard shortcut that takes the user to the instant messaging app. -->
- <string name="keyboard_shortcut_group_applications_im">IM</string>
+ <!-- User visible title for the keyboard shortcut that takes the user to the SMS messaging app. -->
+ <string name="keyboard_shortcut_group_applications_sms">SMS</string>
<!-- User visible title for the keyboard shortcut that takes the user to the music app. -->
<string name="keyboard_shortcut_group_applications_music">Music</string>
<!-- User visible title for the keyboard shortcut that takes the user to the YouTube app. -->
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
index 076b5bc..e1d6a94 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -31,10 +31,9 @@
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.provider.Settings;
-
import com.android.systemui.statusbar.policy.BatteryController;
public class BatteryMeterDrawable extends Drawable implements
@@ -92,18 +91,17 @@
private int mLightModeBackgroundColor;
private int mLightModeFillColor;
- private final SettingObserver mSettingObserver = new SettingObserver();
+ private final SettingObserver mSettingObserver;
private final Context mContext;
- private final Handler mHandler;
private int mLevel = -1;
private boolean mPluggedIn;
private boolean mListening;
- public BatteryMeterDrawable(Context context, Handler handler, int frameColor) {
+ public BatteryMeterDrawable(Context context, int frameColor) {
mContext = context;
- mHandler = handler;
+ mSettingObserver = new SettingObserver(new Handler(mContext.getMainLooper()));
final Resources res = context.getResources();
TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
@@ -199,12 +197,7 @@
}
private void postInvalidate() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- invalidateSelf();
- }
- });
+ scheduleSelf(this::invalidateSelf, 0);
}
public void setBatteryController(BatteryController batteryController) {
@@ -506,8 +499,8 @@
}
private final class SettingObserver extends ContentObserver {
- public SettingObserver() {
- super(new Handler());
+ public SettingObserver(Handler handler) {
+ super(handler);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index d8b95cc..4f3ffde 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -49,7 +49,7 @@
defStyle, 0);
final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
context.getColor(R.color.batterymeter_frame_color));
- mDrawable = new BatteryMeterDrawable(context, new Handler(), frameColor);
+ mDrawable = new BatteryMeterDrawable(context, frameColor);
atts.recycle();
mSlotBattery = context.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/BootReceiver.java b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
deleted file mode 100644
index 8e24eeb..0000000
--- a/packages/SystemUI/src/com/android/systemui/BootReceiver.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.systemui;
-
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.provider.Settings;
-import android.util.Log;
-
-/**
- * Performs a number of miscellaneous, non-system-critical actions
- * after the system has finished booting.
- */
-public class BootReceiver extends BroadcastReceiver {
- private static final String TAG = "SystemUIBootReceiver";
-
- @Override
- public void onReceive(final Context context, Intent intent) {
- try {
- // Start the load average overlay, if activated
- ContentResolver res = context.getContentResolver();
- if (Settings.Global.getInt(res, Settings.Global.SHOW_PROCESSES, 0) != 0) {
- Intent loadavg = new Intent(context, com.android.systemui.LoadAverageService.class);
- context.startService(loadavg);
- }
- } catch (Exception e) {
- Log.e(TAG, "Can't start load average service", e);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/LatencyTester.java b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
new file mode 100644
index 0000000..c14b17f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/LatencyTester.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Build;
+import android.os.PowerManager;
+import android.os.SystemClock;
+
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.LatencyTracker;
+import com.android.systemui.statusbar.phone.FingerprintUnlockController;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+/**
+ * Class that only runs on debuggable builds that listens to broadcasts that simulate actions in the
+ * system that are used for testing the latency.
+ */
+public class LatencyTester extends SystemUI {
+
+ private static final String ACTION_FINGERPRINT_WAKE =
+ "com.android.systemui.latency.ACTION_FINGERPRINT_WAKE";
+ private static final String ACTION_TURN_ON_SCREEN =
+ "com.android.systemui.latency.ACTION_TURN_ON_SCREEN";
+
+ @Override
+ public void start() {
+ if (!Build.IS_DEBUGGABLE) {
+ return;
+ }
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_FINGERPRINT_WAKE);
+ filter.addAction(ACTION_TURN_ON_SCREEN);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (ACTION_FINGERPRINT_WAKE.equals(action)) {
+ fakeWakeAndUnlock();
+ } else if (ACTION_TURN_ON_SCREEN.equals(action)) {
+ fakeTurnOnScreen();
+ }
+ }
+ }, filter);
+ }
+
+ private void fakeTurnOnScreen() {
+ PowerManager powerManager = mContext.getSystemService(PowerManager.class);
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionStart(
+ LatencyTracker.ACTION_TURN_ON_SCREEN);
+ }
+ powerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:LATENCY_TESTS");
+ }
+
+ private void fakeWakeAndUnlock() {
+ FingerprintUnlockController fingerprintUnlockController = getComponent(PhoneStatusBar.class)
+ .getFingerprintUnlockController();
+ fingerprintUnlockController.onFingerprintAcquired();
+ fingerprintUnlockController.onFingerprintAuthenticated(
+ KeyguardUpdateMonitor.getCurrentUser());
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java b/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
deleted file mode 100644
index 59ffe03..0000000
--- a/packages/SystemUI/src/com/android/systemui/LoadAverageService.java
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright (C) 2007 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.systemui;
-
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.view.Gravity;
-import android.view.View;
-import android.view.WindowManager;
-
-import com.android.internal.os.ProcessCpuTracker;
-
-public class LoadAverageService extends Service {
- private View mView;
-
- private static final class CpuTracker extends ProcessCpuTracker {
- String mLoadText;
- int mLoadWidth;
-
- private final Paint mPaint;
-
- CpuTracker(Paint paint) {
- super(false);
- mPaint = paint;
- }
-
- @Override
- public void onLoadChanged(float load1, float load5, float load15) {
- mLoadText = load1 + " / " + load5 + " / " + load15;
- mLoadWidth = (int)mPaint.measureText(mLoadText);
- }
-
- @Override
- public int onMeasureProcessName(String name) {
- return (int)mPaint.measureText(name);
- }
- }
-
- private class LoadView extends View {
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == 1) {
- mStats.update();
- updateDisplay();
- Message m = obtainMessage(1);
- sendMessageDelayed(m, 2000);
- }
- }
- };
-
- private final CpuTracker mStats;
-
- private Paint mLoadPaint;
- private Paint mAddedPaint;
- private Paint mRemovedPaint;
- private Paint mShadowPaint;
- private Paint mShadow2Paint;
- private Paint mIrqPaint;
- private Paint mSystemPaint;
- private Paint mUserPaint;
- private float mAscent;
- private int mFH;
-
- private int mNeededWidth;
- private int mNeededHeight;
-
- LoadView(Context c) {
- super(c);
-
- setPadding(4, 4, 4, 4);
- //setBackgroundResource(com.android.internal.R.drawable.load_average_background);
-
- // Need to scale text size by density... but we won't do it
- // linearly, because with higher dps it is nice to squeeze the
- // text a bit to fit more of it. And with lower dps, trying to
- // go much smaller will result in unreadable text.
- int textSize = 10;
- float density = c.getResources().getDisplayMetrics().density;
- if (density < 1) {
- textSize = 9;
- } else {
- textSize = (int)(10*density);
- if (textSize < 10) {
- textSize = 10;
- }
- }
- mLoadPaint = new Paint();
- mLoadPaint.setAntiAlias(true);
- mLoadPaint.setTextSize(textSize);
- mLoadPaint.setARGB(255, 255, 255, 255);
-
- mAddedPaint = new Paint();
- mAddedPaint.setAntiAlias(true);
- mAddedPaint.setTextSize(textSize);
- mAddedPaint.setARGB(255, 128, 255, 128);
-
- mRemovedPaint = new Paint();
- mRemovedPaint.setAntiAlias(true);
- mRemovedPaint.setStrikeThruText(true);
- mRemovedPaint.setTextSize(textSize);
- mRemovedPaint.setARGB(255, 255, 128, 128);
-
- mShadowPaint = new Paint();
- mShadowPaint.setAntiAlias(true);
- mShadowPaint.setTextSize(textSize);
- //mShadowPaint.setFakeBoldText(true);
- mShadowPaint.setARGB(192, 0, 0, 0);
- mLoadPaint.setShadowLayer(4, 0, 0, 0xff000000);
-
- mShadow2Paint = new Paint();
- mShadow2Paint.setAntiAlias(true);
- mShadow2Paint.setTextSize(textSize);
- //mShadow2Paint.setFakeBoldText(true);
- mShadow2Paint.setARGB(192, 0, 0, 0);
- mLoadPaint.setShadowLayer(2, 0, 0, 0xff000000);
-
- mIrqPaint = new Paint();
- mIrqPaint.setARGB(0x80, 0, 0, 0xff);
- mIrqPaint.setShadowLayer(2, 0, 0, 0xff000000);
- mSystemPaint = new Paint();
- mSystemPaint.setARGB(0x80, 0xff, 0, 0);
- mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000);
- mUserPaint = new Paint();
- mUserPaint.setARGB(0x80, 0, 0xff, 0);
- mSystemPaint.setShadowLayer(2, 0, 0, 0xff000000);
-
- mAscent = mLoadPaint.ascent();
- float descent = mLoadPaint.descent();
- mFH = (int)(descent - mAscent + .5f);
-
- mStats = new CpuTracker(mLoadPaint);
- mStats.init();
- updateDisplay();
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mHandler.sendEmptyMessage(1);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mHandler.removeMessages(1);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec),
- resolveSize(mNeededHeight, heightMeasureSpec));
- }
-
- @Override
- public void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- final int W = mNeededWidth;
- final int RIGHT = getWidth()-1;
-
- final CpuTracker stats = mStats;
- final int userTime = stats.getLastUserTime();
- final int systemTime = stats.getLastSystemTime();
- final int iowaitTime = stats.getLastIoWaitTime();
- final int irqTime = stats.getLastIrqTime();
- final int softIrqTime = stats.getLastSoftIrqTime();
- final int idleTime = stats.getLastIdleTime();
-
- final int totalTime = userTime+systemTime+iowaitTime+irqTime+softIrqTime+idleTime;
- if (totalTime == 0) {
- return;
- }
- int userW = (userTime*W)/totalTime;
- int systemW = (systemTime*W)/totalTime;
- int irqW = ((iowaitTime+irqTime+softIrqTime)*W)/totalTime;
-
- int paddingRight = getPaddingRight();
- int x = RIGHT - paddingRight;
- int top = getPaddingTop() + 2;
- int bottom = getPaddingTop() + mFH - 2;
-
- if (irqW > 0) {
- canvas.drawRect(x-irqW, top, x, bottom, mIrqPaint);
- x -= irqW;
- }
- if (systemW > 0) {
- canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
- x -= systemW;
- }
- if (userW > 0) {
- canvas.drawRect(x-userW, top, x, bottom, mUserPaint);
- x -= userW;
- }
-
- int y = getPaddingTop() - (int)mAscent;
- canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth-1,
- y-1, mShadowPaint);
- canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth-1,
- y+1, mShadowPaint);
- canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth+1,
- y-1, mShadow2Paint);
- canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth+1,
- y+1, mShadow2Paint);
- canvas.drawText(stats.mLoadText, RIGHT-paddingRight-stats.mLoadWidth,
- y, mLoadPaint);
-
- int N = stats.countWorkingStats();
- for (int i=0; i<N; i++) {
- CpuTracker.Stats st = stats.getWorkingStats(i);
- y += mFH;
- top += mFH;
- bottom += mFH;
-
- userW = (st.rel_utime*W)/totalTime;
- systemW = (st.rel_stime*W)/totalTime;
- x = RIGHT - paddingRight;
- if (systemW > 0) {
- canvas.drawRect(x-systemW, top, x, bottom, mSystemPaint);
- x -= systemW;
- }
- if (userW > 0) {
- canvas.drawRect(x-userW, top, x, bottom, mUserPaint);
- x -= userW;
- }
-
- canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth-1,
- y-1, mShadowPaint);
- canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth-1,
- y+1, mShadowPaint);
- canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth+1,
- y-1, mShadow2Paint);
- canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth+1,
- y+1, mShadow2Paint);
- Paint p = mLoadPaint;
- if (st.added) p = mAddedPaint;
- if (st.removed) p = mRemovedPaint;
- canvas.drawText(st.name, RIGHT-paddingRight-st.nameWidth, y, p);
- }
- }
-
- void updateDisplay() {
- final CpuTracker stats = mStats;
- final int NW = stats.countWorkingStats();
-
- int maxWidth = stats.mLoadWidth;
- for (int i=0; i<NW; i++) {
- CpuTracker.Stats st = stats.getWorkingStats(i);
- if (st.nameWidth > maxWidth) {
- maxWidth = st.nameWidth;
- }
- }
-
- int neededWidth = getPaddingLeft() + getPaddingRight() + maxWidth;
- int neededHeight = getPaddingTop() + getPaddingBottom() + (mFH*(1+NW));
- if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) {
- mNeededWidth = neededWidth;
- mNeededHeight = neededHeight;
- requestLayout();
- } else {
- invalidate();
- }
- }
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- mView = new LoadView(this);
- WindowManager.LayoutParams params = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
- WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
- PixelFormat.TRANSLUCENT);
- params.gravity = Gravity.END | Gravity.TOP;
- params.setTitle("Load Average");
- WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
- wm.addView(mView, params);
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- ((WindowManager)getSystemService(WINDOW_SERVICE)).removeView(mView);
- mView = null;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index e300aff..bfc8642 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -29,11 +29,22 @@
import android.os.UserHandle;
import android.util.Log;
+import com.android.systemui.keyboard.KeyboardUI;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.media.RingtonePlayer;
import com.android.systemui.plugins.OverlayPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.power.PowerUI;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.shortcut.ShortcutKeyDispatcher;
import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.SystemBars;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tv.pip.PipUI;
+import com.android.systemui.usb.StorageNotification;
+import com.android.systemui.volume.VolumeUI;
import java.util.HashMap;
import java.util.Map;
@@ -50,19 +61,20 @@
* The classes of the stuff to start.
*/
private final Class<?>[] SERVICES = new Class[] {
- com.android.systemui.tuner.TunerService.class,
- com.android.systemui.keyguard.KeyguardViewMediator.class,
- com.android.systemui.recents.Recents.class,
- com.android.systemui.volume.VolumeUI.class,
+ TunerService.class,
+ KeyguardViewMediator.class,
+ Recents.class,
+ VolumeUI.class,
Divider.class,
- com.android.systemui.statusbar.SystemBars.class,
- com.android.systemui.usb.StorageNotification.class,
- com.android.systemui.power.PowerUI.class,
- com.android.systemui.media.RingtonePlayer.class,
- com.android.systemui.keyboard.KeyboardUI.class,
- com.android.systemui.tv.pip.PipUI.class,
- com.android.systemui.shortcut.ShortcutKeyDispatcher.class,
- com.android.systemui.VendorServices.class
+ SystemBars.class,
+ StorageNotification.class,
+ PowerUI.class,
+ RingtonePlayer.class,
+ KeyboardUI.class,
+ PipUI.class,
+ ShortcutKeyDispatcher.class,
+ VendorServices.class,
+ LatencyTester.class
};
/**
@@ -70,8 +82,8 @@
* above.
*/
private final Class<?>[] SERVICES_PER_USER = new Class[] {
- com.android.systemui.recents.Recents.class,
- com.android.systemui.tv.pip.PipUI.class
+ Recents.class,
+ PipUI.class
};
/**
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 261d241..56f6b8d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -60,6 +60,11 @@
private static final String ACTION_BASE = "com.android.systemui.doze";
private static final String PULSE_ACTION = ACTION_BASE + ".pulse";
+ /**
+ * If true, reregisters all trigger sensors when the screen turns off.
+ */
+ private static final boolean REREGISTER_ALL_SENSORS_ON_SCREEN_OFF = true;
+
private final String mTag = String.format(TAG + ".%08x", hashCode());
private final Context mContext = this;
private final DozeParameters mDozeParameters = new DozeParameters(mContext);
@@ -272,6 +277,9 @@
public void onPulseFinished() {
if (mPulsing && mDreaming) {
mPulsing = false;
+ if (REREGISTER_ALL_SENSORS_ON_SCREEN_OFF) {
+ reregisterAllSensors();
+ }
turnDisplayOff();
}
mWakeLock.release(); // needs to be unconditional to balance acquire
@@ -308,6 +316,15 @@
listenForNotifications(listen);
}
+ private void reregisterAllSensors() {
+ for (TriggerSensor s : mSensors) {
+ s.setListening(false);
+ }
+ for (TriggerSensor s : mSensors) {
+ s.setListening(true);
+ }
+ }
+
private void listenForBroadcasts(boolean listen) {
if (listen) {
final IntentFilter filter = new IntentFilter(PULSE_ACTION);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b9e8acb..24247e4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -73,6 +73,7 @@
import com.android.keyguard.KeyguardSecurityView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.LatencyTracker;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
@@ -1894,6 +1895,9 @@
private void handleNotifyScreenTurnedOn() {
Trace.beginSection("KeyguardViewMediator#handleNotifyScreenTurnedOn");
+ if (LatencyTracker.isEnabled(mContext)) {
+ LatencyTracker.getInstance(mContext).onActionEnd(LatencyTracker.ACTION_TURN_ON_SCREEN);
+ }
synchronized (this) {
if (DEBUG) Log.d(TAG, "handleNotifyScreenTurnedOn");
mStatusBarKeyguardViewManager.onScreenTurnedOn();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index afedbe3..1c242e9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -88,9 +88,9 @@
if (mListening == listening) return;
mListening = listening;
if (mListening) {
- mPages.get(mPosition).setListening(listening);
+ setPageListening(mPosition, true);
if (mOffPage) {
- mPages.get(mPosition + 1).setListening(listening);
+ setPageListening(mPosition + 1, true);
}
} else {
// Make sure no pages are listening.
@@ -131,6 +131,9 @@
private void setPageListening(int position, boolean listening) {
if (position >= mPages.size()) return;
+ if (isLayoutRtl()) {
+ position = mPages.size() - 1 - position;
+ }
mPages.get(position).setListening(listening);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 2173922..f345172 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -334,4 +334,10 @@
public int getQsMinExpansionHeight() {
return mHeader.getHeight();
}
+
+ @Override
+ public void hideImmediately() {
+ animate().cancel();
+ setY(-mHeader.getHeight());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 40ef6eb..0cd6490 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -64,7 +64,10 @@
for (int i = 0; i < possibleTiles.length; i++) {
final String spec = possibleTiles[i];
final QSTile<?> tile = host.createTile(spec);
- if (tile == null || !tile.isAvailable()) {
+ if (tile == null) {
+ continue;
+ } else if (!tile.isAvailable()) {
+ tile.destroy();
continue;
}
tile.setListening(this, true);
@@ -78,6 +81,7 @@
tile.getState().copyTo(state);
// Ignore the current state and get the generic label instead.
state.label = tile.getTileLabel();
+ tile.destroy();
mainHandler.post(new Runnable() {
@Override
public void run() {
@@ -126,6 +130,7 @@
state.label = label;
state.contentDescription = label;
state.icon = new DrawableIcon(drawable);
+ state.autoMirrorDrawable = false;
addTile(spec, appLabel, state, false);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index b36221d..484e008 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -221,7 +221,9 @@
@Override
public State newTileState() {
- return new State();
+ State state = new State();
+ state.autoMirrorDrawable = false;
+ return state;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
index b61a81c..d89fbfd3c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -118,7 +118,7 @@
@Override
public Drawable getDrawable(Context context) {
BatteryMeterDrawable drawable =
- new BatteryMeterDrawable(context, new Handler(Looper.getMainLooper()),
+ new BatteryMeterDrawable(context,
context.getColor(R.color.batterymeter_frame_color));
drawable.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
drawable.onPowerSaveChanged(mPowerSave);
@@ -165,7 +165,7 @@
private final class BatteryDetail implements DetailAdapter, OnClickListener,
OnAttachStateChangeListener {
private final BatteryMeterDrawable mDrawable = new BatteryMeterDrawable(mHost.getContext(),
- new Handler(), mHost.getContext().getColor(R.color.batterymeter_frame_color));
+ mHost.getContext().getColor(R.color.batterymeter_frame_color));
private View mCurrentView;
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 89bb1d2..ec4ab51 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -69,12 +69,23 @@
private boolean mListening;
private boolean mShowingDetail;
+ private boolean mReceiverRegistered;
public DndTile(Host host) {
super(host);
mController = host.getZenModeController();
mDetailAdapter = new DndDetailAdapter();
mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
+ mReceiverRegistered = true;
+ }
+
+ @Override
+ protected void handleDestroy() {
+ super.handleDestroy();
+ if (mReceiverRegistered) {
+ mContext.unregisterReceiver(mReceiver);
+ mReceiverRegistered = false;
+ }
}
public static void setVisible(Context context, boolean visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index 9415b27..c02e5ae 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -75,14 +75,12 @@
protected void handleUpdateState(BooleanState state, Object arg) {
final boolean isActivated = mController.isActivated();
state.value = isActivated;
- state.label = mContext.getString(R.string.quick_settings_night_display_label);
+ state.label = state.contentDescription =
+ mContext.getString(R.string.quick_settings_night_display_label);
state.icon = ResourceIcon.get(isActivated ? R.drawable.ic_qs_night_display_on
: R.drawable.ic_qs_night_display_off);
- state.contentDescription = mContext.getString(isActivated
- ? R.string.quick_settings_night_display_summary_on
- : R.string.quick_settings_night_display_summary_off);
- state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
- = Switch.class.getName();
+ state.minimalAccessibilityClassName = state.expandedAccessibilityClassName =
+ Switch.class.getName();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 7207463..3c245b4 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -18,12 +18,10 @@
import android.app.ActivityManager;
import android.app.UiModeManager;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -99,7 +97,7 @@
// and does not reside in the home stack.
private String mOverrideRecentsPackageName;
- private Handler mHandler = new Handler();
+ private Handler mHandler;
private RecentsImpl mImpl;
private int mDraggingInRecentsCurrentUser;
@@ -165,20 +163,6 @@
}
};
-
- private BroadcastReceiver mSystemUserUnlockedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
- int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId != UserHandle.USER_NULL) {
- mImpl.onUserUnlocked(userId);
- }
- }
- }
- };
-
-
/**
* Returns the callbacks interface that non-system users can call.
*/
@@ -208,7 +192,7 @@
sSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
sTaskLoader = new RecentsTaskLoader(mContext);
sConfiguration = new RecentsConfiguration(mContext);
-
+ mHandler = new Handler();
UiModeManager uiModeManager = (UiModeManager) mContext.
getSystemService(Context.UI_MODE_SERVICE);
if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
@@ -238,12 +222,6 @@
// For the system user, initialize an instance of the interface that we can pass to the
// secondary user
mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
-
- // Listen for user-unlocked to kick off preloading recents
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_UNLOCKED);
- mContext.registerReceiverAsUser(mSystemUserUnlockedReceiver, UserHandle.SYSTEM, filter,
- null /* permission */, null /* scheduler */);
} else {
// For the secondary user, bind to the primary user's service to get a persistent
// interface to register its implementation and to later update its state
@@ -501,6 +479,7 @@
return COUNTER_WINDOW_UNSUPPORTED;
case ActivityInfo.RESIZE_MODE_RESIZEABLE:
case ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE:
+ case ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION:
return COUNTER_WINDOW_SUPPORTED;
default:
return COUNTER_WINDOW_INCOMPATIBLE;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index e5493b6..ec99d20 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -43,7 +43,7 @@
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.DejankUtils;
import com.android.systemui.Interpolators;
-import com.android.systemui.LatencyTracker;
+import com.android.keyguard.LatencyTracker;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.recents.events.EventBus;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 390ef87..64ef997 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -188,7 +188,7 @@
reloadResources();
}
- public void onUserUnlocked(int userId) {
+ public void onBootCompleted() {
// When we start, preload the data associated with the previous recent tasks.
// We can use a new plan since the caches will be the same.
RecentsTaskLoader loader = Recents.getTaskLoader();
@@ -201,10 +201,6 @@
loader.loadTasks(mContext, plan, launchOpts);
}
- public void onBootCompleted() {
- // Do nothing
- }
-
public void onConfigurationChanged() {
Resources res = mContext.getResources();
reloadResources();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
index 9faaa4b..a673c8c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
@@ -47,12 +47,13 @@
public void startEnterAnimation(boolean isPipShown) {
for(int i = 0; i < mGridView.getChildCount(); i++) {
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
+ long delay = Math.max(mDelay * i, 0);
view.setTranslationX(-mTranslationX);
view.animate()
.alpha(isPipShown ? mDimAlpha : 1.0f)
.translationX(0)
.setDuration(mDuration)
- .setStartDelay(mDelay * i)
+ .setStartDelay(delay)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
}
}
@@ -60,11 +61,12 @@
public void startExitAnimation(DismissRecentsToHomeAnimationStarted dismissEvent) {
for(int i = mGridView.getChildCount() - 1; i >= 0; i--) {
TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
+ long delay = Math.max(mDelay * (mGridView.getChildCount() - 1 - i), 0);
view.animate()
.alpha(0.0f)
.translationXBy(-mTranslationX)
.setDuration(mDuration)
- .setStartDelay(mDelay * (mGridView.getChildCount() - 1 - i))
+ .setStartDelay(delay)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
if(i == 0) {
view.animate().setListener(dismissEvent.getAnimationTrigger()
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index cb77d7b..4e34bbc 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -1113,6 +1113,7 @@
public final void onBusEvent(RecentsActivityStartingEvent recentsActivityStartingEvent) {
if (mGrowRecents && getWindowManagerProxy().getDockSide() == WindowManager.DOCKED_TOP
+ && getSnapAlgorithm().getMiddleTarget() != getSnapAlgorithm().getLastSplitTarget()
&& getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position) {
mState.growAfterRecentsDrawn = true;
startDragging(false /* animate */, false /* touching */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index a7132e5..4cc7a16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -161,7 +161,7 @@
"com.android.systemui.statusbar.banner_action_cancel";
private static final String BANNER_ACTION_SETUP =
"com.android.systemui.statusbar.banner_action_setup";
- private static final String WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION
+ private static final String NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION
= "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
protected CommandQueue mCommandQueue;
@@ -217,14 +217,14 @@
protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
// public mode, private notifications, etc
- private boolean mLockscreenPublicMode = false;
+ private final SparseBooleanArray mLockscreenPublicMode = new SparseBooleanArray();
private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
private UserManager mUserManager;
private int mDensity;
- private KeyguardManager mKeyguardManager;
+ protected KeyguardManager mKeyguardManager;
private LockPatternUtils mLockPatternUtils;
// UI-specific methods
@@ -465,11 +465,11 @@
row.setUserExpanded(true);
if (!mAllowLockscreenRemoteInput) {
- if (isLockscreenPublicMode()) {
+ final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
+ if (isLockscreenPublicMode(userId)) {
onLockedRemoteInput(row, view);
return true;
}
- final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
if (mUserManager.getUserInfo(userId).isManagedProfile()
&& mKeyguardManager.isDeviceLocked(userId)) {
onLockedWorkRemoteInput(userId, row, view);
@@ -560,7 +560,7 @@
);
}
- } else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
+ } else if (NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION.equals(action)) {
final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
if (intentSender != null) {
@@ -577,7 +577,6 @@
/* ignore */
}
}
- onWorkChallengeUnlocked();
}
}
};
@@ -585,12 +584,18 @@
private final BroadcastReceiver mAllUsersReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
+ final String action = intent.getAction();
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+
if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action) &&
isCurrentProfile(getSendingUserId())) {
mUsersAllowingPrivateNotifications.clear();
updateLockscreenNotificationSetting();
updateNotifications();
+ } else if (Intent.ACTION_DEVICE_LOCKED_CHANGED.equals(action)) {
+ if (userId != mCurrentUserId && isCurrentProfile(userId)) {
+ onWorkChallengeChanged();
+ }
}
}
};
@@ -815,7 +820,7 @@
mContext.registerReceiver(mBroadcastReceiver, filter);
IntentFilter internalFilter = new IntentFilter();
- internalFilter.addAction(WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
+ internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
internalFilter.addAction(BANNER_ACTION_CANCEL);
internalFilter.addAction(BANNER_ACTION_SETUP);
mContext.registerReceiver(mBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
@@ -823,6 +828,7 @@
IntentFilter allUsersFilter = new IntentFilter();
allUsersFilter.addAction(
DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ allUsersFilter.addAction(Intent.ACTION_DEVICE_LOCKED_CHANGED);
mContext.registerReceiverAsUser(mAllUsersReceiver, UserHandle.ALL, allUsersFilter,
null, null);
updateCurrentProfilesCache();
@@ -1126,9 +1132,10 @@
@Override
public void onClick(View v) {
// If the user has security enabled, show challenge if the setting is changed.
- if (guts.hasImportanceChanged() && isLockscreenPublicMode() &&
- (mState == StatusBarState.KEYGUARD
- || mState == StatusBarState.SHADE_LOCKED)) {
+ if (guts.hasImportanceChanged()
+ && isLockscreenPublicMode(sbn.getUser().getIdentifier())
+ && (mState == StatusBarState.KEYGUARD
+ || mState == StatusBarState.SHADE_LOCKED)) {
OnDismissAction dismissAction = new OnDismissAction() {
@Override
public boolean onDismiss() {
@@ -1430,15 +1437,15 @@
/**
* Save the current "public" (locked and secure) state of the lockscreen.
*/
- public void setLockscreenPublicMode(boolean publicMode) {
- mLockscreenPublicMode = publicMode;
+ public void setLockscreenPublicMode(boolean publicMode, int userId) {
+ mLockscreenPublicMode.put(userId, publicMode);
}
- public boolean isLockscreenPublicMode() {
- return mLockscreenPublicMode;
+ public boolean isLockscreenPublicMode(int userId) {
+ return mLockscreenPublicMode.get(userId, false);
}
- protected void onWorkChallengeUnlocked() {}
+ protected void onWorkChallengeChanged() {}
/**
* Has the given user chosen to allow notifications to be shown even when the lockscreen is in
@@ -1496,8 +1503,9 @@
* If so, notifications should be hidden.
*/
@Override // NotificationData.Environment
- public boolean shouldHideNotifications(int userid) {
- return isLockscreenPublicMode() && !userAllowsNotificationsInPublic(userid);
+ public boolean shouldHideNotifications(int userId) {
+ return isLockscreenPublicMode(mCurrentUserId) && !userAllowsNotificationsInPublic(userId)
+ || (userId != mCurrentUserId && shouldHideNotifications(mCurrentUserId));
}
/**
@@ -1506,7 +1514,7 @@
*/
@Override // NotificationDate.Environment
public boolean shouldHideNotifications(String key) {
- return isLockscreenPublicMode()
+ return isLockscreenPublicMode(mCurrentUserId)
&& mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
}
@@ -1514,8 +1522,8 @@
* Returns true if we're on a secure lockscreen.
*/
@Override // NotificationData.Environment
- public boolean onSecureLockScreen() {
- return isLockscreenPublicMode();
+ public boolean isSecurelyLocked(int userId) {
+ return isLockscreenPublicMode(userId);
}
public void onNotificationClear(StatusBarNotification notification) {
@@ -1711,6 +1719,23 @@
sbn.getPackageContext(mContext),
contentContainerPublic, mOnClickHandler);
}
+
+ if (contentViewLocal != null) {
+ contentViewLocal.setIsRootNamespace(true);
+ contentContainer.setContractedChild(contentViewLocal);
+ }
+ if (bigContentViewLocal != null) {
+ bigContentViewLocal.setIsRootNamespace(true);
+ contentContainer.setExpandedChild(bigContentViewLocal);
+ }
+ if (headsUpContentViewLocal != null) {
+ headsUpContentViewLocal.setIsRootNamespace(true);
+ contentContainer.setHeadsUpChild(headsUpContentViewLocal);
+ }
+ if (publicViewLocal != null) {
+ publicViewLocal.setIsRootNamespace(true);
+ contentContainerPublic.setContractedChild(publicViewLocal);
+ }
}
catch (RuntimeException e) {
final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
@@ -1718,23 +1743,6 @@
return false;
}
- if (contentViewLocal != null) {
- contentViewLocal.setIsRootNamespace(true);
- contentContainer.setContractedChild(contentViewLocal);
- }
- if (bigContentViewLocal != null) {
- bigContentViewLocal.setIsRootNamespace(true);
- contentContainer.setExpandedChild(bigContentViewLocal);
- }
- if (headsUpContentViewLocal != null) {
- headsUpContentViewLocal.setIsRootNamespace(true);
- contentContainer.setHeadsUpChild(headsUpContentViewLocal);
- }
- if (publicViewLocal != null) {
- publicViewLocal.setIsRootNamespace(true);
- contentContainerPublic.setContractedChild(publicViewLocal);
- }
-
// Extract target SDK version.
try {
ApplicationInfo info = pmUser.getApplicationInfo(sbn.getPackageName(), 0);
@@ -2076,8 +2084,7 @@
if (newIntent == null) {
return false;
}
- final Intent callBackIntent = new Intent(
- WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
+ final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
callBackIntent.setPackage(mContext.getPackageName());
@@ -2276,14 +2283,16 @@
entry.row.setOnKeyguard(false);
entry.row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
}
+ int userId = entry.notification.getUserId();
boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
entry.notification) && !entry.row.isRemoved();
boolean childWithVisibleSummary = childNotification
&& mGroupManager.getGroupSummary(entry.notification).getVisibility()
== View.VISIBLE;
boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
- if (suppressedSummary || (isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
- (onKeyguard && !childWithVisibleSummary
+ if (suppressedSummary
+ || (isLockscreenPublicMode(userId) && !mShowLockscreenNotifications)
+ || (onKeyguard && !childWithVisibleSummary
&& (visibleNotifications >= maxNotifications || !showOnKeyguard))) {
entry.row.setVisibility(View.GONE);
if (onKeyguard && showOnKeyguard && !childNotification && !suppressedSummary) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index e781f1b..f438762 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -488,9 +488,9 @@
final Icon messagingIcon = getIconForIntentCategory(Intent.CATEGORY_APP_MESSAGING, userId);
if (messagingIcon != null) {
keyboardShortcutInfoAppItems.add(new KeyboardShortcutInfo(
- mContext.getString(R.string.keyboard_shortcut_group_applications_im),
+ mContext.getString(R.string.keyboard_shortcut_group_applications_sms),
messagingIcon,
- KeyEvent.KEYCODE_T,
+ KeyEvent.KEYCODE_S,
KeyEvent.META_META_ON));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index cf962df..0ef97152 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -95,8 +95,6 @@
KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitor);
context.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
new IntentFilter(Intent.ACTION_TIME_TICK), null, null);
- context.registerReceiverAsUser(mUnlockReceiver, UserHandle.ALL,
- new IntentFilter(Intent.ACTION_USER_UNLOCKED), null, null);
}
public void setVisible(boolean visible) {
@@ -322,6 +320,13 @@
super.onFingerprintAuthFailed();
mLastSuccessiveErrorMessage = -1;
}
+
+ @Override
+ public void onUserUnlocked() {
+ if (mVisible) {
+ updateIndication();
+ }
+ }
};
BroadcastReceiver mTickReceiver = new BroadcastReceiver() {
@@ -333,14 +338,6 @@
}
};
- BroadcastReceiver mUnlockReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mVisible) {
- updateIndication();
- }
- }
- };
private final Handler mHandler = new Handler() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index b6e54af..bae16f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -380,7 +380,7 @@
return true;
}
- if (mEnvironment.onSecureLockScreen() &&
+ if (mEnvironment.isSecurelyLocked(sbn.getUserId()) &&
(sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
|| mEnvironment.shouldHideNotifications(sbn.getUserId())
|| mEnvironment.shouldHideNotifications(sbn.getKey()))) {
@@ -463,7 +463,7 @@
* Provides access to keyguard state and user settings dependent data.
*/
public interface Environment {
- public boolean onSecureLockScreen();
+ public boolean isSecurelyLocked(int userId);
public boolean shouldHideNotifications(int userid);
public boolean shouldHideNotifications(String key);
public boolean isDeviceProvisioned();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index 59e4244..f46fc67 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.android.keyguard.AlphaOptimizedImageButton;
@@ -41,6 +42,7 @@
public void onFinishInflate() {
super.onFinishInflate();
mIcon = (AlphaOptimizedImageButton) findViewById(R.id.car_nav_button_icon);
+ mIcon.setScaleType(ImageView.ScaleType.CENTER);
mIcon.setClickable(false);
mIcon.setBackgroundColor(android.R.color.transparent);
mIcon.setAlpha(UNSELECTED_ALPHA);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 82867c6..42d9433 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -30,7 +30,7 @@
import com.android.keyguard.KeyguardConstants;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.systemui.LatencyTracker;
+import com.android.keyguard.LatencyTracker;
import com.android.systemui.keyguard.KeyguardViewMediator;
/**
@@ -42,8 +42,6 @@
private static final boolean DEBUG_FP_WAKELOCK = KeyguardConstants.DEBUG_FP_WAKELOCK;
private static final long FINGERPRINT_WAKELOCK_TIMEOUT_MS = 15 * 1000;
private static final String FINGERPRINT_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
- private static final String ACTION_FINGERPRINT_WAKE_FAKE =
- "com.android.systemui.ACTION_FINGERPRINT_WAKE_FAKE";
/**
* Mode in which we don't need to wake up the device when we get a fingerprint.
@@ -123,14 +121,6 @@
mScrimController = scrimController;
mPhoneStatusBar = phoneStatusBar;
mUnlockMethodCache = unlockMethodCache;
- if (Build.IS_DEBUGGABLE) {
- context.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- fakeWakeAndUnlock();
- }
- }, new IntentFilter(ACTION_FINGERPRINT_WAKE_FAKE));
- }
}
public void setStatusBarKeyguardViewManager(
@@ -159,11 +149,6 @@
}
}
- public void fakeWakeAndUnlock() {
- onFingerprintAcquired();
- onFingerprintAuthenticated(KeyguardUpdateMonitor.getCurrentUser());
- }
-
@Override
public void onFingerprintAcquired() {
Trace.beginSection("FingerprintUnlockController#onFingerprintAcquired");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 4270147..f9b7bb5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -122,6 +122,7 @@
private KeyguardIndicationController mIndicationController;
private AccessibilityController mAccessibilityController;
private PhoneStatusBar mPhoneStatusBar;
+ private KeyguardAffordanceHelper mAffordanceHelper;
private boolean mUserSetupComplete;
private boolean mPrewarmBound;
@@ -308,6 +309,10 @@
updateCameraVisibility(); // in case onFinishInflate() was called too early
}
+ public void setAffordanceHelper(KeyguardAffordanceHelper affordanceHelper) {
+ mAffordanceHelper = affordanceHelper;
+ }
+
public void setUserSetupComplete(boolean userSetupComplete) {
mUserSetupComplete = userSetupComplete;
updateCameraVisibility();
@@ -620,6 +625,9 @@
mPreviewContainer.addView(mCameraPreview);
mCameraPreview.setVisibility(visibleBefore ? View.VISIBLE : View.INVISIBLE);
}
+ if (mAffordanceHelper != null) {
+ mAffordanceHelper.updatePreviews();
+ }
}
private void updateLeftPreview() {
@@ -637,6 +645,9 @@
mPreviewContainer.addView(mLeftPreview);
mLeftPreview.setVisibility(View.INVISIBLE);
}
+ if (mAffordanceHelper != null) {
+ mAffordanceHelper.updatePreviews();
+ }
}
public void startFinishDozeAnimation() {
@@ -720,6 +731,13 @@
@Override
public void onStrongAuthStateChanged(int userId) {
mLockIcon.update();
+ }
+
+ @Override
+ public void onUserUnlocked() {
+ inflateCameraPreview();
+ updateCameraVisibility();
+ updateLeftAffordance();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 706abdc..34b8371 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -96,9 +96,10 @@
}
final int activeUserId = ActivityManager.getCurrentUser();
- final boolean allowDismissKeyguard =
- !UserManager.isSplitSystemUser()
- && activeUserId == keyguardUserId;
+ final boolean isSystemUser =
+ UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;
+ final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;
+
// If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
// set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 9e5b881..3a0eb94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -60,6 +60,8 @@
// slippery nav bar when everything is disabled, e.g. during setup
final static boolean SLIPPERY_WHEN_DISABLED = true;
+ final static boolean ALTERNATE_CAR_MODE_UI = false;
+
final Display mDisplay;
View mCurrentView = null;
View[] mRotatedViews = new View[4];
@@ -95,7 +97,8 @@
private OnVerticalChangedListener mOnVerticalChangedListener;
private boolean mLayoutTransitionsEnabled = true;
private boolean mWakeAndUnlocking;
- private boolean mCarMode = false;
+ private boolean mUseCarModeUi = false;
+ private boolean mInCarMode = false;
private boolean mDockedStackExists;
private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
@@ -291,7 +294,9 @@
mMenuIcon = ctx.getDrawable(R.drawable.ic_sysbar_menu);
mImeIcon = ctx.getDrawable(R.drawable.ic_ime_switcher_default);
- updateCarModeIcons(ctx);
+ if (ALTERNATE_CAR_MODE_UI) {
+ updateCarModeIcons(ctx);
+ }
}
}
@@ -342,14 +347,14 @@
// carmode, respectively. Recents are not available in CarMode in nav bar so change
// to recent icon is not required.
Drawable backIcon = (backAlt)
- ? getBackIconWithAlt(mCarMode, mVertical)
- : getBackIcon(mCarMode, mVertical);
+ ? getBackIconWithAlt(mUseCarModeUi, mVertical)
+ : getBackIcon(mUseCarModeUi, mVertical);
getBackButton().setImageDrawable(backIcon);
updateRecentsIcon();
- if (mCarMode) {
+ if (mUseCarModeUi) {
getHomeButton().setImageDrawable(mHomeCarModeIcon);
} else {
getHomeButton().setImageDrawable(mHomeDefaultIcon);
@@ -377,9 +382,9 @@
final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
- // Disable recents always in car mode.
- boolean disableRecent = (
- mCarMode || (disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
+ // Always disable recents when alternate car mode UI is active.
+ boolean disableRecent = mUseCarModeUi
+ || ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
&& ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
@@ -627,14 +632,19 @@
boolean uiCarModeChanged = false;
if (newConfig != null) {
int uiMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK;
- if (mCarMode && uiMode != Configuration.UI_MODE_TYPE_CAR) {
- mCarMode = false;
- uiCarModeChanged = true;
- getHomeButton().setCarMode(mCarMode);
- } else if (uiMode == Configuration.UI_MODE_TYPE_CAR) {
- mCarMode = true;
- uiCarModeChanged = true;
- getHomeButton().setCarMode(mCarMode);
+ final boolean isCarMode = (uiMode == Configuration.UI_MODE_TYPE_CAR);
+
+ if (isCarMode != mInCarMode) {
+ mInCarMode = isCarMode;
+ getHomeButton().setCarMode(isCarMode);
+
+ if (ALTERNATE_CAR_MODE_UI) {
+ mUseCarModeUi = isCarMode;
+ uiCarModeChanged = true;
+ } else {
+ // Don't use car mode behavior if ALTERNATE_CAR_MODE_UI not set.
+ mUseCarModeUi = false;
+ }
}
}
return uiCarModeChanged;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 5d1af2f..7b35cbd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -233,6 +233,7 @@
mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
+ mKeyguardBottomArea.setAffordanceHelper(mAfforanceHelper);
mLastOrientation = getResources().getConfiguration().orientation;
mQsAutoReinflateContainer =
@@ -328,7 +329,7 @@
} else if (!mQsExpanded) {
setQsExpansion(mQsMinExpansionHeight + mLastOverscroll);
}
- updateStackHeight(getExpandedHeight());
+ updateExpandedHeight(getExpandedHeight());
updateHeader();
// If we are running a size change animation, the animation takes care of the height of
@@ -376,10 +377,7 @@
boolean animate = mNotificationStackScroller.isAddOrRemoveAnimationPending();
int stackScrollerPadding;
if (mStatusBarState != StatusBarState.KEYGUARD) {
- int bottom = mQsContainer.getHeader().getHeight();
- stackScrollerPadding = mStatusBarState == StatusBarState.SHADE
- ? bottom + mQsPeekHeight
- : mKeyguardStatusBar.getHeight();
+ stackScrollerPadding = mQsContainer.getHeader().getHeight() + mQsPeekHeight;
mTopPaddingAdjustment = 0;
} else {
mClockPositionAlgorithm.setup(
@@ -1004,8 +1002,8 @@
mKeyguardShowing = keyguardShowing;
mQsContainer.setKeyguardShowing(mKeyguardShowing);
- if (goingToFullShade || (oldState == StatusBarState.KEYGUARD
- && statusBarState == StatusBarState.SHADE_LOCKED)) {
+ if (oldState == StatusBarState.KEYGUARD
+ && (goingToFullShade || statusBarState == StatusBarState.SHADE_LOCKED)) {
animateKeyguardStatusBarOut();
long delay = mStatusBarState == StatusBarState.SHADE_LOCKED
? 0 : mStatusBar.calculateGoingToFullShadeDelay();
@@ -1019,7 +1017,7 @@
mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
if (keyguardShowing && oldState != mStatusBarState) {
mKeyguardBottomArea.onKeyguardShowingChanged();
- mAfforanceHelper.updatePreviews();
+ mQsContainer.hideImmediately();
}
}
if (keyguardShowing) {
@@ -1166,6 +1164,7 @@
private void updateQsState() {
mQsContainer.setExpanded(mQsExpanded);
+ mNotificationStackScroller.setQsExpanded(mQsExpanded);
mNotificationStackScroller.setScrollingEnabled(
mStatusBarState != StatusBarState.KEYGUARD && (!mQsExpanded
|| mQsExpansionFromOverscroll));
@@ -1314,9 +1313,12 @@
}
return;
}
- boolean belowFalsingThreshold = isFalseTouch();
- if (belowFalsingThreshold) {
+
+ // If we move in the opposite direction, reset velocity and use a different duration.
+ boolean oppositeDirection = false;
+ if (vel > 0 && !expand || vel < 0 && expand) {
vel = 0;
+ oppositeDirection = true;
}
ValueAnimator animator = ValueAnimator.ofFloat(mQsExpansionHeight, target);
if (isClick) {
@@ -1325,7 +1327,7 @@
} else {
mFlingAnimationUtils.apply(animator, mQsExpansionHeight, target, vel);
}
- if (belowFalsingThreshold) {
+ if (oppositeDirection) {
animator.setDuration(350);
}
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@@ -1427,7 +1429,7 @@
setQsExpansion(mQsMinExpansionHeight
+ t * (getTempQsMaxExpansion() - mQsMinExpansionHeight));
}
- updateStackHeight(expandedHeight);
+ updateExpandedHeight(expandedHeight);
updateHeader();
updateUnlockIcon();
updateNotificationTranslucency();
@@ -1487,7 +1489,7 @@
maxQsHeight, mStatusBarState == StatusBarState.KEYGUARD
? mClockPositionResult.stackScrollerPadding - mTopPaddingAdjustment
: 0)
- + notificationHeight;
+ + notificationHeight + mNotificationStackScroller.getTopPaddingOverflow();
if (totalHeight > mNotificationStackScroller.getHeight()) {
float fullyCollapsedHeight = maxQsHeight
+ mNotificationStackScroller.getLayoutMinHeight();
@@ -1730,6 +1732,14 @@
if (view == null && mQsExpanded) {
return;
}
+ ExpandableView firstChildNotGone = mNotificationStackScroller.getFirstChildNotGone();
+ ExpandableNotificationRow firstRow = firstChildNotGone instanceof ExpandableNotificationRow
+ ? (ExpandableNotificationRow) firstChildNotGone
+ : null;
+ if (firstRow != null
+ && (view == firstRow || (firstRow.getNotificationParent() == firstRow))) {
+ requestScrollerTopPaddingUpdate(false);
+ }
requestPanelHeightUpdate();
}
@@ -2249,8 +2259,8 @@
mQsAutoReinflateContainer.setTranslationX(translation);
}
- protected void updateStackHeight(float stackHeight) {
- mNotificationStackScroller.setStackHeight(stackHeight);
+ protected void updateExpandedHeight(float expandedHeight) {
+ mNotificationStackScroller.setExpandedHeight(expandedHeight);
updateKeyguardBottomAreaAlpha();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index c6aec73..3de03b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InputDevice;
@@ -37,7 +36,7 @@
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Interpolators;
-import com.android.systemui.LatencyTracker;
+import com.android.keyguard.LatencyTracker;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.doze.DozeLog;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 8ee014c..84deabe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -37,6 +37,7 @@
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.IActivityManager;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.StatusBarManager;
@@ -132,7 +133,7 @@
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.Interpolators;
-import com.android.systemui.LatencyTracker;
+import com.android.keyguard.LatencyTracker;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
@@ -1765,18 +1766,21 @@
for (int i=0; i<N; i++) {
Entry ent = activeNotifications.get(i);
int vis = ent.notification.getNotification().visibility;
+ int userId = ent.notification.getUserId();
// Display public version of the notification if we need to redact.
- final boolean hideSensitive =
- !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId());
+ boolean deviceSensitive = (isLockscreenPublicMode(mCurrentUserId)
+ && !userAllowsPrivateNotificationsInPublic(mCurrentUserId));
+ boolean userSensitive = deviceSensitive || (isLockscreenPublicMode(userId)
+ && !userAllowsPrivateNotificationsInPublic(userId));
boolean sensitiveNote = vis == Notification.VISIBILITY_PRIVATE;
boolean sensitivePackage = packageHasVisibilityOverride(ent.notification.getKey());
- boolean sensitive = (sensitiveNote && hideSensitive) || sensitivePackage;
- boolean showingPublic = sensitive && isLockscreenPublicMode();
+ boolean sensitive = (sensitiveNote && userSensitive) || sensitivePackage;
+ boolean showingPublic = sensitive && isLockscreenPublicMode(userId);
if (showingPublic) {
updatePublicContentView(ent, ent.notification);
}
- ent.row.setSensitive(sensitive, hideSensitive);
+ ent.row.setSensitive(sensitive, deviceSensitive);
if (ent.autoRedacted && ent.legacy) {
// TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
// for legacy auto redacted notifications.
@@ -2745,7 +2749,7 @@
public void handleSystemNavigationKey(int key) {
if (SPEW) Log.d(TAG, "handleSystemNavigationKey: " + key);
if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
- || mKeyguardMonitor.isShowing()) {
+ || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) {
return;
}
@@ -2980,6 +2984,10 @@
return mGestureRec;
}
+ public FingerprintUnlockController getFingerprintUnlockController() {
+ return mFingerprintUnlockController;
+ }
+
private void setNavigationIconHints(int hints) {
if (hints == mNavigationIconHints) return;
@@ -3427,6 +3435,9 @@
if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
}
+ if (mFlashlightController != null) {
+ mFlashlightController.dump(fd, pw, args);
+ }
FalsingManager.getInstance(mContext).dump(pw);
FalsingLog.dump(pw);
@@ -4333,17 +4344,23 @@
}
private void updatePublicMode() {
- boolean isPublic = false;
- if (mStatusBarKeyguardViewManager.isShowing()) {
- for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
- UserInfo userInfo = mCurrentProfiles.valueAt(i);
- if (mStatusBarKeyguardViewManager.isSecure(userInfo.id)) {
- isPublic = true;
- break;
+ final boolean showingKeyguard = mStatusBarKeyguardViewManager.isShowing();
+ final boolean devicePublic = showingKeyguard
+ && mStatusBarKeyguardViewManager.isSecure(mCurrentUserId);
+
+ // Look for public mode users. Users are considered public in either case of:
+ // - device keyguard is shown in secure mode;
+ // - profile is locked with a work challenge.
+ for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+ final int userId = mCurrentProfiles.valueAt(i).id;
+ boolean isProfilePublic = devicePublic;
+ if (!devicePublic && userId != mCurrentUserId) {
+ if (mStatusBarKeyguardViewManager.isSecure(userId)) {
+ isProfilePublic = mKeyguardManager.isDeviceLocked(userId);
}
}
+ setLockscreenPublicMode(isProfilePublic, userId);
}
- setLockscreenPublicMode(isPublic);
}
protected void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
@@ -4378,7 +4395,8 @@
checkBarModes();
updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
- mStatusBarKeyguardViewManager.isSecure());
+ mStatusBarKeyguardViewManager.isSecure(),
+ mStatusBarKeyguardViewManager.isOccluded());
Trace.endSection();
}
@@ -4400,7 +4418,8 @@
public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
if (mStackScroller == null) return;
boolean onKeyguard = mState == StatusBarState.KEYGUARD;
- mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade);
+ boolean publicMode = isAnyProfilePublicMode();
+ mStackScroller.setHideSensitive(publicMode, goingToFullShade);
mStackScroller.setDimmed(onKeyguard, fromShadeLocked /* animate */);
mStackScroller.setExpandingEnabled(!onKeyguard);
ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
@@ -4456,6 +4475,9 @@
animateCollapsePanels();
return true;
}
+ if (mKeyguardUserSwitcher.hideIfNotSimple(true)) {
+ return true;
+ }
return false;
}
@@ -4650,6 +4672,7 @@
* @param expandView The view to expand after going to the shade.
*/
public void goToLockedShade(View expandView) {
+ int userId = mCurrentUserId;
ExpandableNotificationRow row = null;
if (expandView instanceof ExpandableNotificationRow) {
row = (ExpandableNotificationRow) expandView;
@@ -4657,10 +4680,13 @@
// Indicate that the group expansion is changing at this time -- this way the group
// and children backgrounds / divider animations will look correct.
row.setGroupExpansionChanging(true);
+ if (row.getStatusBarNotification() != null) {
+ userId = row.getStatusBarNotification().getUserId();
+ }
}
boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
|| !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();
- if (isLockscreenPublicMode() && fullShadeNeedsBouncer) {
+ if (isLockscreenPublicMode(userId) && fullShadeNeedsBouncer) {
mLeaveOpenOnKeyguardHide = true;
showBouncer();
mDraggedDownRow = row;
@@ -4705,10 +4731,20 @@
mPendingWorkRemoteInputView = clicked;
}
+ private boolean isAnyProfilePublicMode() {
+ for (int i = mCurrentProfiles.size() - 1; i >= 0; i--) {
+ if (isLockscreenPublicMode(mCurrentProfiles.valueAt(i).id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
- protected void onWorkChallengeUnlocked() {
- if (mPendingWorkRemoteInputView != null) {
- final View pendingWorkRemoteInputView = mPendingWorkRemoteInputView;
+ protected void onWorkChallengeChanged() {
+ updatePublicMode();
+ updateNotifications();
+ if (mPendingWorkRemoteInputView != null && !isAnyProfilePublicMode()) {
// Expand notification panel and the notification row, then click on remote input view
final Runnable clickPendingViewRunnable = new Runnable() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index b0b86be..a8b0122 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -350,9 +350,7 @@
}
} else if (v == mAlarmStatus && mNextAlarm != null) {
PendingIntent showIntent = mNextAlarm.getShowIntent();
- if (showIntent != null && showIntent.isActivity()) {
- mActivityStarter.startActivity(showIntent.getIntent(), true /* dismissShade */);
- }
+ mActivityStarter.startPendingIntentDismissingKeyguard(showIntent);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 01609e4..77c60fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -31,7 +31,7 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.DejankUtils;
-import com.android.systemui.LatencyTracker;
+import com.android.keyguard.LatencyTracker;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.RemoteInputController;
@@ -264,10 +264,12 @@
}
}
mOccluded = occluded;
- mPhoneStatusBar.updateMediaMetaData(false, animate && !occluded);
+ if (mShowing) {
+ mPhoneStatusBar.updateMediaMetaData(false, animate && !occluded);
+ }
mStatusBarWindowManager.setKeyguardOccluded(occluded);
reset();
- if (animate && !occluded) {
+ if (animate && !occluded && mShowing) {
mPhoneStatusBar.animateKeyguardUnoccluding();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index b9c7a4b..6726c92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -53,6 +53,7 @@
protected boolean mCharged;
protected boolean mPowerSave;
private boolean mTestmode = false;
+ private boolean mHasReceivedBattery = false;
public BatteryControllerImpl(Context context) {
mContext = context;
@@ -92,6 +93,7 @@
synchronized (mChangeCallbacks) {
mChangeCallbacks.add(cb);
}
+ if (!mHasReceivedBattery) return;
cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging);
cb.onPowerSaveChanged(mPowerSave);
}
@@ -108,6 +110,7 @@
final String action = intent.getAction();
if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
+ mHasReceivedBattery = true;
mLevel = (int)(100f
* intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
/ intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index 91b21ed..4e9fc76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -27,6 +27,8 @@
import android.text.TextUtils;
import android.util.Log;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -80,6 +82,7 @@
public void setFlashlight(boolean enabled) {
boolean pendingError = false;
synchronized (this) {
+ if (mCameraId == null) return;
if (mFlashlightEnabled != enabled) {
mFlashlightEnabled = enabled;
try {
@@ -235,6 +238,17 @@
}
};
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("FlashlightController state:");
+
+ pw.print(" mCameraId=");
+ pw.println(mCameraId);
+ pw.print(" mFlashlightEnabled=");
+ pw.println(mFlashlightEnabled);
+ pw.print(" mTorchAvailable=");
+ pw.println(mTorchAvailable);
+ }
+
public interface FlashlightListener {
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index c175180..44816f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -38,6 +38,7 @@
private int mCurrentUser;
private boolean mShowing;
private boolean mSecure;
+ private boolean mOccluded;
private boolean mCanSkipBouncer;
private boolean mListening;
@@ -81,6 +82,10 @@
return mSecure;
}
+ public boolean isOccluded() {
+ return mOccluded;
+ }
+
public boolean canSkipBouncer() {
return mCanSkipBouncer;
}
@@ -99,10 +104,11 @@
}
}
- public void notifyKeyguardState(boolean showing, boolean secure) {
- if (mShowing == showing && mSecure == secure) return;
+ public void notifyKeyguardState(boolean showing, boolean secure, boolean occluded) {
+ if (mShowing == showing && mSecure == secure && mOccluded == occluded) return;
mShowing = showing;
mSecure = secure;
+ mOccluded = occluded;
notifyKeyguardChanged();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index 21f3f5e..1cf4050 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -128,7 +128,7 @@
}
}
- private void hide(boolean animate) {
+ private boolean hide(boolean animate) {
if (mUserSwitcher != null && mUserSwitcherContainer.getVisibility() == View.VISIBLE) {
cancelAnimations();
if (animate) {
@@ -137,7 +137,9 @@
mUserSwitcherContainer.setVisibility(View.GONE);
}
mStatusBarView.setKeyguardUserSwitcherShowing(false, animate);
+ return true;
}
+ return false;
}
private void cancelAnimations() {
@@ -223,10 +225,11 @@
}
}
- public void hideIfNotSimple(boolean animate) {
+ public boolean hideIfNotSimple(boolean animate) {
if (mUserSwitcherContainer != null && !mUserSwitcherController.isSimpleUserSwitcher()) {
- hide(animate);
+ return hide(animate);
}
+ return false;
}
boolean isAnimating() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 50e5b88..81da672 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -43,6 +43,7 @@
private boolean mShadeExpanded;
private float mMaxHeadsUpTranslation;
private boolean mDismissAllInProgress;
+ private int mLayoutMinHeight;
public int getScrollY() {
return mScrollY;
@@ -137,10 +138,6 @@
mStackTranslation = stackTranslation;
}
- public int getLayoutHeight() {
- return mLayoutHeight;
- }
-
public void setLayoutHeight(int layoutHeight) {
mLayoutHeight = layoutHeight;
}
@@ -154,7 +151,7 @@
}
public int getInnerHeight() {
- return mLayoutHeight - mTopPadding;
+ return Math.max(mLayoutHeight - mTopPadding, mLayoutMinHeight);
}
public boolean isShadeExpanded() {
@@ -180,4 +177,8 @@
public boolean isDismissAllInProgress() {
return mDismissAllInProgress;
}
+
+ public void setLayoutMinHeight(int layoutMinHeight) {
+ mLayoutMinHeight = layoutMinHeight;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 90f4100..4b46578 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -112,11 +112,7 @@
private int mCurrentStackHeight = Integer.MAX_VALUE;
private final Paint mBackgroundPaint = new Paint();
- /**
- * mCurrentStackHeight is the actual stack height, mLastSetStackHeight is the stack height set
- * externally from {@link #setStackHeight}
- */
- private float mLastSetStackHeight;
+ private float mExpandedHeight;
private int mOwnScrollY;
private int mMaxLayoutHeight;
@@ -355,6 +351,9 @@
return object.getBackgroundFadeAmount();
}
};
+ private boolean mQsExpanded;
+ private boolean mForwardScrollable;
+ private boolean mBackwardScrollable;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -520,6 +519,7 @@
clampScrollPosition();
requestChildrenUpdate();
updateFirstAndLastBackgroundViews();
+ updateAlgorithmLayoutMinHeight();
}
private void requestAnimationOnViewResize(ExpandableNotificationRow row) {
@@ -561,9 +561,14 @@
private void updateAlgorithmHeightAndPadding() {
mAmbientState.setLayoutHeight(getLayoutHeight());
+ updateAlgorithmLayoutMinHeight();
mAmbientState.setTopPadding(mTopPadding);
}
+ private void updateAlgorithmLayoutMinHeight() {
+ mAmbientState.setLayoutMinHeight(mQsExpanded && !onKeyguard() ? getLayoutMinHeight() : 0);
+ }
+
/**
* Updates the children views according to the stack scroll algorithm. Call this whenever
* modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
@@ -594,7 +599,7 @@
if (startingPosition < mOwnScrollY) {
// This child starts off screen, so let's keep it offscreen to keep the others visible
- mOwnScrollY += childHeight;
+ setOwnScrollY(mOwnScrollY + childHeight);
}
}
}
@@ -617,7 +622,7 @@
// Only apply the scroll if we're scrolling the view upwards, or the view is so far up
// that it is not visible anymore.
if (mOwnScrollY < targetScroll || outOfViewScroll < mOwnScrollY) {
- mOwnScrollY = targetScroll;
+ setOwnScrollY(targetScroll);
}
}
}
@@ -637,7 +642,7 @@
private void clampScrollPosition() {
int scrollRange = getScrollRange();
if (scrollRange < mOwnScrollY) {
- mOwnScrollY = scrollRange;
+ setOwnScrollY(scrollRange);
}
}
@@ -660,19 +665,19 @@
}
/**
- * Update the height of the stack to a new height.
+ * Update the height of the panel.
*
- * @param height the new height of the stack
+ * @param height the expanded height of the panel
*/
- public void setStackHeight(float height) {
- mLastSetStackHeight = height;
+ public void setExpandedHeight(float height) {
+ mExpandedHeight = height;
setIsExpanded(height > 0.0f);
int stackHeight;
float translationY;
float appearEndPosition = getAppearEndPosition();
float appearStartPosition = getAppearStartPosition();
if (height >= appearEndPosition) {
- translationY = mTopPaddingOverflow;
+ translationY = 0;
stackHeight = (int) height;
} else {
float appearFraction = getAppearFraction(height);
@@ -699,8 +704,12 @@
* Measured relative to the resting position.
*/
private float getExpandTranslationStart() {
- int startPosition = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp()
- ? 0 : -getFirstChildIntrinsicHeight();
+ int startPosition = 0;
+ if (!mTrackingHeadsUp && !mHeadsUpManager.hasPinnedHeadsUp()) {
+ startPosition = - Math.min(getFirstChildIntrinsicHeight(),
+ mMaxLayoutHeight - mIntrinsicPadding - mBottomStackSlowDownHeight
+ - mBottomStackPeekSize);
+ }
return startPosition - mTopPadding;
}
@@ -723,7 +732,7 @@
? mHeadsUpManager.getTopHeadsUpPinnedHeight() + mBottomStackPeekSize
+ mBottomStackSlowDownHeight
: getLayoutMinHeight();
- return firstItemHeight + mTopPadding + mTopPaddingOverflow;
+ return firstItemHeight + (onKeyguard() ? mTopPadding : mIntrinsicPadding);
}
/**
@@ -1048,7 +1057,7 @@
@Override
public int getMaxExpandHeight(ExpandableView view) {
int maxContentHeight = view.getMaxContentHeight();
- if (view.isSummaryWithChildren()) {
+ if (view.isSummaryWithChildren() && view.getParent() == this) {
// Faking a measure with the group expanded to simulate how the group would look if
// it was. Doing a calculation here would be highly non-trivial because of the
// algorithm
@@ -1063,8 +1072,11 @@
row.getStatusBarNotification());
mGroupExpandedForMeasure = false;
row.setForceUnlocked(false);
- int height = mCurrentStackScrollState.getViewStateForView(view).height;
- return Math.min(height, maxContentHeight);
+ StackViewState viewState = mCurrentStackScrollState.getViewStateForView(view);
+ if (viewState != null) {
+ // The view could have been removed
+ return Math.min(viewState.height, maxContentHeight);
+ }
}
return maxContentHeight;
}
@@ -1153,6 +1165,10 @@
@Override
public boolean isAntiFalsingNeeded() {
+ return onKeyguard();
+ }
+
+ private boolean onKeyguard() {
return mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD;
}
@@ -1262,7 +1278,7 @@
if (!isScrollingEnabled()) {
return false;
}
- if (isInsideQsContainer(ev)) {
+ if (isInsideQsContainer(ev) && !mIsBeingDragged) {
return false;
}
mForcedScroll = null;
@@ -1431,7 +1447,7 @@
false /* onTop */,
false /* animate */);
}
- mOwnScrollY = range;
+ setOwnScrollY(range);
scrollAmount = 0.0f;
}
return scrollAmount;
@@ -1462,7 +1478,7 @@
setOverScrolledPixels(currentTopPixels - newScrollY,
true /* onTop */,
false /* animate */);
- mOwnScrollY = 0;
+ setOwnScrollY(0);
scrollAmount = 0.0f;
}
return scrollAmount;
@@ -1676,7 +1692,7 @@
}
private void customScrollTo(int y) {
- mOwnScrollY = y;
+ setOwnScrollY(y);
updateChildren();
}
@@ -1687,7 +1703,7 @@
final int oldX = mScrollX;
final int oldY = mOwnScrollY;
mScrollX = scrollX;
- mOwnScrollY = scrollY;
+ setOwnScrollY(scrollY);
if (clampedY) {
springBack();
} else {
@@ -1717,12 +1733,12 @@
if (overScrolledTop) {
onTop = true;
newAmount = -mOwnScrollY;
- mOwnScrollY = 0;
+ setOwnScrollY(0);
mDontReportNextOverScroll = true;
} else {
onTop = false;
newAmount = mOwnScrollY - scrollRange;
- mOwnScrollY = scrollRange;
+ setOwnScrollY(scrollRange);
}
setOverScrollAmount(newAmount, onTop, false);
setOverScrollAmount(0.0f, onTop, true);
@@ -1850,6 +1866,19 @@
if (scrollable != mScrollable) {
mScrollable = scrollable;
setFocusable(scrollable);
+ updateForwardAndBackwardScrollability();
+ }
+ }
+
+ private void updateForwardAndBackwardScrollability() {
+ boolean forwardScrollable = mScrollable && mOwnScrollY < getScrollRange();
+ boolean backwardsScrollable = mScrollable && mOwnScrollY > 0;
+ boolean changed = forwardScrollable != mForwardScrollable
+ || backwardsScrollable != mBackwardScrollable;
+ mForwardScrollable = forwardScrollable;
+ mBackwardScrollable = backwardsScrollable;
+ if (changed) {
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
}
}
@@ -2012,6 +2041,7 @@
if (!mIsExpanded) {
mBackgroundBounds.top = 0;
mBackgroundBounds.bottom = 0;
+ return;
}
ActivatableNotificationView firstView = mFirstVisibleBackgroundChild;
int top = 0;
@@ -2109,13 +2139,13 @@
float topAmount = getCurrentOverScrollAmount(true);
float bottomAmount = getCurrentOverScrollAmount(false);
if (velocityY < 0 && topAmount > 0) {
- mOwnScrollY -= (int) topAmount;
+ setOwnScrollY(mOwnScrollY - (int) topAmount);
mDontReportNextOverScroll = true;
setOverScrollAmount(0, true, false);
mMaxOverScroll = Math.abs(velocityY) / 1000f * getRubberBandFactor(true /* onTop */)
* mOverflingDistance + topAmount;
} else if (velocityY > 0 && bottomAmount > 0) {
- mOwnScrollY += bottomAmount;
+ setOwnScrollY((int) (mOwnScrollY + bottomAmount));
setOverScrollAmount(0, false, false);
mMaxOverScroll = Math.abs(velocityY) / 1000f
* getRubberBandFactor(false /* onTop */) * mOverflingDistance
@@ -2158,26 +2188,22 @@
*/
public void updateTopPadding(float qsHeight, boolean animate,
boolean ignoreIntrinsicPadding) {
- float start = qsHeight;
- float stackHeight = getHeight() - start;
+ int topPadding = (int) qsHeight;
int minStackHeight = getLayoutMinHeight();
- if (stackHeight <= minStackHeight) {
- float overflow = minStackHeight - stackHeight;
- stackHeight = minStackHeight;
- start = getHeight() - stackHeight;
- mTopPaddingOverflow = overflow;
+ if (topPadding + minStackHeight > getHeight()) {
+ mTopPaddingOverflow = topPadding + minStackHeight - getHeight();
} else {
mTopPaddingOverflow = 0;
}
- setTopPadding(ignoreIntrinsicPadding ? (int) start : clampPadding((int) start),
+ setTopPadding(ignoreIntrinsicPadding ? topPadding : clampPadding(topPadding),
animate);
- setStackHeight(mLastSetStackHeight);
+ setExpandedHeight(mExpandedHeight);
}
public int getLayoutMinHeight() {
int firstChildMinHeight = getFirstChildIntrinsicHeight();
return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
- mMaxLayoutHeight - mTopPadding);
+ mMaxLayoutHeight - mIntrinsicPadding);
}
public int getFirstChildIntrinsicHeight() {
@@ -2470,11 +2496,11 @@
if (endPosition <= mOwnScrollY) {
// This child is fully scrolled of the top, so we have to deduct its height from the
// scrollPosition
- mOwnScrollY -= childHeight;
+ setOwnScrollY(mOwnScrollY - childHeight);
} else if (startingPosition < mOwnScrollY) {
// This child is currently being scrolled into, set the scroll position to the start of
// this child
- mOwnScrollY = startingPosition;
+ setOwnScrollY(startingPosition);
}
}
@@ -3059,7 +3085,7 @@
public void onExpansionStopped() {
mIsExpansionChanging = false;
if (!mIsExpanded) {
- mOwnScrollY = 0;
+ setOwnScrollY(0);
mPhoneStatusBar.resetUserExpandedStates();
// lets make sure nothing is in the overlay / transient anymore
@@ -3092,7 +3118,7 @@
public void resetScrollPosition() {
mScroller.abortAnimation();
- mOwnScrollY = 0;
+ setOwnScrollY(0);
}
private void setIsExpanded(boolean isExpanded) {
@@ -3128,10 +3154,14 @@
updateScrollPositionOnExpandInBottom(view);
clampScrollPosition();
notifyHeightChangeListener(view);
+ ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
+ ? (ExpandableNotificationRow) view
+ : null;
+ if (row != null && (row == mFirstVisibleBackgroundChild
+ || row.getNotificationParent() == mFirstVisibleBackgroundChild)) {
+ updateAlgorithmLayoutMinHeight();
+ }
if (needsAnimation) {
- ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
- ? (ExpandableNotificationRow) view
- : null;
requestAnimationOnViewResize(row);
}
requestChildrenUpdate();
@@ -3157,7 +3187,7 @@
}
int stackEnd = getStackEndPosition();
if (endPosition > stackEnd) {
- mOwnScrollY += endPosition - stackEnd;
+ setOwnScrollY((int) (mOwnScrollY + endPosition - stackEnd));
mDisallowScrollingInThisMotion = true;
}
}
@@ -3414,7 +3444,7 @@
}
private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
- if (screenLocation == null || screenLocation.y < mTopPadding + mTopPaddingOverflow) {
+ if (screenLocation == null || screenLocation.y < mTopPadding) {
return AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE;
}
if (screenLocation.y > getBottomMostNotificationBottom()) {
@@ -3719,15 +3749,14 @@
@Override
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfoInternal(info);
- final int scrollRange = getScrollRange();
- if (scrollRange > 0) {
+ if (mScrollable) {
info.setScrollable(true);
- if (mScrollY > 0) {
+ if (mBackwardScrollable) {
info.addAction(
AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD);
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_UP);
}
- if (mScrollY < scrollRange) {
+ if (mForwardScrollable) {
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD);
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_DOWN);
}
@@ -3898,6 +3927,18 @@
mCurrentStackScrollState.removeViewStateForView(view);
}
+ public void setQsExpanded(boolean qsExpanded) {
+ mQsExpanded = qsExpanded;
+ updateAlgorithmLayoutMinHeight();
+ }
+
+ public void setOwnScrollY(int ownScrollY) {
+ if (ownScrollY != mOwnScrollY) {
+ mOwnScrollY = ownScrollY;
+ updateForwardAndBackwardScrollability();
+ }
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
@@ -4121,7 +4162,7 @@
onDragCancelled(animView);
// If we're on the lockscreen we want to false this.
- if (mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD) {
+ if (isAntiFalsingNeeded()) {
mHandler.removeCallbacks(mFalsingCheck);
mHandler.postDelayed(mFalsingCheck, COVER_GEAR_DELAY);
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index 5fe9296..3b14e60 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -30,6 +30,8 @@
PreferenceFragment.OnPreferenceStartFragmentCallback,
PreferenceFragment.OnPreferenceStartScreenCallback {
+ static final String ACTIVITY_ALIAS_NAME = "com.android.systemui.tuner.TunerSettingLink";
+
private static final String TAG_TUNER = "tuner";
protected void onCreate(Bundle savedInstanceState) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index e0a1547..ebc962d 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -255,6 +255,12 @@
enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
+
+ userContext(context).getPackageManager().setComponentEnabledSetting(
+ new ComponentName(context, TunerActivity.ACTIVITY_ALIAS_NAME),
+ enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
}
public static final boolean isTunerEnabled(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 085e003..75c2bcd 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -19,13 +19,13 @@
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerNative;
-import android.app.ActivityOptions;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Rect;
import android.media.session.MediaController;
@@ -33,24 +33,27 @@
import android.media.session.PlaybackState;
import android.os.Debug;
import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
-
+import android.view.IWindowManager;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.WindowManagerGlobal;
import com.android.systemui.Prefs;
import com.android.systemui.R;
-import com.android.systemui.SystemUIApplication;
-import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.statusbar.tv.TvStatusBar;
+import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import java.util.ArrayList;
import java.util.List;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
import static com.android.systemui.Prefs.Key.TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN;
/**
@@ -160,6 +163,9 @@
private boolean mOnboardingShown;
private String[] mLastPackagesResourceGranted;
+ private InputChannel mInputChannel;
+ private PipInputEventReceiver mInputEventReceiver;
+
private final Runnable mResizePinnedStackRunnable = new Runnable() {
@Override
public void run() {
@@ -197,6 +203,25 @@
}
};
+ /**
+ * Input handler used for Pip windows. Currently eats all the input events.
+ */
+ private final class PipInputEventReceiver extends InputEventReceiver {
+ public PipInputEventReceiver(InputChannel inputChannel, Looper looper) {
+ super(inputChannel, looper);
+ }
+
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = true;
+ try {
+ // To be implemented for input handling over Pip windows
+ } finally {
+ finishInputEvent(event, handled);
+ }
+ }
+ }
+
private PipManager() { }
/**
@@ -221,6 +246,20 @@
mPipRecentsOverlayManager = new PipRecentsOverlayManager(context);
mMediaSessionManager =
(MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
+
+ PackageManager pm = mContext.getPackageManager();
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) {
+ // Initialize the Pip input consumer
+ mInputChannel = new InputChannel();
+ try {
+ IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ wm.destroyInputConsumer(INPUT_CONSUMER_PIP);
+ wm.createInputConsumer(INPUT_CONSUMER_PIP, mInputChannel);
+ mInputEventReceiver = new PipInputEventReceiver(mInputChannel, Looper.myLooper());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to create Pip input consumer", e);
+ }
+ }
}
private void loadConfigurationsAndApply() {
@@ -298,6 +337,7 @@
mListeners.get(i).onMoveToFullscreen();
}
resizePinnedStack(mState);
+ updatePipVisibility(false);
}
/**
@@ -307,7 +347,11 @@
*/
private void showPipOverlay() {
if (DEBUG) Log.d(TAG, "showPipOverlay()");
- PipOverlayActivity.showPipOverlay(mContext);
+ // Temporary workaround to prevent the overlay on phones
+ PackageManager pm = mContext.getPackageManager();
+ if (pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY)) {
+ PipOverlayActivity.showPipOverlay(mContext);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java
index b3e9f43..3306cb3 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipUI.java
@@ -21,11 +21,10 @@
import com.android.systemui.SystemUI;
-import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
/**
- * Controls the picture-in-picture window for TV devices.
+ * Controls the picture-in-picture window.
*/
public class PipUI extends SystemUI {
private boolean mSupportPip;
@@ -33,8 +32,7 @@
@Override
public void start() {
PackageManager pm = mContext.getPackageManager();
- mSupportPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)
- && pm.hasSystemFeature(FEATURE_LEANBACK);
+ mSupportPip = pm.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
if (!mSupportPip) {
return;
}
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 23967aa..6038171 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -45,7 +45,8 @@
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
mockito-target-minus-junit4 \
- SystemUI-proto-tags
+ SystemUI-proto \
+ SystemUI-tags
LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
diff --git a/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
new file mode 100644
index 0000000..5cb5e68
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/BatteryMeterDrawableTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyFloat;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BatteryMeterDrawableTest {
+
+ private Context mContext;
+ private Resources mResources;
+ private BatteryMeterDrawable mBatteryMeter;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getTargetContext();
+ mResources = mContext.getResources();
+ mBatteryMeter = new BatteryMeterDrawable(mContext, 0);
+ }
+
+ @Test
+ public void testGetIntrinsicSize() {
+ assertEquals(
+ mResources.getDimensionPixelSize(R.dimen.battery_width),
+ mBatteryMeter.getIntrinsicWidth());
+ assertEquals(
+ mResources.getDimensionPixelSize(R.dimen.battery_height),
+ mBatteryMeter.getIntrinsicHeight());
+ }
+
+ @Test
+ public void testDrawNothingBeforeOnBatteryLevelChanged() {
+ final Canvas canvas = mock(Canvas.class);
+ mBatteryMeter.draw(canvas);
+ verify(canvas, never()).drawPath(any(), any());
+ verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
+ }
+
+ @Test
+ public void testDrawImageButNoTextIfPluggedIn() {
+ mBatteryMeter.onBatteryLevelChanged(0, true, true);
+ final Canvas canvas = mock(Canvas.class);
+ mBatteryMeter.draw(canvas);
+ verify(canvas, atLeastOnce()).drawPath(any(), any());
+ verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
+ }
+
+ @Test
+ public void testDrawTextIfNotPluggedIn() {
+ mBatteryMeter.onBatteryLevelChanged(0, false, false);
+ final Canvas canvas = mock(Canvas.class);
+ mBatteryMeter.draw(canvas);
+ verify(canvas, times(1)).drawText(anyString(), anyFloat(), anyFloat(), any());
+ }
+
+ @Test
+ public void testDrawNoTextIfPowerSaveEnabled() {
+ mBatteryMeter.onBatteryLevelChanged(0, false, false);
+ mBatteryMeter.onPowerSaveChanged(true);
+ final Canvas canvas = mock(Canvas.class);
+ mBatteryMeter.draw(canvas);
+ verify(canvas, never()).drawText(anyString(), anyFloat(), anyFloat(), any());
+ }
+
+ @Test
+ public void testDrawTextWarningAtCriticalLevel() {
+ int criticalLevel = mResources.getInteger(
+ com.android.internal.R.integer.config_criticalBatteryWarningLevel);
+ mBatteryMeter.onBatteryLevelChanged(criticalLevel, false, false);
+ final Canvas canvas = mock(Canvas.class);
+ mBatteryMeter.draw(canvas);
+ String warningString = mResources.getString(R.string.battery_meter_very_low_overlay_symbol);
+ verify(canvas, times(1)).drawText(eq(warningString), anyFloat(), anyFloat(), any());
+ }
+
+ @Test
+ public void testDrawTextNoWarningAboveCriticalLevel() {
+ int criticalLevel = mResources.getInteger(
+ com.android.internal.R.integer.config_criticalBatteryWarningLevel);
+ mBatteryMeter.onBatteryLevelChanged(criticalLevel + 1, false, false);
+ final Canvas canvas = mock(Canvas.class);
+ mBatteryMeter.draw(canvas);
+ String warningString = mResources.getString(R.string.battery_meter_very_low_overlay_symbol);
+ verify(canvas, never()).drawText(eq(warningString), anyFloat(), anyFloat(), any());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
index ab7de39..9050b83 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -33,13 +33,11 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.net.Uri;
import android.os.HandlerThread;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.PluginInstanceManager.ClassLoaderFactory;
import org.junit.After;
import org.junit.Before;
@@ -64,6 +62,7 @@
private PackageManager mMockPm;
private PluginListener mMockListener;
private PluginInstanceManager mPluginInstanceManager;
+ private PluginManager mMockManager;
@Before
public void setup() throws Exception {
@@ -72,9 +71,11 @@
mContextWrapper = new MyContextWrapper(getContext());
mMockPm = mock(PackageManager.class);
mMockListener = mock(PluginListener.class);
+ mMockManager = mock(PluginManager.class);
+ when(mMockManager.getClassLoader(Mockito.any(), Mockito.any()))
+ .thenReturn(getClass().getClassLoader());
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
- mMockListener, true, mHandlerThread.getLooper(), 1, true,
- new TestClassLoaderFactory());
+ mMockListener, true, mHandlerThread.getLooper(), 1, mMockManager, true);
sMockPlugin = mock(Plugin.class);
when(sMockPlugin.getVersion()).thenReturn(1);
}
@@ -89,7 +90,7 @@
public void testNoPlugins() {
when(mMockPm.queryIntentServices(Mockito.any(), Mockito.anyInt())).thenReturn(
Collections.emptyList());
- mPluginInstanceManager.startListening();
+ mPluginInstanceManager.loadAll();
waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler);
@@ -112,7 +113,7 @@
public void testPluginDestroy() {
createPlugin(); // Get into valid created state.
- mPluginInstanceManager.stopListening();
+ mPluginInstanceManager.destroy();
waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler);
@@ -127,7 +128,7 @@
setupFakePmQuery();
when(sMockPlugin.getVersion()).thenReturn(2);
- mPluginInstanceManager.startListening();
+ mPluginInstanceManager.loadAll();
waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler);
@@ -141,10 +142,7 @@
public void testReloadOnChange() {
createPlugin(); // Get into valid created state.
- // Send a package changed broadcast.
- Intent i = new Intent(Intent.ACTION_PACKAGE_CHANGED,
- Uri.fromParts("package", "com.android.systemui", null));
- mPluginInstanceManager.onReceive(mContextWrapper, i);
+ mPluginInstanceManager.onPackageChange("com.android.systemui");
waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler);
@@ -164,11 +162,10 @@
public void testNonDebuggable() {
// Create a version that thinks the build is not debuggable.
mPluginInstanceManager = new PluginInstanceManager(mContextWrapper, mMockPm, "myAction",
- mMockListener, true, mHandlerThread.getLooper(), 1, false,
- new TestClassLoaderFactory());
+ mMockListener, true, mHandlerThread.getLooper(), 1, mMockManager, false);
setupFakePmQuery();
- mPluginInstanceManager.startListening();
+ mPluginInstanceManager.loadAll();
waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler);;
@@ -236,19 +233,12 @@
private void createPlugin() {
setupFakePmQuery();
- mPluginInstanceManager.startListening();
+ mPluginInstanceManager.loadAll();
waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler);
}
- private static class TestClassLoaderFactory extends ClassLoaderFactory {
- @Override
- public ClassLoader createClassLoader(String path, ClassLoader base) {
- return base;
- }
- }
-
// Real context with no registering/unregistering of receivers.
private static class MyContextWrapper extends ContextWrapper {
public MyContextWrapper(Context base) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index 56e742a..4b1827d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -51,7 +51,7 @@
mMockFactory = mock(PluginInstanceManagerFactory.class);
mMockPluginInstance = mock(PluginInstanceManager.class);
when(mMockFactory.createPluginInstanceManager(Mockito.any(), Mockito.any(), Mockito.any(),
- Mockito.anyBoolean(), Mockito.any(), Mockito.anyInt()))
+ Mockito.anyBoolean(), Mockito.any(), Mockito.anyInt(), Mockito.any()))
.thenReturn(mMockPluginInstance);
mPluginManager = new PluginManager(getContext(), mMockFactory, true, mMockExceptionHandler);
resetExceptionHandler();
@@ -62,7 +62,7 @@
public void testAddListener() {
mPluginManager.addPluginListener("myAction", mMockListener, 1);
- verify(mMockPluginInstance).startListening();
+ verify(mMockPluginInstance).loadAll();
}
@Test
@@ -70,7 +70,7 @@
mPluginManager.addPluginListener("myAction", mMockListener, 1);
mPluginManager.removePluginListener(mMockListener);
- verify(mMockPluginInstance).stopListening();
+ verify(mMockPluginInstance).destroy();
}
@Test
@@ -80,7 +80,7 @@
resetExceptionHandler();
mPluginManager.addPluginListener("myAction", mMockListener, 1);
- verify(mMockPluginInstance, Mockito.never()).startListening();
+ verify(mMockPluginInstance, Mockito.never()).loadAll();
}
@Test
diff --git a/preloaded-classes b/preloaded-classes
index 42f290e..5ddd08b 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -2077,9 +2077,6 @@
android.view.HandlerActionQueue
android.view.HandlerActionQueue$HandlerAction
android.view.HardwareLayer
-android.view.IAssetAtlas
-android.view.IAssetAtlas$Stub
-android.view.IAssetAtlas$Stub$Proxy
android.view.IGraphicsStats
android.view.IGraphicsStats$Stub
android.view.IGraphicsStats$Stub$Proxy
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index da041da..64d8a4c 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2566,6 +2566,15 @@
// OPEN: Settings > Wireless > Manage wireless plan dialog
DIALOG_MANAGE_MOBILE_PLAN = 609;
+ // ACTION: Logs network type of the device while provisioning
+ PROVISIONING_NETWORK_TYPE = 610;
+
+ // ACTION: Logs action which triggered provisioning.
+ PROVISIONING_ACTION = 611;
+
+ // ACTION: Logs extra passed by the dpc while provisioning.
+ PROVISIONING_EXTRA = 612;
+
// ---- End O Constants, all O constants go above this line ----
// Add new aosp constants above this line.
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index 0658620..bf3681b 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -28,7 +28,7 @@
frameworks/base/libs/hwui \
$(rs_generated_include_dir)
-LOCAL_CFLAGS += -Wno-unused-parameter -std=c++11
+LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 06c4350..af370ff 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -644,7 +644,7 @@
in_allocs[2] = (RsAllocation)C;
rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
- in_allocs, sizeof(in_allocs), nullptr,
+ in_allocs, NELEM(in_allocs), nullptr,
&call, sizeof(call), nullptr, 0);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0b83e66..4819c0a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -64,6 +64,7 @@
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
@@ -498,20 +499,6 @@
}
@Override
- public void sendAccessibilityEvents(ParceledListSlice events, int userId) {
- List<AccessibilityEvent> a11yEvents = events.getList();
- // Grab the lock once for the entire batch
- synchronized (mLock) {
- int numEventsToProcess = Math.min(a11yEvents.size(),
- AccessibilityManager.MAX_A11Y_EVENTS_PER_SERVICE_CALL);
- for (int i = 0; i < numEventsToProcess; i++) {
- AccessibilityEvent event = a11yEvents.get(i);
- sendAccessibilityEvent(event, userId);
- }
- }
- }
-
- @Override
public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) {
synchronized (mLock) {
// We treat calls from a profile as if made by its parent as profiles
@@ -1315,14 +1302,8 @@
private void updateServicesLocked(UserState userState) {
Map<ComponentName, Service> componentNameToServiceMap =
userState.mComponentNameToServiceMap;
- boolean isUnlockingOrUnlocked;
- final long identity = Binder.clearCallingIdentity();
- try {
- isUnlockingOrUnlocked = mContext.getSystemService(UserManager.class)
+ boolean isUnlockingOrUnlocked = LocalServices.getService(UserManagerInternal.class)
.isUserUnlockingOrUnlocked(userState.mUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 497eac9..8424b39 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -6057,7 +6057,11 @@
// the app developer's cert, so they're different on every
// device.
if (signaturesMatch(sigs, pkgInfo)) {
- if (pkgInfo.versionCode >= version) {
+ if ((pkgInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
+ Slog.i(TAG, "Package has restoreAnyVersion; taking data");
+ policy = RestorePolicy.ACCEPT;
+ } else if (pkgInfo.versionCode >= version) {
Slog.i(TAG, "Sig + version match; taking data");
policy = RestorePolicy.ACCEPT;
} else {
@@ -7479,7 +7483,11 @@
// the app developer's cert, so they're different on every
// device.
if (signaturesMatch(sigs, pkgInfo)) {
- if (pkgInfo.versionCode >= version) {
+ if ((pkgInfo.applicationInfo.flags
+ & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
+ Slog.i(TAG, "Package has restoreAnyVersion; taking data");
+ policy = RestorePolicy.ACCEPT;
+ } else if (pkgInfo.versionCode >= version) {
Slog.i(TAG, "Sig + version match; taking data");
policy = RestorePolicy.ACCEPT;
} else {
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 58f2074..9efafb7 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -17,7 +17,12 @@
LOCAL_AIDL_INCLUDES += \
system/netd/server/binder
-LOCAL_JAVA_LIBRARIES := services.net telephony-common
+LOCAL_JAVA_LIBRARIES := \
+ services.net \
+ telephony-common \
+ android.hardware.power@1.0-java \
+ android.hardware.light@2.0-java
+
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
deleted file mode 100644
index b0f6048..0000000
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ /dev/null
@@ -1,717 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You 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.server;
-
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.Atlas;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.drawable.Drawable;
-import android.os.Environment;
-import android.os.RemoteException;
-import android.os.SystemProperties;
-import android.util.Log;
-import android.util.LongSparseArray;
-import android.view.GraphicBuffer;
-import android.view.IAssetAtlas;
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashSet;
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * This service is responsible for packing preloaded bitmaps into a single
- * atlas texture. The resulting texture can be shared across processes to
- * reduce overall memory usage.
- *
- * @hide
- */
-public class AssetAtlasService extends IAssetAtlas.Stub {
- /**
- * Name of the <code>AssetAtlasService</code>.
- */
- public static final String ASSET_ATLAS_SERVICE = "assetatlas";
-
- private static final String LOG_TAG = "AssetAtlas";
-
- // Turns debug logs on/off. Debug logs are kept to a minimum and should
- // remain on to diagnose issues
- private static final boolean DEBUG_ATLAS = true;
-
- // When set to true the content of the atlas will be saved to disk
- // in /data/system/atlas.png. The shared GraphicBuffer may be empty
- private static final boolean DEBUG_ATLAS_TEXTURE = false;
-
- // Minimum size in pixels to consider for the resulting texture
- private static final int MIN_SIZE = 512;
- // Maximum size in pixels to consider for the resulting texture
- private static final int MAX_SIZE = 2048;
- // Increment in number of pixels between size variants when looking
- // for the best texture dimensions
- private static final int STEP = 64;
-
- // This percentage of the total number of pixels represents the minimum
- // number of pixels we want to be able to pack in the atlas
- private static final float PACKING_THRESHOLD = 0.8f;
-
- // Defines the number of int fields used to represent a single entry
- // in the atlas map. This number defines the size of the array returned
- // by the getMap(). See the mAtlasMap field for more information
- private static final int ATLAS_MAP_ENTRY_FIELD_COUNT = 3;
-
- // Specifies how our GraphicBuffer will be used. To get proper swizzling
- // the buffer will be written to using OpenGL (from JNI) so we can leave
- // the software flag set to "never"
- private static final int GRAPHIC_BUFFER_USAGE = GraphicBuffer.USAGE_SW_READ_NEVER |
- GraphicBuffer.USAGE_SW_WRITE_NEVER | GraphicBuffer.USAGE_HW_TEXTURE;
-
- // This boolean is set to true if an atlas was successfully
- // computed and rendered
- private final AtomicBoolean mAtlasReady = new AtomicBoolean(false);
-
- private final Context mContext;
-
- // Version name of the current build, used to identify changes to assets list
- private final String mVersionName;
-
- // Holds the atlas' data. This buffer can be mapped to
- // OpenGL using an EGLImage
- private GraphicBuffer mBuffer;
-
- // Describes how bitmaps are placed in the atlas. Each bitmap is
- // represented by several entries in the array:
- // long0: SkBitmap*, the native bitmap object
- // long1: x position
- // long2: y position
- private long[] mAtlasMap;
-
- /**
- * Creates a new service. Upon creating, the service will gather the list of
- * assets to consider for packing into the atlas and spawn a new thread to
- * start the packing work.
- *
- * @param context The context giving access to preloaded resources
- */
- public AssetAtlasService(Context context) {
- mContext = context;
- mVersionName = queryVersionName(context);
-
- Collection<Bitmap> bitmaps = new HashSet<Bitmap>(300);
- int totalPixelCount = 0;
-
- // We only care about drawables that hold bitmaps
- final Resources resources = context.getResources();
- final LongSparseArray<Drawable.ConstantState> drawables = resources.getPreloadedDrawables();
-
- final int count = drawables.size();
- for (int i = 0; i < count; i++) {
- try {
- totalPixelCount += drawables.valueAt(i).addAtlasableBitmaps(bitmaps);
- } catch (Throwable t) {
- Log.e("AssetAtlas", "Failed to fetch preloaded drawable state", t);
- throw t;
- }
- }
-
- ArrayList<Bitmap> sortedBitmaps = new ArrayList<Bitmap>(bitmaps);
- // Our algorithms perform better when the bitmaps are first sorted
- // The comparator will sort the bitmap by width first, then by height
- Collections.sort(sortedBitmaps, new Comparator<Bitmap>() {
- @Override
- public int compare(Bitmap b1, Bitmap b2) {
- if (b1.getWidth() == b2.getWidth()) {
- return b2.getHeight() - b1.getHeight();
- }
- return b2.getWidth() - b1.getWidth();
- }
- });
-
- // Kick off the packing work on a worker thread
- new Thread(new Renderer(sortedBitmaps, totalPixelCount)).start();
- }
-
- /**
- * Queries the version name stored in framework's AndroidManifest.
- * The version name can be used to identify possible changes to
- * framework resources.
- *
- * @see #getBuildIdentifier(String)
- */
- private static String queryVersionName(Context context) {
- try {
- String packageName = context.getPackageName();
- PackageInfo info = context.getPackageManager().getPackageInfo(packageName,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
- return info.versionName;
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(LOG_TAG, "Could not get package info", e);
- }
- return null;
- }
-
- /**
- * Callback invoked by the server thread to indicate we can now run
- * 3rd party code.
- */
- public void systemRunning() {
- }
-
- /**
- * The renderer does all the work:
- */
- private class Renderer implements Runnable {
- private final ArrayList<Bitmap> mBitmaps;
- private final int mPixelCount;
-
- Renderer(ArrayList<Bitmap> bitmaps, int pixelCount) {
- mBitmaps = bitmaps;
- mPixelCount = pixelCount;
- }
-
- /**
- * 1. On first boot or after every update, brute-force through all the
- * possible atlas configurations and look for the best one (maximimize
- * number of packed assets and minimize texture size)
- * a. If a best configuration was computed, write it out to disk for
- * future use
- * 2. Read best configuration from disk
- * 3. Compute the packing using the best configuration
- * 4. Allocate a GraphicBuffer
- * 5. Render assets in the buffer
- */
- @Override
- public void run() {
- Configuration config = chooseConfiguration(mBitmaps, mPixelCount, mVersionName);
- if (DEBUG_ATLAS) Log.d(LOG_TAG, "Loaded configuration: " + config);
-
- if (config != null) {
- mBuffer = GraphicBuffer.create(config.width, config.height,
- PixelFormat.RGBA_8888, GRAPHIC_BUFFER_USAGE);
-
- if (mBuffer != null) {
- Atlas atlas = new Atlas(config.type, config.width, config.height, config.flags);
- if (renderAtlas(mBuffer, atlas, config.count)) {
- mAtlasReady.set(true);
- }
- }
- }
- }
-
- /**
- * Renders a list of bitmaps into the atlas. The position of each bitmap
- * was decided by the packing algorithm and will be honored by this
- * method.
- *
- * @param buffer The buffer to render the atlas entries into
- * @param atlas The atlas to pack the bitmaps into
- * @param packCount The number of bitmaps that will be packed in the atlas
- *
- * @return true if the atlas was rendered, false otherwise
- */
- @SuppressWarnings("MismatchedReadAndWriteOfArray")
- private boolean renderAtlas(GraphicBuffer buffer, Atlas atlas, int packCount) {
- // Use a Source blend mode to improve performance, the target bitmap
- // will be zero'd out so there's no need to waste time applying blending
- final Paint paint = new Paint();
- paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
-
- // We always render the atlas into a bitmap. This bitmap is then
- // uploaded into the GraphicBuffer using OpenGL to swizzle the content
- final Bitmap atlasBitmap = Bitmap.createBitmap(
- buffer.getWidth(), buffer.getHeight(), Bitmap.Config.ARGB_8888);
- final Canvas canvas = new Canvas(atlasBitmap);
-
- final Atlas.Entry entry = new Atlas.Entry();
-
- mAtlasMap = new long[packCount * ATLAS_MAP_ENTRY_FIELD_COUNT];
- long[] atlasMap = mAtlasMap;
- int mapIndex = 0;
-
- boolean result = false;
- final long startRender = System.nanoTime();
- final int count = mBitmaps.size();
-
- for (int i = 0; i < count; i++) {
- final Bitmap bitmap = mBitmaps.get(i);
- if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
- // We have more bitmaps to pack than the current configuration
- // says, we were most likely not able to detect a change in the
- // list of preloaded drawables, abort and delete the configuration
- if (mapIndex >= mAtlasMap.length) {
- deleteDataFile();
- break;
- }
-
- canvas.save();
- canvas.translate(entry.x, entry.y);
- canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
- canvas.restore();
- atlasMap[mapIndex++] = bitmap.refSkPixelRef();
- atlasMap[mapIndex++] = entry.x;
- atlasMap[mapIndex++] = entry.y;
- }
- }
-
- final long endRender = System.nanoTime();
- releaseCanvas(canvas, atlasBitmap);
- result = nUploadAtlas(buffer, atlasBitmap);
- atlasBitmap.recycle();
- final long endUpload = System.nanoTime();
-
- if (DEBUG_ATLAS) {
- float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f;
- float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f;
- Log.d(LOG_TAG, String.format("Rendered atlas in %.2fms (%.2f+%.2fms)",
- renderDuration + uploadDuration, renderDuration, uploadDuration));
- }
-
- return result;
- }
-
- /**
- * Releases the canvas used to render into the buffer. Calling this method
- * will release any resource previously acquired. If {@link #DEBUG_ATLAS_TEXTURE}
- * is turend on, calling this method will write the content of the atlas
- * to disk in /data/system/atlas.png for debugging.
- */
- private void releaseCanvas(Canvas canvas, Bitmap atlasBitmap) {
- canvas.setBitmap(null);
- if (DEBUG_ATLAS_TEXTURE) {
-
- File systemDirectory = new File(Environment.getDataDirectory(), "system");
- File dataFile = new File(systemDirectory, "atlas.png");
-
- try {
- FileOutputStream out = new FileOutputStream(dataFile);
- atlasBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
- out.close();
- } catch (FileNotFoundException e) {
- // Ignore
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- }
-
- private static native boolean nUploadAtlas(GraphicBuffer buffer, Bitmap bitmap);
-
- @Override
- public boolean isCompatible(int ppid) {
- return ppid == android.os.Process.myPpid();
- }
-
- @Override
- public GraphicBuffer getBuffer() throws RemoteException {
- return mAtlasReady.get() ? mBuffer : null;
- }
-
- @Override
- public long[] getMap() throws RemoteException {
- return mAtlasReady.get() ? mAtlasMap : null;
- }
-
- /**
- * Finds the best atlas configuration to pack the list of supplied bitmaps.
- * This method takes advantage of multi-core systems by spawning a number
- * of threads equal to the number of available cores.
- */
- private static Configuration computeBestConfiguration(
- ArrayList<Bitmap> bitmaps, int pixelCount) {
- if (DEBUG_ATLAS) Log.d(LOG_TAG, "Computing best atlas configuration...");
-
- long begin = System.nanoTime();
- List<WorkerResult> results = Collections.synchronizedList(new ArrayList<WorkerResult>());
-
- // Don't bother with an extra thread if there's only one processor
- int cpuCount = Runtime.getRuntime().availableProcessors();
- if (cpuCount == 1) {
- new ComputeWorker(MIN_SIZE, MAX_SIZE, STEP, bitmaps, pixelCount, results, null).run();
- } else {
- int start = MIN_SIZE + (cpuCount - 1) * STEP;
- int end = MAX_SIZE;
- int step = STEP * cpuCount;
-
- final CountDownLatch signal = new CountDownLatch(cpuCount);
-
- for (int i = 0; i < cpuCount; i++, start -= STEP, end -= STEP) {
- ComputeWorker worker = new ComputeWorker(start, end, step,
- bitmaps, pixelCount, results, signal);
- new Thread(worker, "Atlas Worker #" + (i + 1)).start();
- }
-
- boolean isAllWorkerFinished;
- try {
- isAllWorkerFinished = signal.await(10, TimeUnit.SECONDS);
- } catch (InterruptedException e) {
- Log.w(LOG_TAG, "Could not complete configuration computation");
- return null;
- }
-
- if (!isAllWorkerFinished) {
- // We have to abort here, otherwise the async updates on "results" would crash the
- // sort later.
- Log.w(LOG_TAG, "Could not complete configuration computation before timeout.");
- return null;
- }
- }
-
- // Maximize the number of packed bitmaps, minimize the texture size
- Collections.sort(results, new Comparator<WorkerResult>() {
- @Override
- public int compare(WorkerResult r1, WorkerResult r2) {
- int delta = r2.count - r1.count;
- if (delta != 0) return delta;
- return r1.width * r1.height - r2.width * r2.height;
- }
- });
-
- if (DEBUG_ATLAS) {
- float delay = (System.nanoTime() - begin) / 1000.0f / 1000.0f / 1000.0f;
- Log.d(LOG_TAG, String.format("Found best atlas configuration (out of %d) in %.2fs",
- results.size(), delay));
- }
-
- WorkerResult result = results.get(0);
- return new Configuration(result.type, result.width, result.height, result.count);
- }
-
- /**
- * Returns the path to the file containing the best computed
- * atlas configuration.
- */
- private static File getDataFile() {
- File systemDirectory = new File(Environment.getDataDirectory(), "system");
- return new File(systemDirectory, "framework_atlas.config");
- }
-
- private static void deleteDataFile() {
- Log.w(LOG_TAG, "Current configuration inconsistent with assets list");
- if (!getDataFile().delete()) {
- Log.w(LOG_TAG, "Could not delete the current configuration");
- }
- }
-
- private File getFrameworkResourcesFile() {
- return new File(mContext.getApplicationInfo().sourceDir);
- }
-
- /**
- * Returns the best known atlas configuration. This method will either
- * read the configuration from disk or start a brute-force search
- * and save the result out to disk.
- */
- private Configuration chooseConfiguration(ArrayList<Bitmap> bitmaps, int pixelCount,
- String versionName) {
- Configuration config = null;
-
- final File dataFile = getDataFile();
- if (dataFile.exists()) {
- config = readConfiguration(dataFile, versionName);
- }
-
- if (config == null) {
- config = computeBestConfiguration(bitmaps, pixelCount);
- if (config != null) writeConfiguration(config, dataFile, versionName);
- }
-
- return config;
- }
-
- /**
- * Writes the specified atlas configuration to the specified file.
- */
- private void writeConfiguration(Configuration config, File file, String versionName) {
- BufferedWriter writer = null;
- try {
- writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
- writer.write(getBuildIdentifier(versionName));
- writer.newLine();
- writer.write(config.type.toString());
- writer.newLine();
- writer.write(String.valueOf(config.width));
- writer.newLine();
- writer.write(String.valueOf(config.height));
- writer.newLine();
- writer.write(String.valueOf(config.count));
- writer.newLine();
- writer.write(String.valueOf(config.flags));
- writer.newLine();
- } catch (FileNotFoundException e) {
- Log.w(LOG_TAG, "Could not write " + file, e);
- } catch (IOException e) {
- Log.w(LOG_TAG, "Could not write " + file, e);
- } finally {
- if (writer != null) {
- try {
- writer.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- }
-
- /**
- * Reads an atlas configuration from the specified file. This method
- * returns null if an error occurs or if the configuration is invalid.
- */
- private Configuration readConfiguration(File file, String versionName) {
- BufferedReader reader = null;
- Configuration config = null;
- try {
- reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
-
- if (checkBuildIdentifier(reader, versionName)) {
- Atlas.Type type = Atlas.Type.valueOf(reader.readLine());
- int width = readInt(reader, MIN_SIZE, MAX_SIZE);
- int height = readInt(reader, MIN_SIZE, MAX_SIZE);
- int count = readInt(reader, 0, Integer.MAX_VALUE);
- int flags = readInt(reader, Integer.MIN_VALUE, Integer.MAX_VALUE);
-
- config = new Configuration(type, width, height, count, flags);
- }
- } catch (IllegalArgumentException e) {
- Log.w(LOG_TAG, "Invalid parameter value in " + file, e);
- } catch (FileNotFoundException e) {
- Log.w(LOG_TAG, "Could not read " + file, e);
- } catch (IOException e) {
- Log.w(LOG_TAG, "Could not read " + file, e);
- } finally {
- if (reader != null) {
- try {
- reader.close();
- } catch (IOException e) {
- // Ignore
- }
- }
- }
- return config;
- }
-
- private static int readInt(BufferedReader reader, int min, int max) throws IOException {
- return Math.max(min, Math.min(max, Integer.parseInt(reader.readLine())));
- }
-
- /**
- * Compares the next line in the specified buffered reader to the current
- * build identifier. Returns whether the two values are equal.
- *
- * @see #getBuildIdentifier(String)
- */
- private boolean checkBuildIdentifier(BufferedReader reader, String versionName)
- throws IOException {
- String deviceBuildId = getBuildIdentifier(versionName);
- String buildId = reader.readLine();
- return deviceBuildId.equals(buildId);
- }
-
- /**
- * Returns an identifier for the current build that can be used to detect
- * likely changes to framework resources. The build identifier is made of
- * several distinct values:
- *
- * build fingerprint/framework version name/file size of framework resources apk
- *
- * Only the build fingerprint should be necessary on user builds but
- * the other values are useful to detect changes on eng builds during
- * development.
- *
- * This identifier does not attempt to be exact: a new identifier does not
- * necessarily mean the preloaded drawables have changed. It is important
- * however that whenever the list of preloaded drawables changes, this
- * identifier changes as well.
- *
- * @see #checkBuildIdentifier(java.io.BufferedReader, String)
- */
- private String getBuildIdentifier(String versionName) {
- return SystemProperties.get("ro.build.fingerprint", "") + '/' + versionName + '/' +
- String.valueOf(getFrameworkResourcesFile().length());
- }
-
- /**
- * Atlas configuration. Specifies the algorithm, dimensions and flags to use.
- */
- private static class Configuration {
- final Atlas.Type type;
- final int width;
- final int height;
- final int count;
- final int flags;
-
- Configuration(Atlas.Type type, int width, int height, int count) {
- this(type, width, height, count, Atlas.FLAG_DEFAULTS);
- }
-
- Configuration(Atlas.Type type, int width, int height, int count, int flags) {
- this.type = type;
- this.width = width;
- this.height = height;
- this.count = count;
- this.flags = flags;
- }
-
- @Override
- public String toString() {
- return type.toString() + " (" + width + "x" + height + ") flags=0x" +
- Integer.toHexString(flags) + " count=" + count;
- }
- }
-
- /**
- * Used during the brute-force search to gather information about each
- * variant of the packing algorithm.
- */
- private static class WorkerResult {
- Atlas.Type type;
- int width;
- int height;
- int count;
-
- WorkerResult(Atlas.Type type, int width, int height, int count) {
- this.type = type;
- this.width = width;
- this.height = height;
- this.count = count;
- }
-
- @Override
- public String toString() {
- return String.format("%s %dx%d", type.toString(), width, height);
- }
- }
-
- /**
- * A compute worker will try a finite number of variations of the packing
- * algorithms and save the results in a supplied list.
- */
- private static class ComputeWorker implements Runnable {
- private final int mStart;
- private final int mEnd;
- private final int mStep;
- private final List<Bitmap> mBitmaps;
- private final List<WorkerResult> mResults;
- private final CountDownLatch mSignal;
- private final int mThreshold;
-
- /**
- * Creates a new compute worker to brute-force through a range of
- * packing algorithms variants.
- *
- * @param start The minimum texture width to try
- * @param end The maximum texture width to try
- * @param step The number of pixels to increment the texture width by at each step
- * @param bitmaps The list of bitmaps to pack in the atlas
- * @param pixelCount The total number of pixels occupied by the list of bitmaps
- * @param results The list of results in which to save the brute-force search results
- * @param signal Latch to decrement when this worker is done, may be null
- */
- ComputeWorker(int start, int end, int step, List<Bitmap> bitmaps, int pixelCount,
- List<WorkerResult> results, CountDownLatch signal) {
- mStart = start;
- mEnd = end;
- mStep = step;
- mBitmaps = bitmaps;
- mResults = results;
- mSignal = signal;
-
- // Minimum number of pixels we want to be able to pack
- int threshold = (int) (pixelCount * PACKING_THRESHOLD);
- // Make sure we can find at least one configuration
- while (threshold > MAX_SIZE * MAX_SIZE) {
- threshold >>= 1;
- }
- mThreshold = threshold;
- }
-
- @Override
- public void run() {
- if (DEBUG_ATLAS) Log.d(LOG_TAG, "Running " + Thread.currentThread().getName());
-
- Atlas.Entry entry = new Atlas.Entry();
-
- for (int width = mEnd; width > mStart; width -= mStep) {
- for (int height = MAX_SIZE; height > MIN_SIZE; height -= STEP) {
- // If the atlas is not big enough, skip it
- if (width * height <= mThreshold) continue;
-
- boolean packSuccess = false;
-
- for (Atlas.Type type : Atlas.Type.values()) {
- final int count = packBitmaps(type, width, height, entry);
- if (count > 0) {
- mResults.add(new WorkerResult(type, width, height, count));
- if (count == mBitmaps.size()) {
- // If we were able to pack everything let's stop here
- // Changing the type further won't make things better
- packSuccess = true;
- break;
- }
- }
- }
-
- // If we were not able to pack everything let's stop here
- // Decreasing the height further won't make things better
- if (!packSuccess) {
- break;
- }
- }
- }
-
- if (mSignal != null) {
- mSignal.countDown();
- }
- }
-
- private int packBitmaps(Atlas.Type type, int width, int height, Atlas.Entry entry) {
- int total = 0;
- Atlas atlas = new Atlas(type, width, height);
-
- final int count = mBitmaps.size();
- for (int i = 0; i < count; i++) {
- final Bitmap bitmap = mBitmaps.get(i);
- if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
- total++;
- }
- }
-
- return total;
- }
- }
-}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index fa2f6ac..ae60d1e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -78,6 +78,7 @@
import android.net.metrics.DefaultNetworkEvent;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
+import android.net.util.AvoidBadWifiTracker;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -403,11 +404,6 @@
private static final int EVENT_REQUEST_LINKPROPERTIES = 32;
private static final int EVENT_REQUEST_NETCAPABILITIES = 33;
- /**
- * Used internally to (re)configure avoid bad wifi setting.
- */
- private static final int EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI = 34;
-
/** Handler thread used for both of the handlers below. */
@VisibleForTesting
protected final HandlerThread mHandlerThread;
@@ -501,6 +497,9 @@
private final IpConnectivityLog mMetricsLog;
+ @VisibleForTesting
+ final AvoidBadWifiTracker mAvoidBadWifiTracker;
+
/**
* Implements support for the legacy "one network per network type" model.
*
@@ -863,14 +862,8 @@
LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
- intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- mHandler.sendEmptyMessage(EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI);
- }
- }, UserHandle.ALL, intentFilter, null, null);
- updateAvoidBadWifi();
+ mAvoidBadWifiTracker = createAvoidBadWifiTracker(
+ mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
}
private NetworkRequest createInternetRequestForTransport(
@@ -921,12 +914,6 @@
mSettingsObserver.observe(
Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON),
EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
-
- // Watch for whether to automatically switch away from wifi networks that lose Internet
- // access.
- mSettingsObserver.observe(
- Settings.Global.getUriFor(Settings.Global.NETWORK_AVOID_BAD_WIFI),
- EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI);
}
private synchronized int nextNetworkRequestId() {
@@ -2794,36 +2781,23 @@
PROMPT_UNVALIDATED_DELAY_MS);
}
- private boolean mAvoidBadWifi = true;
-
public boolean avoidBadWifi() {
- return mAvoidBadWifi;
+ return mAvoidBadWifiTracker.currentValue();
}
- @VisibleForTesting
- /** Whether the device or carrier configuration disables avoiding bad wifi by default. */
- public boolean configRestrictsAvoidBadWifi() {
- return mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi) == 0;
+ private void rematchForAvoidBadWifiUpdate() {
+ rematchAllNetworksAndRequests(null, 0);
+ for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) {
+ if (nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ sendUpdatedScoreToFactories(nai);
+ }
+ }
}
- /** Whether we should display a notification when wifi becomes unvalidated. */
- public boolean shouldNotifyWifiUnvalidated() {
- return configRestrictsAvoidBadWifi() &&
- Settings.Global.getString(mContext.getContentResolver(),
- Settings.Global.NETWORK_AVOID_BAD_WIFI) == null;
- }
-
- private boolean updateAvoidBadWifi() {
- boolean settingAvoidBadWifi = "1".equals(Settings.Global.getString(
- mContext.getContentResolver(), Settings.Global.NETWORK_AVOID_BAD_WIFI));
-
- boolean prev = mAvoidBadWifi;
- mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
- return mAvoidBadWifi != prev;
- }
-
+ // TODO: Evaluate whether this is of interest to other consumers of
+ // AvoidBadWifiTracker and worth moving out of here.
private void dumpAvoidBadWifiSettings(IndentingPrintWriter pw) {
- boolean configRestrict = configRestrictsAvoidBadWifi();
+ final boolean configRestrict = mAvoidBadWifiTracker.configRestrictsAvoidBadWifi();
if (!configRestrict) {
pw.println("Bad Wi-Fi avoidance: unrestricted");
return;
@@ -2833,8 +2807,7 @@
pw.increaseIndent();
pw.println("Config restrict: " + configRestrict);
- String value = Settings.Global.getString(
- mContext.getContentResolver(), Settings.Global.NETWORK_AVOID_BAD_WIFI);
+ final String value = mAvoidBadWifiTracker.getSettingsValue();
String description;
// Can't use a switch statement because strings are legal case labels, but null is not.
if ("0".equals(value)) {
@@ -2897,17 +2870,12 @@
showValidationNotification(nai, NotificationType.NO_INTERNET);
}
- // TODO: Delete this like updateMobileDataAlwaysOn above.
- @VisibleForTesting
- void updateNetworkAvoidBadWifi() {
- mHandler.sendEmptyMessage(EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI);
- }
-
private void handleNetworkUnvalidated(NetworkAgentInfo nai) {
NetworkCapabilities nc = nai.networkCapabilities;
if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
- if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && shouldNotifyWifiUnvalidated()) {
+ if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
+ mAvoidBadWifiTracker.shouldNotifyWifiUnvalidated()) {
showValidationNotification(nai, NotificationType.LOST_INTERNET);
}
}
@@ -3002,18 +2970,6 @@
handleMobileDataAlwaysOn();
break;
}
- case EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI: {
- if (updateAvoidBadWifi()) {
- rematchAllNetworksAndRequests(null, 0);
- for (NetworkAgentInfo nai: mNetworkAgentInfos.values()) {
- if (nai.networkCapabilities.hasTransport(
- NetworkCapabilities.TRANSPORT_WIFI)) {
- sendUpdatedScoreToFactories(nai);
- }
- }
- }
- break;
- }
case EVENT_REQUEST_LINKPROPERTIES:
handleRequestLinkProperties((NetworkRequest) msg.obj, msg.arg1);
break;
@@ -5577,6 +5533,11 @@
}
@VisibleForTesting
+ AvoidBadWifiTracker createAvoidBadWifiTracker(Context c, Handler h, Runnable r) {
+ return new AvoidBadWifiTracker(c, h, r);
+ }
+
+ @VisibleForTesting
public WakeupMessage makeWakeupMessage(Context c, Handler h, String s, int cmd, Object obj) {
return new WakeupMessage(c, h, s, cmd, 0, 0, obj);
}
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index dbc1f31..466633a 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -2726,12 +2726,12 @@
}
}
} else if ("whitelist".equals(cmd)) {
- long token = Binder.clearCallingIdentity();
- try {
- String arg = shell.getNextArg();
- if (arg != null) {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.DEVICE_POWER, null);
+ String arg = shell.getNextArg();
+ if (arg != null) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.DEVICE_POWER, null);
+ long token = Binder.clearCallingIdentity();
+ try {
do {
if (arg.length() < 1 || (arg.charAt(0) != '-'
&& arg.charAt(0) != '+' && arg.charAt(0) != '=')) {
@@ -2754,30 +2754,30 @@
pw.println(getPowerSaveWhitelistAppInternal(pkg));
}
} while ((arg=shell.getNextArg()) != null);
- } else {
- synchronized (this) {
- for (int j=0; j<mPowerSaveWhitelistAppsExceptIdle.size(); j++) {
- pw.print("system-excidle,");
- pw.print(mPowerSaveWhitelistAppsExceptIdle.keyAt(j));
- pw.print(",");
- pw.println(mPowerSaveWhitelistAppsExceptIdle.valueAt(j));
- }
- for (int j=0; j<mPowerSaveWhitelistApps.size(); j++) {
- pw.print("system,");
- pw.print(mPowerSaveWhitelistApps.keyAt(j));
- pw.print(",");
- pw.println(mPowerSaveWhitelistApps.valueAt(j));
- }
- for (int j=0; j<mPowerSaveWhitelistUserApps.size(); j++) {
- pw.print("user,");
- pw.print(mPowerSaveWhitelistUserApps.keyAt(j));
- pw.print(",");
- pw.println(mPowerSaveWhitelistUserApps.valueAt(j));
- }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ } else {
+ synchronized (this) {
+ for (int j=0; j<mPowerSaveWhitelistAppsExceptIdle.size(); j++) {
+ pw.print("system-excidle,");
+ pw.print(mPowerSaveWhitelistAppsExceptIdle.keyAt(j));
+ pw.print(",");
+ pw.println(mPowerSaveWhitelistAppsExceptIdle.valueAt(j));
+ }
+ for (int j=0; j<mPowerSaveWhitelistApps.size(); j++) {
+ pw.print("system,");
+ pw.print(mPowerSaveWhitelistApps.keyAt(j));
+ pw.print(",");
+ pw.println(mPowerSaveWhitelistApps.valueAt(j));
+ }
+ for (int j=0; j<mPowerSaveWhitelistUserApps.size(); j++) {
+ pw.print("user,");
+ pw.print(mPowerSaveWhitelistUserApps.keyAt(j));
+ pw.print(",");
+ pw.println(mPowerSaveWhitelistUserApps.valueAt(j));
}
}
- } finally {
- Binder.restoreCallingIdentity(token);
}
} else if ("tempwhitelist".equals(cmd)) {
String opt;
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 8f16504..e64aa16 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -77,6 +77,7 @@
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.provider.Settings;
import android.telephony.DataConnectionRealTimeInfo;
import android.telephony.PhoneStateListener;
@@ -1699,6 +1700,7 @@
return;
}
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "inetd bandwidth");
try {
mConnector.execute("bandwidth", suffix + chain, uid);
if (enable) {
@@ -1708,6 +1710,8 @@
}
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
}
}
@@ -1730,6 +1734,7 @@
Log.w(TAG, "setDataSaverMode(): already " + mDataSaverMode);
return true;
}
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "bandwidthEnableDataSaver");
try {
final boolean changed = mNetdService.bandwidthEnableDataSaver(enable);
if (changed) {
@@ -1741,6 +1746,8 @@
} catch (RemoteException e) {
Log.w(TAG, "setDataSaverMode(" + enable + "): netd command failed", e);
return false;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
}
}
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
index 276687f..3c8c699 100644
--- a/services/core/java/com/android/server/RecoverySystemService.java
+++ b/services/core/java/com/android/server/RecoverySystemService.java
@@ -21,6 +21,7 @@
import android.net.LocalSocketAddress;
import android.os.IRecoverySystem;
import android.os.IRecoverySystemProgressListener;
+import android.os.PowerManager;
import android.os.RecoverySystem;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -50,8 +51,15 @@
// The socket at /dev/socket/uncrypt to communicate with uncrypt.
private static final String UNCRYPT_SOCKET = "uncrypt";
+ // The init services that communicate with /system/bin/uncrypt.
+ private static final String INIT_SERVICE_UNCRYPT = "init.svc.uncrypt";
+ private static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb";
+ private static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb";
+
private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
+ private static final Object sRequestLock = new Object();
+
private Context mContext;
public RecoverySystemService(Context context) {
@@ -69,95 +77,155 @@
public boolean uncrypt(String filename, IRecoverySystemProgressListener listener) {
if (DEBUG) Slog.d(TAG, "uncrypt: " + filename);
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+ synchronized (sRequestLock) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
- // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
- // uncrypt.
- RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
-
- try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
- uncryptFile.write(filename + "\n");
- } catch (IOException e) {
- Slog.e(TAG, "IOException when writing \"" + RecoverySystem.UNCRYPT_PACKAGE_FILE +
- "\": ", e);
- return false;
- }
-
- // Trigger uncrypt via init.
- SystemProperties.set("ctl.start", "uncrypt");
-
- // Connect to the uncrypt service socket.
- LocalSocket socket = connectService();
- if (socket == null) {
- Slog.e(TAG, "Failed to connect to uncrypt socket");
- return false;
- }
-
- // Read the status from the socket.
- DataInputStream dis = null;
- DataOutputStream dos = null;
- try {
- dis = new DataInputStream(socket.getInputStream());
- dos = new DataOutputStream(socket.getOutputStream());
- int lastStatus = Integer.MIN_VALUE;
- while (true) {
- int status = dis.readInt();
- // Avoid flooding the log with the same message.
- if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
- continue;
- }
- lastStatus = status;
-
- if (status >= 0 && status <= 100) {
- // Update status
- Slog.i(TAG, "uncrypt read status: " + status);
- if (listener != null) {
- try {
- listener.onProgress(status);
- } catch (RemoteException ignored) {
- Slog.w(TAG, "RemoteException when posting progress");
- }
- }
- if (status == 100) {
- Slog.i(TAG, "uncrypt successfully finished.");
- // Ack receipt of the final status code. uncrypt
- // waits for the ack so the socket won't be
- // destroyed before we receive the code.
- dos.writeInt(0);
- break;
- }
- } else {
- // Error in /system/bin/uncrypt.
- Slog.e(TAG, "uncrypt failed with status: " + status);
- // Ack receipt of the final status code. uncrypt waits
- // for the ack so the socket won't be destroyed before
- // we receive the code.
- dos.writeInt(0);
- return false;
- }
+ final boolean available = checkAndWaitForUncryptService();
+ if (!available) {
+ Slog.e(TAG, "uncrypt service is unavailable.");
+ return false;
}
- } catch (IOException e) {
- Slog.e(TAG, "IOException when reading status: ", e);
- return false;
- } finally {
- IoUtils.closeQuietly(dis);
- IoUtils.closeQuietly(dos);
- IoUtils.closeQuietly(socket);
- }
- return true;
+ // Write the filename into UNCRYPT_PACKAGE_FILE to be read by
+ // uncrypt.
+ RecoverySystem.UNCRYPT_PACKAGE_FILE.delete();
+
+ try (FileWriter uncryptFile = new FileWriter(RecoverySystem.UNCRYPT_PACKAGE_FILE)) {
+ uncryptFile.write(filename + "\n");
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when writing \"" +
+ RecoverySystem.UNCRYPT_PACKAGE_FILE + "\":", e);
+ return false;
+ }
+
+ // Trigger uncrypt via init.
+ SystemProperties.set("ctl.start", "uncrypt");
+
+ // Connect to the uncrypt service socket.
+ LocalSocket socket = connectService();
+ if (socket == null) {
+ Slog.e(TAG, "Failed to connect to uncrypt socket");
+ return false;
+ }
+
+ // Read the status from the socket.
+ DataInputStream dis = null;
+ DataOutputStream dos = null;
+ try {
+ dis = new DataInputStream(socket.getInputStream());
+ dos = new DataOutputStream(socket.getOutputStream());
+ int lastStatus = Integer.MIN_VALUE;
+ while (true) {
+ int status = dis.readInt();
+ // Avoid flooding the log with the same message.
+ if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
+ continue;
+ }
+ lastStatus = status;
+
+ if (status >= 0 && status <= 100) {
+ // Update status
+ Slog.i(TAG, "uncrypt read status: " + status);
+ if (listener != null) {
+ try {
+ listener.onProgress(status);
+ } catch (RemoteException ignored) {
+ Slog.w(TAG, "RemoteException when posting progress");
+ }
+ }
+ if (status == 100) {
+ Slog.i(TAG, "uncrypt successfully finished.");
+ // Ack receipt of the final status code. uncrypt
+ // waits for the ack so the socket won't be
+ // destroyed before we receive the code.
+ dos.writeInt(0);
+ break;
+ }
+ } else {
+ // Error in /system/bin/uncrypt.
+ Slog.e(TAG, "uncrypt failed with status: " + status);
+ // Ack receipt of the final status code. uncrypt waits
+ // for the ack so the socket won't be destroyed before
+ // we receive the code.
+ dos.writeInt(0);
+ return false;
+ }
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "IOException when reading status: ", e);
+ return false;
+ } finally {
+ IoUtils.closeQuietly(dis);
+ IoUtils.closeQuietly(dos);
+ IoUtils.closeQuietly(socket);
+ }
+
+ return true;
+ }
}
@Override // Binder call
public boolean clearBcb() {
if (DEBUG) Slog.d(TAG, "clearBcb");
- return setupOrClearBcb(false, null);
+ synchronized (sRequestLock) {
+ return setupOrClearBcb(false, null);
+ }
}
@Override // Binder call
public boolean setupBcb(String command) {
if (DEBUG) Slog.d(TAG, "setupBcb: [" + command + "]");
- return setupOrClearBcb(true, command);
+ synchronized (sRequestLock) {
+ return setupOrClearBcb(true, command);
+ }
+ }
+
+ @Override // Binder call
+ public void rebootRecoveryWithCommand(String command) {
+ if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
+ synchronized (sRequestLock) {
+ if (!setupOrClearBcb(true, command)) {
+ return;
+ }
+
+ // Having set up the BCB, go ahead and reboot.
+ PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ pm.reboot(PowerManager.REBOOT_RECOVERY);
+ }
+ }
+
+ /**
+ * Check if any of the init services is still running. If so, we cannot
+ * start a new uncrypt/setup-bcb/clear-bcb service right away; otherwise
+ * it may break the socket communication since init creates / deletes
+ * the socket (/dev/socket/uncrypt) on service start / exit.
+ */
+ private boolean checkAndWaitForUncryptService() {
+ for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+ final String uncryptService = SystemProperties.get(INIT_SERVICE_UNCRYPT);
+ final String setupBcbService = SystemProperties.get(INIT_SERVICE_SETUP_BCB);
+ final String clearBcbService = SystemProperties.get(INIT_SERVICE_CLEAR_BCB);
+ final boolean busy = "running".equals(uncryptService) ||
+ "running".equals(setupBcbService) || "running".equals(clearBcbService);
+ if (DEBUG) {
+ Slog.i(TAG, "retry: " + retry + " busy: " + busy +
+ " uncrypt: [" + uncryptService + "]" +
+ " setupBcb: [" + setupBcbService + "]" +
+ " clearBcb: [" + clearBcbService + "]");
+ }
+
+ if (!busy) {
+ return true;
+ }
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ Slog.w(TAG, "Interrupted:", e);
+ }
+ }
+
+ return false;
}
private LocalSocket connectService() {
@@ -176,7 +244,7 @@
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
- Slog.w(TAG, "Interrupted: ", e);
+ Slog.w(TAG, "Interrupted:", e);
}
}
}
@@ -190,6 +258,12 @@
private boolean setupOrClearBcb(boolean isSetup, String command) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+ final boolean available = checkAndWaitForUncryptService();
+ if (!available) {
+ Slog.e(TAG, "uncrypt service is unavailable.");
+ return false;
+ }
+
if (isSetup) {
SystemProperties.set("ctl.start", "setup-bcb");
} else {
@@ -232,7 +306,7 @@
return false;
}
} catch (IOException e) {
- Slog.e(TAG, "IOException when communicating with uncrypt: ", e);
+ Slog.e(TAG, "IOException when communicating with uncrypt:", e);
return false;
} finally {
IoUtils.closeQuietly(dis);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
index 63afccc..c3b7e15 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerBackupHelper.java
@@ -142,9 +142,8 @@
final AccountManagerService.UserAccounts accounts = mAccountManagerService
.getUserAccounts(userId);
synchronized (accounts.cacheLock) {
- SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- List<Pair<String, Integer>> allAccountGrants = DeDatabaseHelper.findAllAccountGrants(
- db);
+ List<Pair<String, Integer>> allAccountGrants = accounts.accountsDb
+ .findAllAccountGrants();
if (allAccountGrants.isEmpty()) {
return null;
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 575018d..7802576 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -98,9 +98,6 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
-import com.android.server.accounts.AccountsDb.CeDatabaseHelper;
-import com.android.server.accounts.AccountsDb.DeDatabaseHelper;
-import com.android.server.accounts.AccountsDb.DebugDbHelper;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
@@ -161,8 +158,6 @@
}
}
- private static final int MAX_DEBUG_DB_SIZE = 64;
-
final Context mContext;
private final PackageManager mPackageManager;
@@ -193,7 +188,7 @@
static class UserAccounts {
private final int userId;
- final DeDatabaseHelper openHelper;
+ final AccountsDb accountsDb;
private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
credentialsPermissionNotificationIds =
new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
@@ -242,12 +237,12 @@
new HashMap<Account, AtomicReference<String>>();
private int debugDbInsertionPoint = -1;
- private SQLiteStatement statementForLogging;
+ private SQLiteStatement statementForLogging; // TODO Move to AccountsDb
UserAccounts(Context context, int userId, File preNDbFile, File deDbFile) {
this.userId = userId;
synchronized (cacheLock) {
- openHelper = DeDatabaseHelper.create(context, userId, preNDbFile, deDbFile);
+ accountsDb = AccountsDb.create(context, userId, preNDbFile, deDbFile);
}
}
}
@@ -993,7 +988,7 @@
UserAccounts accounts, boolean invalidateAuthenticatorCache) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "validateAccountsInternal " + accounts.userId
- + " isCeDatabaseAttached=" + accounts.openHelper.isCeDatabaseAttached()
+ + " isCeDatabaseAttached=" + accounts.accountsDb.isCeDatabaseAttached()
+ " userLocked=" + mLocalUnlockedUsers.get(accounts.userId));
}
@@ -1006,11 +1001,11 @@
boolean userUnlocked = isLocalUnlockedUser(accounts.userId);
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
boolean accountDeleted = false;
// Get a map of stored authenticator types to UID
- Map<String, Integer> metaAuthUid = DeDatabaseHelper.findMetaAuthUid(db);
+ final AccountsDb accountsDb = accounts.accountsDb;
+ Map<String, Integer> metaAuthUid = accountsDb.findMetaAuthUid();
// Create a list of authenticator type whose previous uid no longer exists
HashSet<String> obsoleteAuthType = Sets.newHashSet();
SparseBooleanArray knownUids = null;
@@ -1047,7 +1042,7 @@
// So purge its data from the account databases.
obsoleteAuthType.add(type);
// And delete it from the TABLE_META
- DeDatabaseHelper.deleteMetaByAuthTypeAndUid(db, type, uid);
+ accountsDb.deleteMetaByAuthTypeAndUid(type, uid);
}
}
}
@@ -1056,11 +1051,10 @@
// been re-enabled (after being updated for example), then we just overwrite the old
// values.
for (Entry<String, Integer> entry : knownAuth.entrySet()) {
- DeDatabaseHelper.insertOrReplaceMetaAuthTypeAndUid(db, entry.getKey(),
- entry.getValue());
+ accountsDb.insertOrReplaceMetaAuthTypeAndUid(entry.getKey(), entry.getValue());
}
- final Map<Long, Account> accountsMap = DeDatabaseHelper.findAllAccounts(db);
+ final Map<Long, Account> accountsMap = accountsDb.findAllDeAccounts();
try {
accounts.accountCache.clear();
final HashMap<String, ArrayList<String>> accountNamesByType = new LinkedHashMap<>();
@@ -1070,17 +1064,17 @@
if (obsoleteAuthType.contains(account.type)) {
Slog.w(TAG, "deleting account " + account.name + " because type "
+ account.type + "'s registered authenticator no longer exist.");
- db.beginTransaction();
+ accountsDb.beginTransaction();
try {
- DeDatabaseHelper.deleteAccount(db, accountId);
+ accountsDb.deleteDeAccount(accountId);
// Also delete from CE table if user is unlocked; if user is currently
// locked the account will be removed later by syncDeCeAccountsLocked
if (userUnlocked) {
- AccountsDb.deleteCeAccount(db, accountId);
+ accountsDb.deleteCeAccount(accountId);
}
- db.setTransactionSuccessful();
+ accountsDb.setTransactionSuccessful();
} finally {
- db.endTransaction();
+ accountsDb.endTransaction();
}
accountDeleted = true;
@@ -1163,20 +1157,17 @@
File preNDbFile = new File(mInjector.getPreNDatabaseName(userId));
File deDbFile = new File(mInjector.getDeDatabaseName(userId));
accounts = new UserAccounts(mContext, userId, preNDbFile, deDbFile);
- initializeDebugDbSizeAndCompileSqlStatementForLogging(
- accounts.openHelper.getWritableDatabase(), accounts);
+ initializeDebugDbSizeAndCompileSqlStatementForLogging(accounts);
mUsers.append(userId, accounts);
purgeOldGrants(accounts);
validateAccounts = true;
}
// open CE database if necessary
- if (!accounts.openHelper.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
+ if (!accounts.accountsDb.isCeDatabaseAttached() && mLocalUnlockedUsers.get(userId)) {
Log.i(TAG, "User " + userId + " is unlocked - opening CE database");
synchronized (accounts.cacheLock) {
- File preNDatabaseFile = new File(mInjector.getPreNDatabaseName(userId));
File ceDatabaseFile = new File(mInjector.getCeDatabaseName(userId));
- CeDatabaseHelper.create(mContext, userId, preNDatabaseFile, ceDatabaseFile);
- accounts.openHelper.attachCeDatabase(ceDatabaseFile);
+ accounts.accountsDb.attachCeDatabase(ceDatabaseFile);
}
syncDeCeAccountsLocked(accounts);
}
@@ -1189,8 +1180,7 @@
private void syncDeCeAccountsLocked(UserAccounts accounts) {
Preconditions.checkState(Thread.holdsLock(mUsers), "mUsers lock must be held");
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
- List<Account> accountsToRemove = AccountsDb.findCeAccountsNotInDe(db);
+ List<Account> accountsToRemove = accounts.accountsDb.findCeAccountsNotInDe();
if (!accountsToRemove.isEmpty()) {
Slog.i(TAG, "Accounts " + accountsToRemove + " were previously deleted while user "
+ accounts.userId + " was locked. Removing accounts from CE tables");
@@ -1213,8 +1203,7 @@
private void purgeOldGrants(UserAccounts accounts) {
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- List<Integer> uids = DeDatabaseHelper.findAllUidGrants(db);
+ List<Integer> uids = accounts.accountsDb.findAllUidGrants();
for (int uid : uids) {
final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
if (packageExists) {
@@ -1222,7 +1211,7 @@
}
Log.d(TAG, "deleting grants for UID " + uid
+ " because its package is no longer installed");
- DeDatabaseHelper.deleteGrantsByUid(db, uid);
+ accounts.accountsDb.deleteGrantsByUid(uid);
}
}
}
@@ -1241,7 +1230,7 @@
}
if (accounts != null) {
synchronized (accounts.cacheLock) {
- accounts.openHelper.close();
+ accounts.accountsDb.close();
}
}
Log.i(TAG, "Removing database files for user " + userId);
@@ -1334,9 +1323,7 @@
}
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
- return CeDatabaseHelper.findAccountPasswordByNameAndType(db, account.name,
- account.type);
+ return accounts.accountsDb.findAccountPasswordByNameAndType(account.name, account.type);
}
}
@@ -1365,8 +1352,7 @@
synchronized (accounts.cacheLock) {
AtomicReference<String> previousNameRef = accounts.previousNameCache.get(account);
if (previousNameRef == null) {
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- String previousName = DeDatabaseHelper.findAccountPreviousName(db, account);
+ String previousName = accounts.accountsDb.findDeAccountPreviousName(account);
previousNameRef = new AtomicReference<>(previousName);
accounts.previousNameCache.put(account, previousNameRef);
return previousName;
@@ -1602,8 +1588,7 @@
private boolean updateLastAuthenticatedTime(Account account) {
final UserAccounts accounts = getUserAccountsForCaller();
synchronized (accounts.cacheLock) {
- return DeDatabaseHelper.updateAccountLastAuthenticatedTime(
- accounts.openHelper.getWritableDatabase(), account);
+ return accounts.accountsDb.updateAccountLastAuthenticatedTime(account);
}
}
@@ -1672,22 +1657,21 @@
return false;
}
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
- db.beginTransaction();
+ accounts.accountsDb.beginTransaction();
try {
- if (CeDatabaseHelper.findAccountId(db, account) >= 0) {
+ if (accounts.accountsDb.findCeAccountId(account) >= 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping since the account already exists");
return false;
}
- long accountId = CeDatabaseHelper.insertAccount(db, account, password);
+ long accountId = accounts.accountsDb.insertCeAccount(account, password);
if (accountId < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping the DB insert failed");
return false;
}
// Insert into DE table
- if (DeDatabaseHelper.insertAccount(db, account, accountId) < 0) {
+ if (accounts.accountsDb.insertDeAccount(account, accountId) < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping the DB insert failed");
return false;
@@ -1695,21 +1679,21 @@
if (extras != null) {
for (String key : extras.keySet()) {
final String value = extras.getString(key);
- if (CeDatabaseHelper.insertExtra(db, accountId, key, value) < 0) {
+ if (accounts.accountsDb.insertExtra(accountId, key, value) < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping since insertExtra failed for key " + key);
return false;
}
}
}
- db.setTransactionSuccessful();
+ accounts.accountsDb.setTransactionSuccessful();
logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_ADD, AccountsDb.TABLE_ACCOUNTS,
accountId, accounts, callingUid);
insertAccountIntoCacheLocked(accounts, account);
} finally {
- db.endTransaction();
+ accounts.accountsDb.endTransaction();
}
}
if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
@@ -1892,17 +1876,16 @@
}
}
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
- db.beginTransaction();
+ accounts.accountsDb.beginTransaction();
Account renamedAccount = new Account(newName, accountToRename.type);
try {
- final long accountId = DeDatabaseHelper.findAccountId(db, accountToRename);
+ final long accountId = accounts.accountsDb.findDeAccountId(accountToRename);
if (accountId >= 0) {
- CeDatabaseHelper.renameAccount(db, accountId, newName);
- DeDatabaseHelper.renameAccount(db, accountId, newName, accountToRename.name);
+ accounts.accountsDb.renameCeAccount(accountId, newName);
+ accounts.accountsDb.renameDeAccount(accountId, newName, accountToRename.name);
}
} finally {
- db.endTransaction();
+ accounts.accountsDb.endTransaction();
}
/*
* Database transaction was successful. Clean up cached
@@ -2025,8 +2008,7 @@
}
}
}
- SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- final long accountId = DeDatabaseHelper.findAccountId(db, account);
+ final long accountId = accounts.accountsDb.findDeAccountId(account);
logRecord(
AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
AccountsDb.TABLE_ACCOUNTS,
@@ -2065,8 +2047,7 @@
}
removeVisibleListFunctionality(account, getUserAccounts(UserHandle.getUserId(callingUid)));
UserAccounts accounts = getUserAccountsForCaller();
- SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
- final long accountId = DeDatabaseHelper.findAccountId(db, account);
+ final long accountId = accounts.accountsDb.findDeAccountId(account);
logRecord(
AccountsDb.DEBUG_ACTION_CALLED_ACCOUNT_REMOVE,
AccountsDb.TABLE_ACCOUNTS,
@@ -2143,26 +2124,23 @@
+ " is still locked. CE data will be removed later");
}
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = userUnlocked
- ? accounts.openHelper.getWritableDatabaseUserIsUnlocked()
- : accounts.openHelper.getWritableDatabase();
- db.beginTransaction();
+ accounts.accountsDb.beginTransaction();
// Set to a dummy value, this will only be used if the database
// transaction succeeds.
long accountId = -1;
try {
- accountId = DeDatabaseHelper.findAccountId(db, account);
+ accountId = accounts.accountsDb.findDeAccountId(account);
if (accountId >= 0) {
- DeDatabaseHelper.deleteAccount(db, accountId);
+ accounts.accountsDb.deleteDeAccount(accountId);
if (userUnlocked) {
// Delete from CE table
- AccountsDb.deleteCeAccount(db, accountId);
+ accounts.accountsDb.deleteCeAccount(accountId);
}
- db.setTransactionSuccessful();
+ accounts.accountsDb.setTransactionSuccessful();
isChanged = true;
}
} finally {
- db.endTransaction();
+ accounts.accountsDb.endTransaction();
}
if (isChanged) {
removeAccountFromCacheLocked(accounts, account);
@@ -2221,14 +2199,13 @@
try {
UserAccounts accounts = getUserAccounts(userId);
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
- db.beginTransaction();
+ accounts.accountsDb.beginTransaction();
try {
- invalidateAuthTokenLocked(accounts, db, accountType, authToken);
+ invalidateAuthTokenLocked(accounts, accountType, authToken);
invalidateCustomTokenLocked(accounts, accountType, authToken);
- db.setTransactionSuccessful();
+ accounts.accountsDb.setTransactionSuccessful();
} finally {
- db.endTransaction();
+ accounts.accountsDb.endTransaction();
}
}
} finally {
@@ -2247,21 +2224,20 @@
accounts.accountTokenCaches.remove(accountType, authToken);
}
- private void invalidateAuthTokenLocked(UserAccounts accounts, SQLiteDatabase db,
- String accountType, String authToken) {
+ private void invalidateAuthTokenLocked(UserAccounts accounts, String accountType,
+ String authToken) {
if (authToken == null || accountType == null) {
return;
}
- Cursor cursor = CeDatabaseHelper.findAuthtokenForAllAccounts(db, accountType, authToken);
+ Cursor cursor = accounts.accountsDb.findAuthtokenForAllAccounts(accountType, authToken);
try {
while (cursor.moveToNext()) {
String authTokenId = cursor.getString(0);
String accountName = cursor.getString(1);
String authTokenType = cursor.getString(2);
- CeDatabaseHelper.deleteAuthToken(db, authTokenId);
+ accounts.accountsDb.deleteAuthToken(authTokenId);
writeAuthTokenIntoCacheLocked(
accounts,
- db,
new Account(accountName, accountType),
authTokenType,
null);
@@ -2299,22 +2275,21 @@
cancelNotification(getSigninRequiredNotificationId(accounts, account),
UserHandle.of(accounts.userId));
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
- db.beginTransaction();
+ accounts.accountsDb.beginTransaction();
try {
- long accountId = DeDatabaseHelper.findAccountId(db, account);
+ long accountId = accounts.accountsDb.findDeAccountId(account);
if (accountId < 0) {
return false;
}
- CeDatabaseHelper.deleteAuthtokensByAccountIdAndType(db, accountId, type);
- if (CeDatabaseHelper.insertAuthToken(db, accountId, type, authToken) >= 0) {
- db.setTransactionSuccessful();
- writeAuthTokenIntoCacheLocked(accounts, db, account, type, authToken);
+ accounts.accountsDb.deleteAuthtokensByAccountIdAndType(accountId, type);
+ if (accounts.accountsDb.insertAuthToken(accountId, type, authToken) >= 0) {
+ accounts.accountsDb.setTransactionSuccessful();
+ writeAuthTokenIntoCacheLocked(accounts, account, type, authToken);
return true;
}
return false;
} finally {
- db.endTransaction();
+ accounts.accountsDb.endTransaction();
}
}
}
@@ -2413,16 +2388,15 @@
}
boolean isChanged = false;
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabaseUserIsUnlocked();
- db.beginTransaction();
+ accounts.accountsDb.beginTransaction();
try {
- final long accountId = DeDatabaseHelper.findAccountId(db, account);
+ final long accountId = accounts.accountsDb.findDeAccountId(account);
if (accountId >= 0) {
- CeDatabaseHelper.updateAccountPassword(db, accountId, password);
- CeDatabaseHelper.deleteAuthTokensByAccountId(db, accountId);
+ accounts.accountsDb.updateCeAccountPassword(accountId, password);
+ accounts.accountsDb.deleteAuthTokensByAccountId(accountId);
accounts.authTokenCache.remove(account);
accounts.accountTokenCaches.remove(account);
- db.setTransactionSuccessful();
+ accounts.accountsDb.setTransactionSuccessful();
// If there is an account whose password will be updated and the database
// transactions succeed, then we say that a change has occured. Even if the
// new password is the same as the old and there were no authtokens to delete.
@@ -2433,7 +2407,7 @@
logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts, callingUid);
}
} finally {
- db.endTransaction();
+ accounts.accountsDb.endTransaction();
if (isChanged) {
// Send LOGIN_ACCOUNTS_CHANGED only if the something changed.
sendAccountsChangedBroadcast(accounts.userId);
@@ -2523,26 +2497,25 @@
if (account == null || key == null) {
return;
}
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- db.beginTransaction();
+ accounts.accountsDb.beginTransaction();
try {
- long accountId = DeDatabaseHelper.findAccountId(db, account);
+ long accountId = accounts.accountsDb.findDeAccountId(account);
if (accountId < 0) {
return;
}
- long extrasId = CeDatabaseHelper.findExtrasIdByAccountId(db, accountId, key);
+ long extrasId = accounts.accountsDb.findExtrasIdByAccountId(accountId, key);
if (extrasId < 0) {
- extrasId = CeDatabaseHelper.insertExtra(db, accountId, key, value);
+ extrasId = accounts.accountsDb.insertExtra(accountId, key, value);
if (extrasId < 0) {
return;
}
- } else if (!CeDatabaseHelper.updateExtra(db, extrasId, value)) {
+ } else if (!accounts.accountsDb.updateExtra(extrasId, value)) {
return;
}
- writeUserDataIntoCacheLocked(accounts, db, account, key, value);
- db.setTransactionSuccessful();
+ writeUserDataIntoCacheLocked(accounts, account, key, value);
+ accounts.accountsDb.setTransactionSuccessful();
} finally {
- db.endTransaction();
+ accounts.accountsDb.endTransaction();
}
}
@@ -4171,9 +4144,8 @@
private boolean addSharedAccountAsUser(Account account, int userId) {
userId = handleIncomingUser(userId);
UserAccounts accounts = getUserAccounts(userId);
- SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- DeDatabaseHelper.deleteSharedAccount(db, account);
- long accountId = DeDatabaseHelper.insertSharedAccount(db, account);
+ accounts.accountsDb.deleteSharedAccount(account);
+ long accountId = accounts.accountsDb.insertSharedAccount(account);
if (accountId < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account
+ ", skipping the DB insert failed");
@@ -4188,9 +4160,8 @@
public boolean renameSharedAccountAsUser(Account account, String newName, int userId) {
userId = handleIncomingUser(userId);
UserAccounts accounts = getUserAccounts(userId);
- SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- long sharedTableAccountId = DeDatabaseHelper.findSharedAccountId(db, account);
- int r = DeDatabaseHelper.renameSharedAccount(db, account, newName);
+ long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
+ int r = accounts.accountsDb.renameSharedAccount(account, newName);
if (r > 0) {
int callingUid = getCallingUid();
logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_RENAME, AccountsDb.TABLE_SHARED_ACCOUNTS,
@@ -4209,9 +4180,8 @@
private boolean removeSharedAccountAsUser(Account account, int userId, int callingUid) {
userId = handleIncomingUser(userId);
UserAccounts accounts = getUserAccounts(userId);
- SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- long sharedTableAccountId = DeDatabaseHelper.findSharedAccountId(db, account);
- boolean deleted = DeDatabaseHelper.deleteSharedAccount(db, account);
+ long sharedTableAccountId = accounts.accountsDb.findSharedAccountId(account);
+ boolean deleted = accounts.accountsDb.deleteSharedAccount(account);
if (deleted) {
logRecord(AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE, AccountsDb.TABLE_SHARED_ACCOUNTS,
sharedTableAccountId, accounts, callingUid);
@@ -4223,8 +4193,8 @@
@Override
public Account[] getSharedAccountsAsUser(int userId) {
userId = handleIncomingUser(userId);
- SQLiteDatabase db = getUserAccounts(userId).openHelper.getReadableDatabase();
- List<Account> accountList = DeDatabaseHelper.getSharedAccounts(db);
+ UserAccounts accounts = getUserAccounts(userId);
+ List<Account> accountList = accounts.accountsDb.getSharedAccounts();
Account[] accountArray = new Account[accountList.size()];
accountList.toArray(accountArray);
return accountArray;
@@ -4575,9 +4545,8 @@
if (mAuthDetailsRequired) {
long lastAuthenticatedTime = -1;
if (accountPresent) {
- lastAuthenticatedTime = DeDatabaseHelper
+ lastAuthenticatedTime = mAccounts.accountsDb
.findAccountLastAuthenticatedTime(
- mAccounts.openHelper.getReadableDatabase(),
new Account(mAccountName, mAccountType));
}
result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
@@ -4795,7 +4764,7 @@
LogRecordTask logTask = new LogRecordTask(action, tableName, accountId, userAccount,
callingUid, userAccount.debugDbInsertionPoint);
userAccount.debugDbInsertionPoint = (userAccount.debugDbInsertionPoint + 1)
- % MAX_DEBUG_DB_SIZE;
+ % AccountsDb.MAX_DEBUG_DB_SIZE;
mHandler.post(logTask);
}
@@ -4803,17 +4772,10 @@
* This should only be called once to compile the sql statement for logging
* and to find the insertion point.
*/
- private void initializeDebugDbSizeAndCompileSqlStatementForLogging(SQLiteDatabase db,
- UserAccounts userAccount) {
- // Initialize the count if not done earlier.
- int size = DebugDbHelper.getDebugTableRowCount(db);
- if (size >= MAX_DEBUG_DB_SIZE) {
- // Table is full, and we need to find the point where to insert.
- userAccount.debugDbInsertionPoint = DebugDbHelper.getDebugTableInsertionPoint(db);
- } else {
- userAccount.debugDbInsertionPoint = size;
- }
- userAccount.statementForLogging = DebugDbHelper.compileSqlStatementForLogging(db);
+ private void initializeDebugDbSizeAndCompileSqlStatementForLogging(UserAccounts userAccount) {
+ userAccount.debugDbInsertionPoint = userAccount.accountsDb
+ .calculateDebugTableInsertionPoint();
+ userAccount.statementForLogging = userAccount.accountsDb.compileSqlStatementForLogging();
}
public IBinder onBind(@SuppressWarnings("unused") Intent intent) {
@@ -4862,11 +4824,9 @@
private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
String[] args, boolean isCheckinRequest) {
synchronized (userAccounts.cacheLock) {
- final SQLiteDatabase db = userAccounts.openHelper.getReadableDatabase();
-
if (isCheckinRequest) {
// This is a checkin request. *Only* upload the account types and the count of each.
- DeDatabaseHelper.dumpAccountsTable(db, fout);
+ userAccounts.accountsDb.dumpDeAccountsTable(fout);
} else {
Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */,
Process.myUid(), null);
@@ -4877,7 +4837,7 @@
// Add debug information.
fout.println();
- DebugDbHelper.dumpDebugTable(db, fout);
+ userAccounts.accountsDb.dumpDebugTable(fout);
fout.println();
synchronized (mSessions) {
final long now = SystemClock.elapsedRealtime();
@@ -5139,13 +5099,12 @@
}
UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callerUid));
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
long grantsCount;
if (authTokenType != null) {
- grantsCount = DeDatabaseHelper.findMatchingGrantsCount(db, callerUid, authTokenType,
+ grantsCount = accounts.accountsDb.findMatchingGrantsCount(callerUid, authTokenType,
account);
} else {
- grantsCount = DeDatabaseHelper.findMatchingGrantsCountAnyToken(db, callerUid,
+ grantsCount = accounts.accountsDb.findMatchingGrantsCountAnyToken(callerUid,
account);
}
final boolean permissionGranted = grantsCount > 0;
@@ -5273,10 +5232,9 @@
}
UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- long accountId = DeDatabaseHelper.findAccountId(db, account);
+ long accountId = accounts.accountsDb.findDeAccountId(account);
if (accountId >= 0) {
- DeDatabaseHelper.insertGrant(db, accountId, authTokenType, uid);
+ accounts.accountsDb.insertGrant(accountId, authTokenType, uid);
}
cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
UserHandle.of(accounts.userId));
@@ -5306,17 +5264,16 @@
}
UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
synchronized (accounts.cacheLock) {
- final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
- db.beginTransaction();
+ accounts.accountsDb.beginTransaction();
try {
- long accountId = DeDatabaseHelper.findAccountId(db, account);
+ long accountId = accounts.accountsDb.findDeAccountId(account);
if (accountId >= 0) {
- DeDatabaseHelper.deleteGrantsByAccountIdAuthTokenTypeAndUid(
- db, accountId, authTokenType, uid);
- db.setTransactionSuccessful();
+ accounts.accountsDb.deleteGrantsByAccountIdAuthTokenTypeAndUid(
+ accountId, authTokenType, uid);
+ accounts.accountsDb.setTransactionSuccessful();
}
} finally {
- db.endTransaction();
+ accounts.accountsDb.endTransaction();
}
cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
@@ -5472,11 +5429,11 @@
}
}
- protected void writeUserDataIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
+ protected void writeUserDataIntoCacheLocked(UserAccounts accounts,
Account account, String key, String value) {
Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
if (userDataForAccount == null) {
- userDataForAccount = CeDatabaseHelper.findUserExtrasForAccount(db, account);
+ userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
accounts.userDataCache.put(account, userDataForAccount);
}
if (value == null) {
@@ -5498,11 +5455,11 @@
}
}
- protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
+ protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts,
Account account, String key, String value) {
Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
if (authTokensForAccount == null) {
- authTokensForAccount = CeDatabaseHelper.findAuthTokensByAccount(db, account);
+ authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
accounts.authTokenCache.put(account, authTokensForAccount);
}
if (value == null) {
@@ -5518,8 +5475,7 @@
Map<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
if (authTokensForAccount == null) {
// need to populate the cache for this account
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
- authTokensForAccount = CeDatabaseHelper.findAuthTokensByAccount(db, account);
+ authTokensForAccount = accounts.accountsDb.findAuthTokensByAccount(account);
accounts.authTokenCache.put(account, authTokensForAccount);
}
return authTokensForAccount.get(authTokenType);
@@ -5531,8 +5487,7 @@
Map<String, String> userDataForAccount = accounts.userDataCache.get(account);
if (userDataForAccount == null) {
// need to populate the cache for this account
- final SQLiteDatabase db = accounts.openHelper.getReadableDatabaseUserIsUnlocked();
- userDataForAccount = CeDatabaseHelper.findUserExtrasForAccount(db, account);
+ userDataForAccount = accounts.accountsDb.findUserExtrasForAccount(account);
accounts.userDataCache.put(account, userDataForAccount);
}
return userDataForAccount.get(key);
diff --git a/services/core/java/com/android/server/accounts/AccountsDb.java b/services/core/java/com/android/server/accounts/AccountsDb.java
index 6ef521e..cb594f6 100644
--- a/services/core/java/com/android/server/accounts/AccountsDb.java
+++ b/services/core/java/com/android/server/accounts/AccountsDb.java
@@ -42,8 +42,13 @@
/**
* Persistence layer abstraction for accessing accounts_ce/accounts_de databases.
+ *
+ * <p>At first, CE database needs to be {@link #attachCeDatabase(File) attached to DE},
+ * in order for the tables to be available. All operations with CE database are done through the
+ * connection to the DE database, to which it is attached. This approach allows atomic
+ * transactions across two databases</p>
*/
-class AccountsDb {
+class AccountsDb implements AutoCloseable {
private static final String TAG = "AccountsDb";
private static final String DATABASE_NAME = "accounts.db";
@@ -128,6 +133,8 @@
private static final String CE_TABLE_AUTHTOKENS = CE_DB_PREFIX + TABLE_AUTHTOKENS;
private static final String CE_TABLE_EXTRAS = CE_DB_PREFIX + TABLE_EXTRAS;
+ static final int MAX_DEBUG_DB_SIZE = 64;
+
private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
@@ -169,7 +176,17 @@
private static final String META_KEY_DELIMITER = ":";
private static final String SELECTION_META_BY_AUTHENTICATOR_TYPE = META_KEY + " LIKE ?";
- static class CeDatabaseHelper extends SQLiteOpenHelper {
+ private final DeDatabaseHelper mDeDatabase;
+ private final Context mContext;
+ private final File mPreNDatabaseFile;
+
+ AccountsDb(DeDatabaseHelper deDatabase, Context context, File preNDatabaseFile) {
+ mDeDatabase = deDatabase;
+ mContext = context;
+ mPreNDatabaseFile = preNDatabaseFile;
+ }
+
+ private static class CeDatabaseHelper extends SQLiteOpenHelper {
CeDatabaseHelper(Context context, String ceDatabaseName) {
super(context, ceDatabaseName, null, CE_DATABASE_VERSION);
@@ -249,17 +266,16 @@
/**
* Creates a new {@code CeDatabaseHelper}. If pre-N db file is present at the old location,
* it also performs migration to the new CE database.
- * @param userId id of the user where the database is located
*/
static CeDatabaseHelper create(
Context context,
- int userId,
File preNDatabaseFile,
File ceDatabaseFile) {
boolean newDbExists = ceDatabaseFile.exists();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "CeDatabaseHelper.create userId=" + userId + " oldDbExists="
- + preNDatabaseFile.exists() + " newDbExists=" + newDbExists);
+ Log.v(TAG, "CeDatabaseHelper.create ceDatabaseFile=" + ceDatabaseFile
+ + " oldDbExists=" + preNDatabaseFile.exists()
+ + " newDbExists=" + newDbExists);
}
boolean removeOldDb = false;
if (!newDbExists && preNDatabaseFile.exists()) {
@@ -290,187 +306,189 @@
}
return true;
}
-
- /**
- * Returns information about auth tokens and their account for the specified query
- * parameters.
- * Output is in the format:
- * <pre><code> | AUTHTOKEN_ID | ACCOUNT_NAME | AUTH_TOKEN_TYPE |</code></pre>
- */
- static Cursor findAuthtokenForAllAccounts(SQLiteDatabase db, String accountType,
- String authToken) {
- return db.rawQuery(
- "SELECT " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
- + ", " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
- + ", " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
- + " FROM " + CE_TABLE_ACCOUNTS
- + " JOIN " + CE_TABLE_AUTHTOKENS
- + " ON " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
- + " = " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ACCOUNTS_ID
- + " WHERE " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_AUTHTOKEN
- + " = ? AND " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
- new String[]{authToken, accountType});
- }
-
- static boolean deleteAuthtokensByAccountIdAndType(SQLiteDatabase db, long accountId,
- String authtokenType) {
- return db.delete(CE_TABLE_AUTHTOKENS,
- AUTHTOKENS_ACCOUNTS_ID + "=?" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
- new String[]{String.valueOf(accountId), authtokenType}) > 0;
- }
-
- static boolean deleteAuthToken(SQLiteDatabase db, String authTokenId) {
- return db.delete(
- CE_TABLE_AUTHTOKENS, AUTHTOKENS_ID + "= ?",
- new String[]{authTokenId}) > 0;
- }
-
- static long insertAuthToken(SQLiteDatabase db, long accountId, String authTokenType,
- String authToken) {
- ContentValues values = new ContentValues();
- values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
- values.put(AUTHTOKENS_TYPE, authTokenType);
- values.put(AUTHTOKENS_AUTHTOKEN, authToken);
- return db.insert(
- CE_TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values);
- }
-
- static Map<String, String> findAuthTokensByAccount(final SQLiteDatabase db,
- Account account) {
- HashMap<String, String> authTokensForAccount = new HashMap<>();
- Cursor cursor = db.query(CE_TABLE_AUTHTOKENS,
- COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
- SELECTION_AUTHTOKENS_BY_ACCOUNT,
- new String[]{account.name, account.type},
- null, null, null);
- try {
- while (cursor.moveToNext()) {
- final String type = cursor.getString(0);
- final String authToken = cursor.getString(1);
- authTokensForAccount.put(type, authToken);
- }
- } finally {
- cursor.close();
- }
- return authTokensForAccount;
- }
-
- static int updateAccountPassword(SQLiteDatabase db, long accountId, String password) {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_PASSWORD, password);
- return db.update(
- CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?",
- new String[]{String.valueOf(accountId)});
- }
-
- static boolean renameAccount(SQLiteDatabase db, long accountId, String newName) {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, newName);
- final String[] argsAccountId = {String.valueOf(accountId)};
- return db.update(
- CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId) > 0;
- }
-
- static boolean deleteAuthTokensByAccountId(SQLiteDatabase db, long accountId) {
- return db.delete(
- CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?",
- new String[]{String.valueOf(accountId)}) > 0;
- }
-
- static long findExtrasIdByAccountId(SQLiteDatabase db, long accountId, String key) {
- Cursor cursor = db.query(
- CE_TABLE_EXTRAS, new String[]{EXTRAS_ID},
- EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
- new String[]{key}, null, null, null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getLong(0);
- }
- return -1;
- } finally {
- cursor.close();
- }
- }
-
- static boolean updateExtra(SQLiteDatabase db, long extrasId, String value) {
- ContentValues values = new ContentValues();
- values.put(EXTRAS_VALUE, value);
- int rows = db.update(
- TABLE_EXTRAS, values, EXTRAS_ID + "=?",
- new String[]{String.valueOf(extrasId)});
- return rows == 1;
- }
-
- static long insertExtra(SQLiteDatabase db, long accountId, String key, String value) {
- ContentValues values = new ContentValues();
- values.put(EXTRAS_KEY, key);
- values.put(EXTRAS_ACCOUNTS_ID, accountId);
- values.put(EXTRAS_VALUE, value);
- return db.insert(CE_TABLE_EXTRAS, EXTRAS_KEY, values);
- }
-
- static Map<String, String> findUserExtrasForAccount(SQLiteDatabase db, Account account) {
- Map<String, String> userExtrasForAccount = new HashMap<>();
- Cursor cursor = db.query(CE_TABLE_EXTRAS,
- COLUMNS_EXTRAS_KEY_AND_VALUE,
- SELECTION_USERDATA_BY_ACCOUNT,
- new String[]{account.name, account.type},
- null, null, null);
- try {
- while (cursor.moveToNext()) {
- final String tmpkey = cursor.getString(0);
- final String value = cursor.getString(1);
- userExtrasForAccount.put(tmpkey, value);
- }
- } finally {
- cursor.close();
- }
- return userExtrasForAccount;
- }
-
- static long findAccountId(SQLiteDatabase db, Account account) {
- Cursor cursor = db.query(
- CE_TABLE_ACCOUNTS, new String[]{
- ACCOUNTS_ID},
- "name=? AND type=?", new String[]{account.name, account.type}, null, null,
- null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getLong(0);
- }
- return -1;
- } finally {
- cursor.close();
- }
- }
-
- static String findAccountPasswordByNameAndType(SQLiteDatabase db, String name,
- String type) {
- Cursor cursor = db.query(CE_TABLE_ACCOUNTS, new String[]{
- ACCOUNTS_PASSWORD},
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
- new String[]{name, type}, null, null, null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getString(0);
- }
- return null;
- } finally {
- cursor.close();
- }
- }
-
- static long insertAccount(SQLiteDatabase db, Account account, String password) {
- ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, account.name);
- values.put(ACCOUNTS_TYPE, account.type);
- values.put(ACCOUNTS_PASSWORD, password);
- return db.insert(
- CE_TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
- }
-
}
+ /**
+ * Returns information about auth tokens and their account for the specified query
+ * parameters.
+ * Output is in the format:
+ * <pre><code> | AUTHTOKEN_ID | ACCOUNT_NAME | AUTH_TOKEN_TYPE |</code></pre>
+ */
+ Cursor findAuthtokenForAllAccounts(String accountType, String authToken) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+ return db.rawQuery(
+ "SELECT " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
+ + ", " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
+ + ", " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
+ + " FROM " + CE_TABLE_ACCOUNTS
+ + " JOIN " + CE_TABLE_AUTHTOKENS
+ + " ON " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_ID
+ + " = " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_ACCOUNTS_ID
+ + " WHERE " + CE_TABLE_AUTHTOKENS + "." + AUTHTOKENS_AUTHTOKEN
+ + " = ? AND " + CE_TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
+ new String[]{authToken, accountType});
+ }
+
+ Map<String, String> findAuthTokensByAccount(Account account) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+ HashMap<String, String> authTokensForAccount = new HashMap<>();
+ Cursor cursor = db.query(CE_TABLE_AUTHTOKENS,
+ COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
+ SELECTION_AUTHTOKENS_BY_ACCOUNT,
+ new String[] {account.name, account.type},
+ null, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ final String type = cursor.getString(0);
+ final String authToken = cursor.getString(1);
+ authTokensForAccount.put(type, authToken);
+ }
+ } finally {
+ cursor.close();
+ }
+ return authTokensForAccount;
+ }
+
+ boolean deleteAuthtokensByAccountIdAndType(long accountId, String authtokenType) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+ return db.delete(CE_TABLE_AUTHTOKENS,
+ AUTHTOKENS_ACCOUNTS_ID + "=?" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
+ new String[]{String.valueOf(accountId), authtokenType}) > 0;
+ }
+
+ boolean deleteAuthToken(String authTokenId) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+ return db.delete(
+ CE_TABLE_AUTHTOKENS, AUTHTOKENS_ID + "= ?",
+ new String[]{authTokenId}) > 0;
+ }
+
+ long insertAuthToken(long accountId, String authTokenType, String authToken) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+ ContentValues values = new ContentValues();
+ values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
+ values.put(AUTHTOKENS_TYPE, authTokenType);
+ values.put(AUTHTOKENS_AUTHTOKEN, authToken);
+ return db.insert(
+ CE_TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values);
+ }
+
+ int updateCeAccountPassword(long accountId, String password) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_PASSWORD, password);
+ return db.update(
+ CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?",
+ new String[] {String.valueOf(accountId)});
+ }
+
+ boolean renameCeAccount(long accountId, String newName) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, newName);
+ final String[] argsAccountId = {String.valueOf(accountId)};
+ return db.update(
+ CE_TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId) > 0;
+ }
+
+ boolean deleteAuthTokensByAccountId(long accountId) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+ return db.delete(CE_TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?",
+ new String[] {String.valueOf(accountId)}) > 0;
+ }
+
+ long findExtrasIdByAccountId(long accountId, String key) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+ Cursor cursor = db.query(
+ CE_TABLE_EXTRAS, new String[]{EXTRAS_ID},
+ EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
+ new String[]{key}, null, null, null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
+ }
+ return -1;
+ } finally {
+ cursor.close();
+ }
+ }
+
+ boolean updateExtra(long extrasId, String value) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_VALUE, value);
+ int rows = db.update(
+ TABLE_EXTRAS, values, EXTRAS_ID + "=?",
+ new String[]{String.valueOf(extrasId)});
+ return rows == 1;
+ }
+
+ long insertExtra(long accountId, String key, String value) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+ ContentValues values = new ContentValues();
+ values.put(EXTRAS_KEY, key);
+ values.put(EXTRAS_ACCOUNTS_ID, accountId);
+ values.put(EXTRAS_VALUE, value);
+ return db.insert(CE_TABLE_EXTRAS, EXTRAS_KEY, values);
+ }
+
+ Map<String, String> findUserExtrasForAccount(Account account) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+ Map<String, String> userExtrasForAccount = new HashMap<>();
+ String[] selectionArgs = {account.name, account.type};
+ try (Cursor cursor = db.query(CE_TABLE_EXTRAS,
+ COLUMNS_EXTRAS_KEY_AND_VALUE,
+ SELECTION_USERDATA_BY_ACCOUNT,
+ selectionArgs,
+ null, null, null)) {
+ while (cursor.moveToNext()) {
+ final String tmpkey = cursor.getString(0);
+ final String value = cursor.getString(1);
+ userExtrasForAccount.put(tmpkey, value);
+ }
+ }
+ return userExtrasForAccount;
+ }
+
+ long findCeAccountId(Account account) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+ String[] columns = { ACCOUNTS_ID };
+ String selection = "name=? AND type=?";
+ String[] selectionArgs = {account.name, account.type};
+ try (Cursor cursor = db.query(CE_TABLE_ACCOUNTS, columns, selection, selectionArgs,
+ null, null, null)) {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
+ }
+ return -1;
+ }
+ }
+
+ String findAccountPasswordByNameAndType(String name, String type) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
+ String selection = ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?";
+ String[] selectionArgs = {name, type};
+ String[] columns = {ACCOUNTS_PASSWORD};
+ try (Cursor cursor = db.query(CE_TABLE_ACCOUNTS, columns, selection, selectionArgs,
+ null, null, null)) {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ return null;
+ }
+ }
+
+ long insertCeAccount(Account account, String password) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabaseUserIsUnlocked();
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, account.name);
+ values.put(ACCOUNTS_TYPE, account.type);
+ values.put(ACCOUNTS_PASSWORD, password);
+ return db.insert(
+ CE_TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+ }
+
+
static class DeDatabaseHelper extends SQLiteOpenHelper {
private final int mUserId;
@@ -504,7 +522,7 @@
createGrantsTable(db);
createSharedAccountsTable(db);
createAccountsDeletionTrigger(db);
- DebugDbHelper.createDebugTable(db);
+ createDebugTable(db);
}
private void createSharedAccountsTable(SQLiteDatabase db) {
@@ -533,6 +551,18 @@
+ "," + GRANTS_GRANTEE_UID + "))");
}
+ static void createDebugTable(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + TABLE_DEBUG + " ( "
+ + ACCOUNTS_ID + " INTEGER,"
+ + DEBUG_TABLE_ACTION_TYPE + " TEXT NOT NULL, "
+ + DEBUG_TABLE_TIMESTAMP + " DATETIME,"
+ + DEBUG_TABLE_CALLER_UID + " INTEGER NOT NULL,"
+ + DEBUG_TABLE_TABLE_NAME + " TEXT NOT NULL,"
+ + DEBUG_TABLE_KEY + " INTEGER PRIMARY KEY)");
+ db.execSQL("CREATE INDEX timestamp_index ON " + TABLE_DEBUG + " ("
+ + DEBUG_TABLE_TIMESTAMP + ")");
+ }
+
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
@@ -542,17 +572,6 @@
}
}
- public void attachCeDatabase(File ceDbFile) {
- SQLiteDatabase db = getWritableDatabase();
- db.execSQL("ATTACH DATABASE '" + ceDbFile.getPath()+ "' AS ceDb");
- mCeAttached = true;
- }
-
- public boolean isCeDatabaseAttached() {
- return mCeAttached;
- }
-
-
public SQLiteDatabase getReadableDatabaseUserIsUnlocked() {
if(!mCeAttached) {
Log.wtf(TAG, "getReadableDatabaseUserIsUnlocked called while user " + mUserId
@@ -616,343 +635,308 @@
db.execSQL("DETACH DATABASE preNDb");
}
+ }
- static boolean deleteAccount(SQLiteDatabase db, long accountId) {
- return db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null) > 0;
- }
+ boolean deleteDeAccount(long accountId) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ return db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null) > 0;
+ }
- static long insertSharedAccount(SQLiteDatabase db, Account account) {
- ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, account.name);
- values.put(ACCOUNTS_TYPE, account.type);
- return db.insert(
- TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME, values);
- }
+ long insertSharedAccount(Account account) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, account.name);
+ values.put(ACCOUNTS_TYPE, account.type);
+ return db.insert(
+ TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME, values);
+ }
- static boolean deleteSharedAccount(SQLiteDatabase db, Account account) {
- return db
- .delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
- new String[]{account.name, account.type}) > 0;
- }
+ boolean deleteSharedAccount(Account account) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ return db.delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[]{account.name, account.type}) > 0;
+ }
- static int renameSharedAccount(SQLiteDatabase db, Account account, String newName) {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, newName);
- return db.update(TABLE_SHARED_ACCOUNTS,
- values,
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
- + "=?",
- new String[]{account.name, account.type});
- }
+ int renameSharedAccount(Account account, String newName) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, newName);
+ return db.update(TABLE_SHARED_ACCOUNTS,
+ values,
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[] {account.name, account.type});
+ }
- static List<Account> getSharedAccounts(SQLiteDatabase db) {
- ArrayList<Account> accountList = new ArrayList<>();
- Cursor cursor = null;
- try {
- cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[]{
- ACCOUNTS_NAME, ACCOUNTS_TYPE},
- null, null, null, null, null);
- if (cursor != null && cursor.moveToFirst()) {
- int nameIndex = cursor.getColumnIndex(ACCOUNTS_NAME);
- int typeIndex = cursor.getColumnIndex(ACCOUNTS_TYPE);
- do {
- accountList.add(new Account(cursor.getString(nameIndex),
- cursor.getString(typeIndex)));
- } while (cursor.moveToNext());
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- return accountList;
- }
-
- static long findSharedAccountId(SQLiteDatabase db, Account account) {
- Cursor cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[]{
- ACCOUNTS_ID},
- "name=? AND type=?", new String[]{account.name, account.type}, null, null,
- null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getLong(0);
- }
- return -1;
- } finally {
- cursor.close();
- }
- }
-
- static long findAccountLastAuthenticatedTime(SQLiteDatabase db, Account account) {
- return DatabaseUtils.longForQuery(
- db,
- "SELECT " + AccountsDb.ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
- + " FROM " +
- TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
- + ACCOUNTS_TYPE + "=?",
- new String[] {account.name, account.type});
- }
-
- static boolean updateAccountLastAuthenticatedTime(SQLiteDatabase db, Account account) {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
- int rowCount = db.update(
- TABLE_ACCOUNTS,
- values,
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
- new String[] {
- account.name, account.type
- });
- return rowCount > 0;
- }
-
-
- static void dumpAccountsTable(SQLiteDatabase db, PrintWriter pw) {
- Cursor cursor = db.query(
- TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
- null, null, ACCOUNTS_TYPE, null, null);
- try {
- while (cursor.moveToNext()) {
- // print type,count
- pw.println(cursor.getString(0) + "," + cursor.getString(1));
- }
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
-
- static long findAccountId(SQLiteDatabase db, Account account) {
- Cursor cursor = db.query(
- TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
- "name=? AND type=?", new String[]{account.name, account.type}, null, null,
- null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getLong(0);
- }
- return -1;
- } finally {
- cursor.close();
- }
- }
-
- static Map<Long, Account> findAllAccounts(SQLiteDatabase db) {
- LinkedHashMap<Long, Account> map = new LinkedHashMap<>();
- Cursor cursor = db.query(TABLE_ACCOUNTS,
- new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
- null, null, null, null, ACCOUNTS_ID);
- try {
- while (cursor.moveToNext()) {
- final long accountId = cursor.getLong(0);
- final String accountType = cursor.getString(1);
- final String accountName = cursor.getString(2);
-
- final Account account = new Account(accountName, accountType);
- map.put(accountId, account);
- }
- } finally {
- cursor.close();
- }
- return map;
- }
-
- static String findAccountPreviousName(SQLiteDatabase db, Account account) {
- Cursor cursor = db.query(
- TABLE_ACCOUNTS,
- new String[]{ACCOUNTS_PREVIOUS_NAME},
- ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE
- + "=?",
- new String[]{account.name, account.type},
- null,
- null,
- null);
- try {
- if (cursor.moveToNext()) {
- return cursor.getString(0);
- }
- } finally {
- cursor.close();
- }
- return null;
- }
-
- static long insertAccount(SQLiteDatabase db, Account account, long accountId) {
- ContentValues values = new ContentValues();
- values.put(ACCOUNTS_ID, accountId);
- values.put(ACCOUNTS_NAME, account.name);
- values.put(ACCOUNTS_TYPE, account.type);
- values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
- return db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
- }
-
- static boolean renameAccount(SQLiteDatabase db, long accountId, String newName,
- String previousName) {
- final ContentValues values = new ContentValues();
- values.put(ACCOUNTS_NAME, newName);
- values.put(ACCOUNTS_PREVIOUS_NAME, previousName);
- final String[] argsAccountId = {String.valueOf(accountId)};
- return db.update(
- TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId) > 0;
- }
-
- static boolean deleteGrantsByAccountIdAuthTokenTypeAndUid(SQLiteDatabase db, long accountId,
- String authTokenType, long uid) {
- return db.delete(TABLE_GRANTS,
- GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
- + GRANTS_GRANTEE_UID + "=?",
- new String[]{String.valueOf(accountId), authTokenType, String.valueOf(uid)})
- > 0;
- }
-
- static List<Integer> findAllUidGrants(SQLiteDatabase db) {
- List<Integer> result = new ArrayList<>();
- final Cursor cursor = db.query(TABLE_GRANTS,
- new String[]{GRANTS_GRANTEE_UID},
- null, null, GRANTS_GRANTEE_UID, null, null);
- try {
- while (cursor.moveToNext()) {
- final int uid = cursor.getInt(0);
- result.add(uid);
- }
- } finally {
- cursor.close();
- }
- return result;
- }
-
- static long findMatchingGrantsCount(SQLiteDatabase db,
- int uid, String authTokenType, Account account) {
- String[] args = {String.valueOf(uid), authTokenType,
- account.name, account.type};
- return DatabaseUtils
- .longForQuery(db, COUNT_OF_MATCHING_GRANTS, args);
- }
-
- static long findMatchingGrantsCountAnyToken(SQLiteDatabase db,
- int uid, Account account) {
- String[] args = {String.valueOf(uid), account.name, account.type};
- return DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS_ANY_TOKEN, args);
- }
-
- static long insertGrant(SQLiteDatabase db, long accountId, String authTokenType, int uid) {
- ContentValues values = new ContentValues();
- values.put(GRANTS_ACCOUNTS_ID, accountId);
- values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
- values.put(GRANTS_GRANTEE_UID, uid);
- return db.insert(
- TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
- }
-
- static boolean deleteGrantsByUid(SQLiteDatabase db, int uid) {
- return db.delete(
- TABLE_GRANTS, GRANTS_GRANTEE_UID + "=?",
- new String[]{Integer.toString(uid)}) > 0;
- }
-
- static long insertMetaAuthTypeAndUid(SQLiteDatabase db, String authenticatorType, int uid) {
- ContentValues values = new ContentValues();
- values.put(META_KEY,
- META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + authenticatorType);
- values.put(META_VALUE, uid);
- return db.insert(TABLE_META, null, values);
- }
-
- static long insertOrReplaceMetaAuthTypeAndUid(SQLiteDatabase db, String authenticatorType,
- int uid) {
- ContentValues values = new ContentValues();
- values.put(META_KEY,
- META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + authenticatorType);
- values.put(META_VALUE, uid);
- return db.insertWithOnConflict(TABLE_META, null, values,
- SQLiteDatabase.CONFLICT_REPLACE);
- }
-
- static Map<String, Integer> findMetaAuthUid(SQLiteDatabase db) {
- Cursor metaCursor = db.query(
- TABLE_META,
- new String[]{META_KEY, META_VALUE},
- SELECTION_META_BY_AUTHENTICATOR_TYPE,
- new String[]{META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + "%"},
- null /* groupBy */,
- null /* having */,
- META_KEY);
- Map<String, Integer> map = new LinkedHashMap<>();
- try {
- while (metaCursor.moveToNext()) {
- String type = TextUtils
- .split(metaCursor.getString(0), META_KEY_DELIMITER)[1];
- String uidStr = metaCursor.getString(1);
- if (TextUtils.isEmpty(type) || TextUtils.isEmpty(uidStr)) {
- // Should never happen.
- Slog.e(TAG, "Auth type empty: " + TextUtils.isEmpty(type)
- + ", uid empty: " + TextUtils.isEmpty(uidStr));
- continue;
- }
- int uid = Integer.parseInt(metaCursor.getString(1));
- map.put(type, uid);
- }
- } finally {
- metaCursor.close();
- }
- return map;
- }
-
- static boolean deleteMetaByAuthTypeAndUid(SQLiteDatabase db, String type, int uid) {
- return db.delete(
- TABLE_META,
- META_KEY + "=? AND " + META_VALUE + "=?",
- new String[]{
- META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type,
- String.valueOf(uid)}
- ) > 0;
- }
-
- static List<Pair<String, Integer>> findAllAccountGrants(SQLiteDatabase db) {
- try (Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null)) {
- if (cursor == null || !cursor.moveToFirst()) {
- return Collections.emptyList();
- }
- List<Pair<String, Integer>> results = new ArrayList<>();
+ List<Account> getSharedAccounts() {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ ArrayList<Account> accountList = new ArrayList<>();
+ Cursor cursor = null;
+ try {
+ cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[] {ACCOUNTS_NAME, ACCOUNTS_TYPE},
+ null, null, null, null, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ int nameIndex = cursor.getColumnIndex(ACCOUNTS_NAME);
+ int typeIndex = cursor.getColumnIndex(ACCOUNTS_TYPE);
do {
- final String accountName = cursor.getString(0);
- final int uid = cursor.getInt(1);
- results.add(Pair.create(accountName, uid));
+ accountList.add(new Account(cursor.getString(nameIndex),
+ cursor.getString(typeIndex)));
} while (cursor.moveToNext());
- return results;
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
}
}
+ return accountList;
+ }
- static DeDatabaseHelper create(
- Context context,
- int userId,
- File preNDatabaseFile,
- File deDatabaseFile) {
- boolean newDbExists = deDatabaseFile.exists();
- DeDatabaseHelper deDatabaseHelper = new DeDatabaseHelper(context, userId,
- deDatabaseFile.getPath());
- // If the db just created, and there is a legacy db, migrate it
- if (!newDbExists && preNDatabaseFile.exists()) {
- // Migrate legacy db to the latest version - PRE_N_DATABASE_VERSION
- PreNDatabaseHelper
- preNDatabaseHelper = new PreNDatabaseHelper(context, userId,
- preNDatabaseFile.getPath());
- // Open the database to force upgrade if required
- preNDatabaseHelper.getWritableDatabase();
- preNDatabaseHelper.close();
- // Move data without SPII to DE
- deDatabaseHelper.migratePreNDbToDe(preNDatabaseFile);
+ long findSharedAccountId(Account account) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ Cursor cursor = db.query(TABLE_SHARED_ACCOUNTS, new String[]{
+ ACCOUNTS_ID},
+ "name=? AND type=?", new String[]{account.name, account.type}, null, null,
+ null);
+ try {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
}
- return deDatabaseHelper;
+ return -1;
+ } finally {
+ cursor.close();
}
}
- static class PreNDatabaseHelper extends SQLiteOpenHelper {
+ long findAccountLastAuthenticatedTime(Account account) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ return DatabaseUtils.longForQuery(db,
+ "SELECT " + AccountsDb.ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS
+ + " FROM " + TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
+ + ACCOUNTS_TYPE + "=?",
+ new String[] {account.name, account.type});
+ }
+
+ boolean updateAccountLastAuthenticatedTime(Account account) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
+ int rowCount = db.update(TABLE_ACCOUNTS,
+ values,
+ ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?",
+ new String[] { account.name, account.type });
+ return rowCount > 0;
+ }
+
+ void dumpDeAccountsTable(PrintWriter pw) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ Cursor cursor = db.query(
+ TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
+ null, null, ACCOUNTS_TYPE, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ // print type,count
+ pw.println(cursor.getString(0) + "," + cursor.getString(1));
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ long findDeAccountId(Account account) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ String[] columns = {ACCOUNTS_ID};
+ String selection = "name=? AND type=?";
+ String[] selectionArgs = {account.name, account.type};
+ try (Cursor cursor = db.query(TABLE_ACCOUNTS, columns, selection, selectionArgs,
+ null, null, null)) {
+ if (cursor.moveToNext()) {
+ return cursor.getLong(0);
+ }
+ return -1;
+ }
+ }
+
+ Map<Long, Account> findAllDeAccounts() {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ LinkedHashMap<Long, Account> map = new LinkedHashMap<>();
+ String[] columns = {ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME};
+ try (Cursor cursor = db.query(TABLE_ACCOUNTS, columns,
+ null, null, null, null, ACCOUNTS_ID)) {
+ while (cursor.moveToNext()) {
+ final long accountId = cursor.getLong(0);
+ final String accountType = cursor.getString(1);
+ final String accountName = cursor.getString(2);
+
+ final Account account = new Account(accountName, accountType);
+ map.put(accountId, account);
+ }
+ }
+ return map;
+ }
+
+ String findDeAccountPreviousName(Account account) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ String[] columns = {ACCOUNTS_PREVIOUS_NAME};
+ String selection = ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE + "=?";
+ String[] selectionArgs = {account.name, account.type};
+ try (Cursor cursor = db.query(TABLE_ACCOUNTS, columns, selection, selectionArgs,
+ null, null, null)) {
+ if (cursor.moveToNext()) {
+ return cursor.getString(0);
+ }
+ }
+ return null;
+ }
+
+ long insertDeAccount(Account account, long accountId) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_ID, accountId);
+ values.put(ACCOUNTS_NAME, account.name);
+ values.put(ACCOUNTS_TYPE, account.type);
+ values.put(ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS, System.currentTimeMillis());
+ return db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
+ }
+
+ boolean renameDeAccount(long accountId, String newName, String previousName) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ final ContentValues values = new ContentValues();
+ values.put(ACCOUNTS_NAME, newName);
+ values.put(ACCOUNTS_PREVIOUS_NAME, previousName);
+ final String[] argsAccountId = {String.valueOf(accountId)};
+ return db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId) > 0;
+ }
+
+ boolean deleteGrantsByAccountIdAuthTokenTypeAndUid(long accountId,
+ String authTokenType, long uid) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ return db.delete(TABLE_GRANTS,
+ GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
+ + GRANTS_GRANTEE_UID + "=?",
+ new String[] {String.valueOf(accountId), authTokenType, String.valueOf(uid)}) > 0;
+ }
+
+ List<Integer> findAllUidGrants() {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ List<Integer> result = new ArrayList<>();
+ final Cursor cursor = db.query(TABLE_GRANTS,
+ new String[]{GRANTS_GRANTEE_UID},
+ null, null, GRANTS_GRANTEE_UID, null, null);
+ try {
+ while (cursor.moveToNext()) {
+ final int uid = cursor.getInt(0);
+ result.add(uid);
+ }
+ } finally {
+ cursor.close();
+ }
+ return result;
+ }
+
+ long findMatchingGrantsCount(int uid, String authTokenType, Account account) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ String[] args = {String.valueOf(uid), authTokenType, account.name, account.type};
+ return DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args);
+ }
+
+ long findMatchingGrantsCountAnyToken(int uid, Account account) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ String[] args = {String.valueOf(uid), account.name, account.type};
+ return DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS_ANY_TOKEN, args);
+ }
+
+ long insertGrant(long accountId, String authTokenType, int uid) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(GRANTS_ACCOUNTS_ID, accountId);
+ values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
+ values.put(GRANTS_GRANTEE_UID, uid);
+ return db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
+ }
+
+ boolean deleteGrantsByUid(int uid) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ return db.delete(TABLE_GRANTS, GRANTS_GRANTEE_UID + "=?",
+ new String[] {Integer.toString(uid)}) > 0;
+ }
+
+ long insertOrReplaceMetaAuthTypeAndUid(String authenticatorType, int uid) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(META_KEY,
+ META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + authenticatorType);
+ values.put(META_VALUE, uid);
+ return db.insertWithOnConflict(TABLE_META, null, values,
+ SQLiteDatabase.CONFLICT_REPLACE);
+ }
+
+ Map<String, Integer> findMetaAuthUid() {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ Cursor metaCursor = db.query(
+ TABLE_META,
+ new String[]{META_KEY, META_VALUE},
+ SELECTION_META_BY_AUTHENTICATOR_TYPE,
+ new String[]{META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + "%"},
+ null /* groupBy */,
+ null /* having */,
+ META_KEY);
+ Map<String, Integer> map = new LinkedHashMap<>();
+ try {
+ while (metaCursor.moveToNext()) {
+ String type = TextUtils
+ .split(metaCursor.getString(0), META_KEY_DELIMITER)[1];
+ String uidStr = metaCursor.getString(1);
+ if (TextUtils.isEmpty(type) || TextUtils.isEmpty(uidStr)) {
+ // Should never happen.
+ Slog.e(TAG, "Auth type empty: " + TextUtils.isEmpty(type)
+ + ", uid empty: " + TextUtils.isEmpty(uidStr));
+ continue;
+ }
+ int uid = Integer.parseInt(metaCursor.getString(1));
+ map.put(type, uid);
+ }
+ } finally {
+ metaCursor.close();
+ }
+ return map;
+ }
+
+ boolean deleteMetaByAuthTypeAndUid(String type, int uid) {
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ return db.delete(
+ TABLE_META,
+ META_KEY + "=? AND " + META_VALUE + "=?",
+ new String[]{
+ META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + type,
+ String.valueOf(uid)}
+ ) > 0;
+ }
+
+ /**
+ * Returns list of all grants as {@link Pair pairs} of account name and UID.
+ */
+ List<Pair<String, Integer>> findAllAccountGrants() {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ try (Cursor cursor = db.rawQuery(ACCOUNT_ACCESS_GRANTS, null)) {
+ if (cursor == null || !cursor.moveToFirst()) {
+ return Collections.emptyList();
+ }
+ List<Pair<String, Integer>> results = new ArrayList<>();
+ do {
+ final String accountName = cursor.getString(0);
+ final int uid = cursor.getInt(1);
+ results.add(Pair.create(accountName, uid));
+ } while (cursor.moveToNext());
+ return results;
+ }
+ }
+
+ private static class PreNDatabaseHelper extends SQLiteOpenHelper {
private final Context mContext;
private final int mUserId;
- public PreNDatabaseHelper(Context context, int userId, String preNDatabaseName) {
+ PreNDatabaseHelper(Context context, int userId, String preNDatabaseName) {
super(context, preNDatabaseName, null, PRE_N_DATABASE_VERSION);
mContext = context;
mUserId = userId;
@@ -982,7 +966,7 @@
}
private void addDebugTable(SQLiteDatabase db) {
- DebugDbHelper.createDebugTable(db);
+ DeDatabaseHelper.createDebugTable(db);
}
private void createAccountsDeletionTrigger(SQLiteDatabase db) {
@@ -1007,10 +991,18 @@
+ "," + GRANTS_GRANTEE_UID + "))");
}
+ static long insertMetaAuthTypeAndUid(SQLiteDatabase db, String authenticatorType, int uid) {
+ ContentValues values = new ContentValues();
+ values.put(META_KEY,
+ META_KEY_FOR_AUTHENTICATOR_UID_FOR_TYPE_PREFIX + authenticatorType);
+ values.put(META_VALUE, uid);
+ return db.insert(TABLE_META, null, values);
+ }
+
private void populateMetaTableWithAuthTypeAndUID(SQLiteDatabase db,
Map<String, Integer> authTypeAndUIDMap) {
for (Map.Entry<String, Integer> entry : authTypeAndUIDMap.entrySet()) {
- DeDatabaseHelper.insertMetaAuthTypeAndUid(db, entry.getKey(), entry.getValue());
+ insertMetaAuthTypeAndUid(db, entry.getKey(), entry.getValue());
}
}
@@ -1078,68 +1070,8 @@
}
}
- static class DebugDbHelper{
- private DebugDbHelper() {
- }
-
-
- private static void createDebugTable(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_DEBUG + " ( "
- + ACCOUNTS_ID + " INTEGER,"
- + DEBUG_TABLE_ACTION_TYPE + " TEXT NOT NULL, "
- + DEBUG_TABLE_TIMESTAMP + " DATETIME,"
- + DEBUG_TABLE_CALLER_UID + " INTEGER NOT NULL,"
- + DEBUG_TABLE_TABLE_NAME + " TEXT NOT NULL,"
- + DEBUG_TABLE_KEY + " INTEGER PRIMARY KEY)");
- db.execSQL("CREATE INDEX timestamp_index ON " + TABLE_DEBUG + " ("
- + DEBUG_TABLE_TIMESTAMP + ")");
- }
-
- static SQLiteStatement compileSqlStatementForLogging(SQLiteDatabase db) {
- String sql = "INSERT OR REPLACE INTO " + AccountsDb.TABLE_DEBUG
- + " VALUES (?,?,?,?,?,?)";
- return db.compileStatement(sql);
- }
-
- static int getDebugTableRowCount(SQLiteDatabase db) {
- String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + TABLE_DEBUG;
- return (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
- }
-
- /*
- * Finds the row key where the next insertion should take place. This should
- * be invoked only if the table has reached its full capacity.
- */
- static int getDebugTableInsertionPoint(SQLiteDatabase db) {
- // This query finds the smallest timestamp value (and if 2 records have
- // same timestamp, the choose the lower id).
- String queryCountDebugDbRows = "SELECT " + DEBUG_TABLE_KEY +
- " FROM " + TABLE_DEBUG +
- " ORDER BY " + DEBUG_TABLE_TIMESTAMP + "," + DEBUG_TABLE_KEY +
- " LIMIT 1";
- return (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
- }
-
- static void dumpDebugTable(SQLiteDatabase db, PrintWriter pw) {
- Cursor cursor = db.query(TABLE_DEBUG, null,
- null, null, null, null, DEBUG_TABLE_TIMESTAMP);
- pw.println("AccountId, Action_Type, timestamp, UID, TableName, Key");
- pw.println("Accounts History");
- try {
- while (cursor.moveToNext()) {
- // print type,count
- pw.println(cursor.getString(0) + "," + cursor.getString(1) + "," +
- cursor.getString(2) + "," + cursor.getString(3) + ","
- + cursor.getString(4) + "," + cursor.getString(5));
- }
- } finally {
- cursor.close();
- }
- }
-
- }
-
- static List<Account> findCeAccountsNotInDe(SQLiteDatabase db) {
+ List<Account> findCeAccountsNotInDe() {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
// Select accounts from CE that do not exist in DE
Cursor cursor = db.rawQuery(
"SELECT " + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE
@@ -1161,14 +1093,110 @@
}
}
- static boolean deleteCeAccount(SQLiteDatabase db, long accountId) {
+ boolean deleteCeAccount(long accountId) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabaseUserIsUnlocked();
return db.delete(
CE_TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null) > 0;
}
+ boolean isCeDatabaseAttached() {
+ return mDeDatabase.mCeAttached;
+ }
+
+ void beginTransaction() {
+ mDeDatabase.getWritableDatabase().beginTransaction();
+ }
+
+ void setTransactionSuccessful() {
+ mDeDatabase.getWritableDatabase().setTransactionSuccessful();
+ }
+
+ void endTransaction() {
+ mDeDatabase.getWritableDatabase().endTransaction();
+ }
+
+ void attachCeDatabase(File ceDbFile) {
+ CeDatabaseHelper.create(mContext, mPreNDatabaseFile, ceDbFile);
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ db.execSQL("ATTACH DATABASE '" + ceDbFile.getPath()+ "' AS ceDb");
+ mDeDatabase.mCeAttached = true;
+ }
+
+ /*
+ * Finds the row key where the next insertion should take place. Returns number of rows
+ * if it is less {@link #MAX_DEBUG_DB_SIZE}, otherwise finds the lowest number available.
+ */
+ int calculateDebugTableInsertionPoint() {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ String queryCountDebugDbRows = "SELECT COUNT(*) FROM " + TABLE_DEBUG;
+ int size = (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
+ if (size < MAX_DEBUG_DB_SIZE) {
+ return size;
+ }
+
+ // This query finds the smallest timestamp value (and if 2 records have
+ // same timestamp, the choose the lower id).
+ queryCountDebugDbRows = "SELECT " + DEBUG_TABLE_KEY +
+ " FROM " + TABLE_DEBUG +
+ " ORDER BY " + DEBUG_TABLE_TIMESTAMP + "," + DEBUG_TABLE_KEY +
+ " LIMIT 1";
+ return (int) DatabaseUtils.longForQuery(db, queryCountDebugDbRows, null);
+ }
+
+ SQLiteStatement compileSqlStatementForLogging() {
+ // TODO b/31708085 Fix debug logging - it eagerly opens database for write without a need
+ SQLiteDatabase db = mDeDatabase.getWritableDatabase();
+ String sql = "INSERT OR REPLACE INTO " + AccountsDb.TABLE_DEBUG
+ + " VALUES (?,?,?,?,?,?)";
+ return db.compileStatement(sql);
+ }
+
+ void dumpDebugTable(PrintWriter pw) {
+ SQLiteDatabase db = mDeDatabase.getReadableDatabase();
+ Cursor cursor = db.query(TABLE_DEBUG, null,
+ null, null, null, null, DEBUG_TABLE_TIMESTAMP);
+ pw.println("AccountId, Action_Type, timestamp, UID, TableName, Key");
+ pw.println("Accounts History");
+ try {
+ while (cursor.moveToNext()) {
+ // print type,count
+ pw.println(cursor.getString(0) + "," + cursor.getString(1) + "," +
+ cursor.getString(2) + "," + cursor.getString(3) + ","
+ + cursor.getString(4) + "," + cursor.getString(5));
+ }
+ } finally {
+ cursor.close();
+ }
+ }
+
+ public void close() {
+ mDeDatabase.close();
+ }
+
static void deleteDbFileWarnIfFailed(File dbFile) {
if (!SQLiteDatabase.deleteDatabase(dbFile)) {
Log.w(TAG, "Database at " + dbFile + " was not deleted successfully");
}
}
+
+ public static AccountsDb create(Context context, int userId, File preNDatabaseFile,
+ File deDatabaseFile) {
+ boolean newDbExists = deDatabaseFile.exists();
+ DeDatabaseHelper deDatabaseHelper = new DeDatabaseHelper(context, userId,
+ deDatabaseFile.getPath());
+ // If the db just created, and there is a legacy db, migrate it
+ if (!newDbExists && preNDatabaseFile.exists()) {
+ // Migrate legacy db to the latest version - PRE_N_DATABASE_VERSION
+ PreNDatabaseHelper
+ preNDatabaseHelper = new PreNDatabaseHelper(context, userId,
+ preNDatabaseFile.getPath());
+ // Open the database to force upgrade if required
+ preNDatabaseHelper.getWritableDatabase();
+ preNDatabaseHelper.close();
+ // Move data without SPII to DE
+ deDatabaseHelper.migratePreNDbToDe(preNDatabaseFile);
+ }
+ return new AccountsDb(deDatabaseHelper, context, preNDatabaseFile);
+ }
+
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d4396a4..097d2a5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1121,21 +1121,29 @@
*/
final AppOpsService mAppOpsService;
- /**
- * Current global configuration information. Contains general settings for the entire system,
- * also corresponds to the merged configuration of the default display.
- */
- Configuration mGlobalConfiguration = new Configuration();
-
/** Current sequencing integer of the configuration, for skipping old configurations. */
private int mConfigurationSeq;
/**
* Temp object used when global configuration is updated. It is also sent to outer world
- * instead of {@link #mGlobalConfiguration} because we don't trust anyone...
+ * instead of {@link #getGlobalConfiguration} because we don't trust anyone...
*/
private Configuration mTempGlobalConfig = new Configuration();
+ private final UpdateConfigurationResult mTmpUpdateConfigurationResult =
+ new UpdateConfigurationResult();
+ private static final class UpdateConfigurationResult {
+ // Configuration changes that were updated.
+ int changes;
+ // If the activity was relaunched to match the new configuration.
+ boolean activityRelaunched;
+
+ void reset() {
+ changes = 0;
+ activityRelaunched = false;
+ }
+ }
+
boolean mSuppressResizeConfigChanges;
/**
@@ -1568,6 +1576,14 @@
final boolean mPermissionReviewRequired;
+ /**
+ * Current global configuration information. Contains general settings for the entire system,
+ * also corresponds to the merged configuration of the default display.
+ */
+ Configuration getGlobalConfiguration() {
+ return mStackSupervisor.getConfiguration();
+ }
+
final class KillHandler extends Handler {
static final int KILL_PROCESS_GROUP_MSG = 4000;
@@ -2315,7 +2331,7 @@
callingPackage = r.info.getComponentName();
if (mInVrMode != vrMode) {
mInVrMode = vrMode;
- mShowDialogs = shouldShowDialogs(mGlobalConfiguration, mInVrMode);
+ mShowDialogs = shouldShowDialogs(getGlobalConfiguration(), mInVrMode);
if (r.app != null) {
ProcessRecord proc = r.app;
if (proc.vrThreadTid > 0) {
@@ -2691,15 +2707,16 @@
mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
- mGlobalConfiguration.setToDefaults();
- mGlobalConfiguration.setLocales(LocaleList.getDefault());
+ mTempGlobalConfig.setToDefaults();
+ mTempGlobalConfig.setLocales(LocaleList.getDefault());
+ mConfigurationSeq = mTempGlobalConfig.seq = 1;
- mConfigurationSeq = mGlobalConfiguration.seq = 1;
mProcessCpuTracker.init();
+ mStackSupervisor = new ActivityStackSupervisor(this);
+ mStackSupervisor.onConfigurationChanged(mTempGlobalConfig);
mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
- mStackSupervisor = new ActivityStackSupervisor(this);
mActivityStarter = new ActivityStarter(this, mStackSupervisor);
mRecentTasks = new RecentTasks(this, mStackSupervisor);
@@ -3087,7 +3104,7 @@
synchronized (this) {
ActivityRecord r = mStackSupervisor.isInAnyStackLocked(token);
if (r != null) {
- r.task.stack.notifyActivityDrawnLocked(r);
+ r.getStack().notifyActivityDrawnLocked(r);
}
}
}
@@ -3131,8 +3148,9 @@
}
final void showUnsupportedZoomDialogIfNeededLocked(ActivityRecord r) {
- if (mGlobalConfiguration.densityDpi != DisplayMetrics.DENSITY_DEVICE_STABLE
- && r.appInfo.requiresSmallestWidthDp > mGlobalConfiguration.smallestScreenWidthDp) {
+ final Configuration globalConfig = getGlobalConfiguration();
+ if (globalConfig.densityDpi != DisplayMetrics.DENSITY_DEVICE_STABLE
+ && r.appInfo.requiresSmallestWidthDp > globalConfig.smallestScreenWidthDp) {
final Message msg = Message.obtain();
msg.what = SHOW_UNSUPPORTED_DISPLAY_SIZE_DIALOG_MSG;
msg.obj = r;
@@ -4735,7 +4753,7 @@
return;
}
TaskRecord task = r.task;
- if (task != null && (!task.mFullscreen || !task.stack.mFullscreen)) {
+ if (task != null && (!task.mFullscreen || !task.getStack().mFullscreen)) {
// Fixed screen orientation isn't supported when activities aren't in full screen
// mode.
return;
@@ -4743,7 +4761,7 @@
final long origId = Binder.clearCallingIdentity();
mWindowManager.setAppOrientation(r.appToken, requestedOrientation);
Configuration config = mWindowManager.updateOrientationFromAppTokens(
- mGlobalConfiguration, r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
+ getGlobalConfiguration(), r.mayFreezeScreenLocked(r.app) ? r.appToken : null);
if (config != null) {
r.frozenBeforeDestroy = true;
if (!updateConfigurationLocked(config, r, false)) {
@@ -4775,7 +4793,8 @@
final long origId = Binder.clearCallingIdentity();
try {
r.forceNewConfig = true;
- r.task.stack.ensureActivityConfigurationLocked(r, 0, false);
+ r.ensureActivityConfigurationLocked(0 /* globalChanges */,
+ false /* preserveWindow */);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -4821,7 +4840,7 @@
}
if (mController != null) {
// Find the first activity that is not finishing.
- ActivityRecord next = r.task.stack.topRunningActivityLocked(token, 0);
+ ActivityRecord next = r.getStack().topRunningActivityLocked(token, 0);
if (next != null) {
// ask watcher if this is allowed
boolean resumeOK = true;
@@ -4855,7 +4874,7 @@
Slog.i(TAG, "Removing task failed to finish activity");
}
} else {
- res = tr.stack.requestFinishActivityLocked(token, resultCode,
+ res = tr.getStack().requestFinishActivityLocked(token, resultCode,
resultData, "app-request", true);
if (!res) {
Slog.i(TAG, "Failed to finish by app-request");
@@ -4889,7 +4908,7 @@
for (int i = 0; i < activities.size(); i++) {
ActivityRecord r = activities.get(i);
if (!r.finishing && r.isInStackLocked()) {
- r.task.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
+ r.getStack().finishActivityLocked(r, Activity.RESULT_CANCELED,
null, "finish-heavy", true);
}
}
@@ -4925,7 +4944,7 @@
final long origId = Binder.clearCallingIdentity();
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- r.task.stack.finishSubActivityLocked(r, resultWho, requestCode);
+ r.getStack().finishSubActivityLocked(r, resultWho, requestCode);
}
Binder.restoreCallingIdentity(origId);
}
@@ -4949,7 +4968,7 @@
mStackSupervisor.showLockTaskToast();
return false;
}
- return task.stack.finishActivityAffinityLocked(r);
+ return task.getStack().finishActivityAffinityLocked(r);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -4980,7 +4999,7 @@
if (r == null) {
return false;
}
- return r.task.stack.safelyDestroyActivityLocked(r, "app-req");
+ return r.getStack().safelyDestroyActivityLocked(r, "app-req");
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -6530,7 +6549,7 @@
PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
- + processName + " with config " + mGlobalConfiguration);
+ + processName + " with config " + getGlobalConfiguration());
ApplicationInfo appInfo = app.instrumentationInfo != null
? app.instrumentationInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
@@ -6555,7 +6574,7 @@
app.instrumentationUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
- new Configuration(mGlobalConfiguration), app.compat,
+ new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
@@ -6883,10 +6902,7 @@
public final void activityResumed(IBinder token) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
- ActivityStack stack = ActivityRecord.getStackLocked(token);
- if (stack != null) {
- stack.activityResumedLocked(token);
- }
+ ActivityRecord.activityResumedLocked(token);
}
Binder.restoreCallingIdentity(origId);
}
@@ -6916,9 +6932,9 @@
final long origId = Binder.clearCallingIdentity();
synchronized (this) {
- ActivityRecord r = ActivityRecord.isInStackLocked(token);
+ final ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- r.task.stack.activityStoppedLocked(r, icicle, persistentState, description);
+ r.activityStoppedLocked(icicle, persistentState, description);
}
}
@@ -9062,7 +9078,7 @@
rti.origActivity = tr.origActivity;
rti.realActivity = tr.realActivity;
rti.description = tr.lastDescription;
- rti.stackId = tr.stack != null ? tr.stack.mStackId : -1;
+ rti.stackId = tr.getStackId();
rti.userId = tr.userId;
rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
rti.firstActiveTime = tr.firstActiveTime;
@@ -9191,15 +9207,15 @@
continue;
}
}
+ final ActivityStack stack = tr.getStack();
if ((flags & ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS) != 0) {
- if (tr.stack != null && tr.stack.isHomeStack()) {
+ if (stack != null && stack.isHomeStack()) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
"Skipping, home stack task: " + tr);
continue;
}
}
if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) {
- final ActivityStack stack = tr.stack;
if (stack != null && stack.isDockedStack() && stack.topTask() == tr) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
"Skipping, top task in docked stack: " + tr);
@@ -9207,7 +9223,7 @@
}
}
if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) {
- if (tr.stack != null && tr.stack.isPinnedStack()) {
+ if (stack != null && stack.isPinnedStack()) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
"Skipping, pinned stack task: " + tr);
continue;
@@ -9311,17 +9327,9 @@
}
}
- // Use the full screen as the context for the task thumbnail
- final Point displaySize = new Point();
- final TaskThumbnailInfo thumbnailInfo = new TaskThumbnailInfo();
- r.task.stack.getDisplaySize(displaySize);
- thumbnailInfo.taskWidth = displaySize.x;
- thumbnailInfo.taskHeight = displaySize.y;
- thumbnailInfo.screenOrientation = mGlobalConfiguration.orientation;
-
TaskRecord task = new TaskRecord(this,
mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
- ainfo, intent, description, thumbnailInfo);
+ ainfo, intent, description, new TaskThumbnailInfo());
int trimIdx = mRecentTasks.trimForTaskLocked(task, false);
if (trimIdx >= 0) {
@@ -9338,7 +9346,7 @@
task.inRecents = true;
mRecentTasks.add(task);
- r.task.stack.addTask(task, false, "addAppTask");
+ r.getStack().addTask(task, false, "addAppTask");
task.setLastThumbnailLocked(thumbnail);
task.freeLastThumbnail();
@@ -9404,7 +9412,7 @@
// - a non-null bounds on a non-freeform (fullscreen OR docked) task moves
// that task to freeform
// - otherwise the task is not moved
- int stackId = task.stack.mStackId;
+ int stackId = task.getStackId();
if (!StackId.isTaskResizeAllowed(stackId)) {
throw new IllegalArgumentException("resizeTask not allowed on task=" + task);
}
@@ -9414,7 +9422,7 @@
stackId = FREEFORM_WORKSPACE_STACK_ID;
}
boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0;
- if (stackId != task.stack.mStackId) {
+ if (stackId != task.getStackId()) {
mStackSupervisor.moveTaskToStackUncheckedLocked(
task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
preserveWindow = false;
@@ -9441,7 +9449,7 @@
Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found");
return rect;
}
- if (task.stack != null) {
+ if (task.getStack() != null) {
// Return the bounds from window manager since it will be adjusted for various
// things like the presense of a docked stack for tasks that aren't resizeable.
mWindowManager.getTaskBounds(task.taskId, rect);
@@ -9556,7 +9564,7 @@
for (int i = 0; i < procsToKill.size(); i++) {
ProcessRecord pr = procsToKill.get(i);
if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
- && pr.curReceiver == null) {
+ && pr.curReceivers.isEmpty()) {
pr.kill("remove task", true);
} else {
// We delay killing processes that are not in the background or running a receiver.
@@ -10099,7 +10107,8 @@
synchronized (this) {
final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(
taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
- return tr != null && tr.stack != null && tr.stack.isHomeStack();
+ final ActivityStack stack = tr != null ? tr.getStack() : null;
+ return stack != null && stack.isHomeStack();
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -12446,7 +12455,7 @@
}
final boolean translucentChanged = r.changeWindowTranslucency(true);
if (translucentChanged) {
- r.task.stack.releaseBackgroundResources(r);
+ r.getStack().releaseBackgroundResources(r);
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
mWindowManager.setAppFullscreen(token, true);
@@ -12473,7 +12482,7 @@
}
final boolean translucentChanged = r.changeWindowTranslucency(false);
if (translucentChanged) {
- r.task.stack.convertActivityToTranslucent(r);
+ r.getStack().convertActivityToTranslucent(r);
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.setAppFullscreen(token, false);
@@ -13155,8 +13164,8 @@
// This happens before any activities are started, so we can change global configuration
// in-place.
updateConfigurationLocked(configuration, null, true);
- if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Initial config: " + mGlobalConfiguration);
+ final Configuration globalConfig = getGlobalConfiguration();
+ if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Initial config: " + globalConfig);
// Load resources only after the current configuration has been set.
final Resources res = mContext.getResources();
@@ -13171,11 +13180,10 @@
com.android.internal.R.string.config_appsNotReportingCrashes));
mUserController.mUserSwitchUiEnabled = !res.getBoolean(
com.android.internal.R.bool.config_customUserSwitchUi);
- if ((mGlobalConfiguration.uiMode & UI_MODE_TYPE_TELEVISION)
- == UI_MODE_TYPE_TELEVISION) {
+ if ((globalConfig.uiMode & UI_MODE_TYPE_TELEVISION) == UI_MODE_TYPE_TELEVISION) {
mFullscreenThumbnailScale = (float) res
.getInteger(com.android.internal.R.integer.thumbnail_width_tv) /
- (float) mGlobalConfiguration.screenWidthDp;
+ (float) globalConfig.screenWidthDp;
} else {
mFullscreenThumbnailScale = res.getFraction(
com.android.internal.R.fraction.thumbnail_fullscreen_scale, 1, 1);
@@ -14770,7 +14778,7 @@
pw.println(" mHeavyWeightProcess: " + mHeavyWeightProcess);
}
if (dumpPackage == null) {
- pw.println(" mGlobalConfiguration: " + mGlobalConfiguration);
+ pw.println(" mGlobalConfiguration: " + getGlobalConfiguration());
}
if (dumpAll) {
pw.println(" mConfigWillChange: " + getFocusedStack().mConfigWillChange);
@@ -18753,15 +18761,16 @@
public ConfigurationInfo getDeviceConfigurationInfo() {
ConfigurationInfo config = new ConfigurationInfo();
synchronized (this) {
- config.reqTouchScreen = mGlobalConfiguration.touchscreen;
- config.reqKeyboardType = mGlobalConfiguration.keyboard;
- config.reqNavigation = mGlobalConfiguration.navigation;
- if (mGlobalConfiguration.navigation == Configuration.NAVIGATION_DPAD
- || mGlobalConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
+ final Configuration globalConfig = getGlobalConfiguration();
+ config.reqTouchScreen = globalConfig.touchscreen;
+ config.reqKeyboardType = globalConfig.keyboard;
+ config.reqNavigation = globalConfig.navigation;
+ if (globalConfig.navigation == Configuration.NAVIGATION_DPAD
+ || globalConfig.navigation == Configuration.NAVIGATION_TRACKBALL) {
config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
}
- if (mGlobalConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
- && mGlobalConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
+ if (globalConfig.keyboard != Configuration.KEYBOARD_UNDEFINED
+ && globalConfig.keyboard != Configuration.KEYBOARD_NOKEYS) {
config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
}
config.reqGlEsVersion = GL_ES_VERSION;
@@ -18785,7 +18794,7 @@
public Configuration getConfiguration() {
Configuration ci;
synchronized(this) {
- ci = new Configuration(mGlobalConfiguration);
+ ci = new Configuration(getGlobalConfiguration());
ci.userSetLocale = false;
}
return ci;
@@ -18843,7 +18852,7 @@
private void updateFontScaleIfNeeded(@UserIdInt int userId) {
final float scaleFactor = Settings.System.getFloatForUser(mContext.getContentResolver(),
FONT_SCALE, 1.0f, userId);
- if (mGlobalConfiguration.fontScale != scaleFactor) {
+ if (getGlobalConfiguration().fontScale != scaleFactor) {
final Configuration configuration = mWindowManager.computeNewConfiguration();
configuration.fontScale = scaleFactor;
synchronized (this) {
@@ -18872,7 +18881,7 @@
}
@Override
- public void updateConfiguration(Configuration values) {
+ public boolean updateConfiguration(Configuration values) {
enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
@@ -18887,16 +18896,23 @@
}
final long origId = Binder.clearCallingIdentity();
- if (values != null) {
- Settings.System.clearConfiguration(values);
+
+ try {
+ if (values != null) {
+ Settings.System.clearConfiguration(values);
+ }
+ updateConfigurationLocked(values, null, false, false /* persistent */,
+ UserHandle.USER_NULL, false /* deferResume */,
+ mTmpUpdateConfigurationResult);
+ return mTmpUpdateConfigurationResult.changes != 0;
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- updateConfigurationLocked(values, null, false);
- Binder.restoreCallingIdentity(origId);
}
}
void updateUserConfigurationLocked() {
- final Configuration configuration = new Configuration(mGlobalConfiguration);
+ final Configuration configuration = new Configuration(getGlobalConfiguration());
final int currentUserId = mUserController.getCurrentUserIdLocked();
Settings.System.adjustConfigurationForUser(mContext.getContentResolver(), configuration,
currentUserId, Settings.System.canWrite(mContext));
@@ -18919,6 +18935,12 @@
// To cache the list of supported system locales
private String[] mSupportedSystemLocales = null;
+ private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
+ boolean initLocale, boolean persistent, int userId, boolean deferResume) {
+ return updateConfigurationLocked(values, starting, initLocale, persistent, userId,
+ deferResume, null /* result */);
+ }
+
/**
* Do either or both things: (1) change the current configuration, and (2)
* make sure the given activity is running with the (now) current
@@ -18930,7 +18952,8 @@
* for that particular user
*/
private boolean updateConfigurationLocked(Configuration values, ActivityRecord starting,
- boolean initLocale, boolean persistent, int userId, boolean deferResume) {
+ boolean initLocale, boolean persistent, int userId, boolean deferResume,
+ UpdateConfigurationResult result) {
int changes = 0;
boolean kept = true;
@@ -18949,13 +18972,18 @@
mWindowManager.continueSurfaceLayout();
}
}
+
+ if (result != null) {
+ result.changes = changes;
+ result.activityRelaunched = !kept;
+ }
return kept;
}
/** Update default (global) configuration and notify listeners about changes. */
private int updateGlobalConfiguration(@NonNull Configuration values, boolean initLocale,
boolean persistent, int userId, boolean deferResume) {
- mTempGlobalConfig.setTo(mGlobalConfiguration);
+ mTempGlobalConfig.setTo(getGlobalConfiguration());
final int changes = mTempGlobalConfig.updateFrom(values);
if (changes == 0) {
return 0;
@@ -18985,7 +19013,9 @@
mConfigurationSeq = Math.max(++mConfigurationSeq, 1);
mTempGlobalConfig.seq = mConfigurationSeq;
- mGlobalConfiguration.setTo(mTempGlobalConfig);
+ // Update stored global config and notify everyone about the change.
+ mStackSupervisor.onConfigurationChanged(mTempGlobalConfig);
+
Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + mTempGlobalConfig);
// TODO(multi-display): Update UsageEvents#Event to include displayId.
mUsageStatsService.reportConfigurationChange(mTempGlobalConfig,
@@ -19007,7 +19037,7 @@
// We need another copy of global config because we're scheduling some calls instead of
// running them in place. We need to be sure that object we send will be handled unchanged.
- final Configuration configCopy = new Configuration(mGlobalConfiguration);
+ final Configuration configCopy = new Configuration(mTempGlobalConfig);
if (persistent && Settings.System.hasInterestingConfigurationChanges(changes)) {
Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
msg.obj = configCopy;
@@ -19085,7 +19115,8 @@
}
if (starting != null) {
- kept = mainStack.ensureActivityConfigurationLocked(starting, changes, false);
+ kept = starting.ensureActivityConfigurationLocked(changes,
+ false /* preserveWindow */);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
mStackSupervisor.ensureActivitiesVisibleLocked(starting, changes,
@@ -19128,7 +19159,7 @@
synchronized (this) {
ActivityRecord srec = ActivityRecord.forTokenLocked(token);
if (srec != null) {
- return srec.task.stack.shouldUpRecreateTaskLocked(srec, destAffinity);
+ return srec.getStack().shouldUpRecreateTaskLocked(srec, destAffinity);
}
}
return false;
@@ -19140,7 +19171,7 @@
synchronized (this) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r != null) {
- return r.task.stack.navigateUpToLocked(r, destIntent, resultCode, resultData);
+ return r.getStack().navigateUpToLocked(r, destIntent, resultCode, resultData);
}
return false;
}
@@ -19172,26 +19203,28 @@
// LIFETIME MANAGEMENT
// =========================================================
- // Returns which broadcast queue the app is the current [or imminent] receiver
- // on, or 'null' if the app is not an active broadcast recipient.
- private BroadcastQueue isReceivingBroadcast(ProcessRecord app) {
- BroadcastRecord r = app.curReceiver;
- if (r != null) {
- return r.queue;
+ // Returns whether the app is receiving broadcast.
+ // If receiving, fetch all broadcast queues which the app is
+ // the current [or imminent] receiver on.
+ private boolean isReceivingBroadcastLocked(ProcessRecord app,
+ ArraySet<BroadcastQueue> receivingQueues) {
+ if (!app.curReceivers.isEmpty()) {
+ for (BroadcastRecord r : app.curReceivers) {
+ receivingQueues.add(r.queue);
+ }
+ return true;
}
// It's not the current receiver, but it might be starting up to become one
- synchronized (this) {
- for (BroadcastQueue queue : mBroadcastQueues) {
- r = queue.mPendingBroadcast;
- if (r != null && r.curApp == app) {
- // found it; report which queue it's in
- return queue;
- }
+ for (BroadcastQueue queue : mBroadcastQueues) {
+ final BroadcastRecord r = queue.mPendingBroadcast;
+ if (r != null && r.curApp == app) {
+ // found it; report which queue it's in
+ receivingQueues.add(queue);
}
}
- return null;
+ return !receivingQueues.isEmpty();
}
Association startAssociationLocked(int sourceUid, String sourceProcess, int sourceState,
@@ -19358,7 +19391,7 @@
int schedGroup;
int procState;
boolean foregroundActivities = false;
- BroadcastQueue queue;
+ final ArraySet<BroadcastQueue> queues = new ArraySet<BroadcastQueue>();
if (app == TOP_APP) {
// The last app on the list is the foreground app.
adj = ProcessList.FOREGROUND_APP_ADJ;
@@ -19372,13 +19405,13 @@
schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.adjType = "instrumentation";
procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
- } else if ((queue = isReceivingBroadcast(app)) != null) {
+ } else if (isReceivingBroadcastLocked(app, queues)) {
// An app that is currently receiving a broadcast also
// counts as being in the foreground for OOM killer purposes.
// It's placed in a sched group based on the nature of the
// broadcast as reflected by which queue it's active in.
adj = ProcessList.FOREGROUND_APP_ADJ;
- schedGroup = (queue == mFgBroadcastQueue)
+ schedGroup = (queues.contains(mFgBroadcastQueue))
? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
app.adjType = "broadcast";
procState = ActivityManager.PROCESS_STATE_RECEIVER;
@@ -20389,7 +20422,7 @@
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Setting sched group of " + app.processName
+ " to " + app.curSchedGroup);
- if (app.waitingToKill != null && app.curReceiver == null
+ if (app.waitingToKill != null && app.curReceivers.isEmpty()
&& app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
app.kill(app.waitingToKill, true);
success = false;
@@ -21329,7 +21362,7 @@
for (i=mRemovedProcesses.size()-1; i>=0; i--) {
final ProcessRecord app = mRemovedProcesses.get(i);
if (app.activities.size() == 0
- && app.curReceiver == null && app.services.size() == 0) {
+ && app.curReceivers.isEmpty() && app.services.size() == 0) {
Slog.i(
TAG, "Exiting empty application process "
+ app.toShortString() + " ("
@@ -21705,6 +21738,13 @@
return mUserController.getCurrentUser();
}
+ String getStartedUserState(int userId) {
+ synchronized (this) {
+ final UserState userState = mUserController.getStartedUserStateLocked(userId);
+ return UserState.stateToString(userState.state);
+ }
+ }
+
@Override
public boolean isUserRunning(int userId, int flags) {
if (!mUserController.isSameProfileGroup(userId, UserHandle.getCallingUserId())
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index aed9fa4..7d9a706 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -19,26 +19,76 @@
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.AppGlobals;
+import android.app.IActivityContainer;
+import android.app.IActivityController;
import android.app.IActivityManager;
+import android.app.IInstrumentationWatcher;
+import android.app.IStopUserCallback;
+import android.app.Instrumentation;
import android.app.ProfilerInfo;
+import android.app.UiAutomationConnection;
+import android.app.usage.ConfigurationStats;
+import android.app.usage.IUsageStatsManager;
+import android.app.usage.UsageStatsManager;
+import android.content.ComponentCallbacks2;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.IPackageManager;
+import android.content.pm.InstrumentationInfo;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.ShellCommand;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.DebugUtils;
+import android.view.IWindowManager;
+import com.android.internal.util.HexDump;
+import com.android.internal.util.Preconditions;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
+import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
+import static android.app.ActivityManager.RESIZE_MODE_USER;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-class ActivityManagerShellCommand extends ShellCommand {
+final class ActivityManagerShellCommand extends ShellCommand {
public static final String NO_CLASS_ERROR_CODE = "Error type 3";
+ private static final String SHELL_PACKAGE_NAME = "com.android.shell";
+
+ // Is the object moving in a positive direction?
+ private static final boolean MOVING_FORWARD = true;
+ // Is the object moving in the horizontal plan?
+ private static final boolean MOVING_HORIZONTALLY = true;
+ // Is the object current point great then its target point?
+ private static final boolean GREATER_THAN_TARGET = true;
+ // Amount we reduce the stack size by when testing a task re-size.
+ private static final int STACK_BOUNDS_INSET = 10;
// IPC interface to activity manager -- don't need to do additional security checks.
final IActivityManager mInterface;
@@ -84,28 +134,92 @@
return runStartActivity(pw);
case "startservice":
case "start-service":
- return 1; //runStartService(pw);
+ return runStartService(pw);
case "stopservice":
case "stop-service":
- return 1; //runStopService(pw);
+ return runStopService(pw);
+ case "broadcast":
+ return runSendBroadcast(pw);
+ case "instrument":
+ return runInstrument(pw);
+ case "trace-ipc":
+ return runTraceIpc(pw);
+ case "profile":
+ return runProfile(pw);
+ case "dumpheap":
+ return runDumpHeap(pw);
+ case "set-debug-app":
+ return runSetDebugApp(pw);
+ case "clear-debug-app":
+ return runClearDebugApp(pw);
+ case "set-watch-heap":
+ return runSetWatchHeap(pw);
+ case "clear-watch-heap":
+ return runClearWatchHeap(pw);
+ case "bug-report":
+ return runBugReport(pw);
case "force-stop":
return runForceStop(pw);
case "kill":
return runKill(pw);
case "kill-all":
return runKillAll(pw);
- case "write":
- return runWrite(pw);
+ case "monitor":
+ return runMonitor(pw);
+ case "hang":
+ return runHang(pw);
+ case "restart":
+ return runRestart(pw);
+ case "idle-maintenance":
+ return runIdleMaintenance(pw);
+ case "screen-compat":
+ return runScreenCompat(pw);
+ case "package-importance":
+ return runPackageImportance(pw);
+ case "to-uri":
+ return runToUri(pw, 0);
+ case "to-intent-uri":
+ return runToUri(pw, Intent.URI_INTENT_SCHEME);
+ case "to-app-uri":
+ return runToUri(pw, Intent.URI_ANDROID_APP_SCHEME);
+ case "switch-user":
+ return runSwitchUser(pw);
+ case "get-current-user":
+ return runGetCurrentUser(pw);
+ case "start-user":
+ return runStartUser(pw);
+ case "unlock-user":
+ return runUnlockUser(pw);
+ case "stop-user":
+ return runStopUser(pw);
+ case "is-user-stopped":
+ return runIsUserStopped(pw);
+ case "get-started-user-state":
+ return runGetStartedUserState(pw);
case "track-associations":
return runTrackAssociations(pw);
case "untrack-associations":
return runUntrackAssociations(pw);
- case "is-user-stopped":
- return runIsUserStopped(pw);
case "lenient-background-check":
return runLenientBackgroundCheck(pw);
case "get-uid-state":
return getUidState(pw);
+ case "get-config":
+ return runGetConfig(pw);
+ case "suppress-resize-config-changes":
+ return runSuppressResizeConfigChanges(pw);
+ case "set-inactive":
+ return runSetInactive(pw);
+ case "get-inactive":
+ return runGetInactive(pw);
+ case "send-trim-memory":
+ return runSendTrimMemory(pw);
+ case "stack":
+ return runStack(pw);
+ case "task":
+ return runTask(pw);
+ case "write":
+ return runWrite(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -163,21 +277,6 @@
});
}
- ParcelFileDescriptor openOutputFile(String path) {
- try {
- ParcelFileDescriptor pfd = getShellCallback().openOutputFile(path,
- "u:r:system_server:s0");
- if (pfd != null) {
- return pfd;
- }
- } catch (RuntimeException e) {
- getErrPrintWriter().println("Failure opening file: " + e.getMessage());
- }
- getErrPrintWriter().println("Error: Unable to open file: " + path);
- getErrPrintWriter().println("Consider using a file under /data/local/tmp/");
- return null;
- }
-
int runStartActivity(PrintWriter pw) throws RemoteException {
Intent intent;
try {
@@ -218,6 +317,7 @@
packageName = activities.get(0).activityInfo.packageName;
}
pw.println("Stopping: " + packageName);
+ pw.flush();
mInterface.forceStopPackage(packageName, mUserId);
try {
Thread.sleep(250);
@@ -228,7 +328,7 @@
ProfilerInfo profilerInfo = null;
if (mProfileFile != null) {
- ParcelFileDescriptor fd = openOutputFile(mProfileFile);
+ ParcelFileDescriptor fd = openOutputFileForSystem(mProfileFile);
if (fd == null) {
return 1;
}
@@ -236,6 +336,7 @@
}
pw.println("Starting: " + intent);
+ pw.flush();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
IActivityManager.WaitResult result = null;
@@ -324,6 +425,7 @@
"Error: Activity not started, unknown error code " + res);
break;
}
+ out.flush();
if (mWaitOption && launched) {
if (result == null) {
result = new IActivityManager.WaitResult();
@@ -341,6 +443,7 @@
}
pw.println("WaitTime: " + (endTime-startTime));
pw.println("Complete");
+ pw.flush();
}
mRepeat--;
if (mRepeat > 0) {
@@ -350,10 +453,573 @@
return 0;
}
- int runIsUserStopped(PrintWriter pw) {
- int userId = UserHandle.parseUserArg(getNextArgRequired());
- boolean stopped = mInternal.isUserStopped(userId);
- pw.println(stopped);
+ int runStartService(PrintWriter pw) throws RemoteException {
+ final PrintWriter err = getErrPrintWriter();
+ Intent intent;
+ try {
+ intent = makeIntent(UserHandle.USER_CURRENT);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ if (mUserId == UserHandle.USER_ALL) {
+ err.println("Error: Can't start activity with user 'all'");
+ return -1;
+ }
+ pw.println("Starting service: " + intent);
+ pw.flush();
+ ComponentName cn = mInterface.startService(null, intent, intent.getType(),
+ SHELL_PACKAGE_NAME, mUserId);
+ if (cn == null) {
+ err.println("Error: Not found; no service started.");
+ return -1;
+ } else if (cn.getPackageName().equals("!")) {
+ err.println("Error: Requires permission " + cn.getClassName());
+ return -1;
+ } else if (cn.getPackageName().equals("!!")) {
+ err.println("Error: " + cn.getClassName());
+ return -1;
+ }
+ return 0;
+ }
+
+ int runStopService(PrintWriter pw) throws RemoteException {
+ final PrintWriter err = getErrPrintWriter();
+ Intent intent;
+ try {
+ intent = makeIntent(UserHandle.USER_CURRENT);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ if (mUserId == UserHandle.USER_ALL) {
+ err.println("Error: Can't stop activity with user 'all'");
+ return -1;
+ }
+ pw.println("Stopping service: " + intent);
+ pw.flush();
+ int result = mInterface.stopService(null, intent, intent.getType(), mUserId);
+ if (result == 0) {
+ err.println("Service not stopped: was not running.");
+ return -1;
+ } else if (result == 1) {
+ err.println("Service stopped");
+ return -1;
+ } else if (result == -1) {
+ err.println("Error stopping service");
+ return -1;
+ }
+ return 0;
+ }
+
+ final static class IntentReceiver extends IIntentReceiver.Stub {
+ private final PrintWriter mPw;
+ private boolean mFinished = false;
+
+ IntentReceiver(PrintWriter pw) {
+ mPw = pw;
+ }
+
+ @Override
+ public void performReceive(Intent intent, int resultCode, String data, Bundle extras,
+ boolean ordered, boolean sticky, int sendingUser) {
+ String line = "Broadcast completed: result=" + resultCode;
+ if (data != null) line = line + ", data=\"" + data + "\"";
+ if (extras != null) line = line + ", extras: " + extras;
+ mPw.println(line);
+ mPw.flush();
+ synchronized (this) {
+ mFinished = true;
+ notifyAll();
+ }
+ }
+
+ public synchronized void waitForFinish() {
+ try {
+ while (!mFinished) wait();
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ int runSendBroadcast(PrintWriter pw) throws RemoteException {
+ Intent intent;
+ try {
+ intent = makeIntent(UserHandle.USER_CURRENT);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ IntentReceiver receiver = new IntentReceiver(pw);
+ String[] requiredPermissions = mReceiverPermission == null ? null
+ : new String[] {mReceiverPermission};
+ pw.println("Broadcasting: " + intent);
+ pw.flush();
+ mInterface.broadcastIntent(null, intent, null, receiver, 0, null, null, requiredPermissions,
+ android.app.AppOpsManager.OP_NONE, null, true, false, mUserId);
+ receiver.waitForFinish();
+ return 0;
+ }
+
+ final static class InstrumentationWatcher extends IInstrumentationWatcher.Stub {
+ private final IActivityManager mInterface;
+ private final PrintWriter mPw;
+ private boolean mFinished = false;
+ private boolean mRawMode = false;
+
+ InstrumentationWatcher(IActivityManager iam, PrintWriter pw) {
+ mInterface = iam;
+ mPw = pw;
+ }
+
+ /**
+ * Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode",
+ * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that.
+ * @param rawMode true for raw mode, false for pretty mode.
+ */
+ public void setRawOutput(boolean rawMode) {
+ mRawMode = rawMode;
+ }
+
+ @Override
+ public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) {
+ synchronized (this) {
+ // pretty printer mode?
+ String pretty = null;
+ if (!mRawMode && results != null) {
+ pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
+ }
+ if (pretty != null) {
+ mPw.print(pretty);
+ } else {
+ if (results != null) {
+ for (String key : results.keySet()) {
+ mPw.println(
+ "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key));
+ }
+ }
+ mPw.println("INSTRUMENTATION_STATUS_CODE: " + resultCode);
+ }
+ mPw.flush();
+ notifyAll();
+ }
+ }
+
+ @Override
+ public void instrumentationFinished(ComponentName name, int resultCode,
+ Bundle results) {
+ synchronized (this) {
+ // pretty printer mode?
+ String pretty = null;
+ if (!mRawMode && results != null) {
+ pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
+ }
+ if (pretty != null) {
+ mPw.println(pretty);
+ } else {
+ if (results != null) {
+ for (String key : results.keySet()) {
+ mPw.println(
+ "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key));
+ }
+ }
+ mPw.println("INSTRUMENTATION_CODE: " + resultCode);
+ }
+ mPw.flush();
+ mFinished = true;
+ notifyAll();
+ }
+ }
+
+ public boolean waitForFinish() {
+ synchronized (this) {
+ while (!mFinished) {
+ try {
+ if (!mInterface.asBinder().pingBinder()) {
+ return false;
+ }
+ wait(1000);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+ return true;
+ }
+ }
+
+ int runInstrument(PrintWriter pw) throws RemoteException {
+ final PrintWriter err = getErrPrintWriter();
+ String profileFile = null;
+ boolean wait = false;
+ boolean rawMode = false;
+ boolean no_window_animation = false;
+ int userId = UserHandle.USER_CURRENT;
+ Bundle args = new Bundle();
+ String argKey = null, argValue = null;
+ IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+ String abi = null;
+
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("-p")) {
+ profileFile = getNextArgRequired();
+ } else if (opt.equals("-w")) {
+ wait = true;
+ } else if (opt.equals("-r")) {
+ rawMode = true;
+ } else if (opt.equals("-e")) {
+ argKey = getNextArgRequired();
+ argValue = getNextArgRequired();
+ args.putString(argKey, argValue);
+ } else if (opt.equals("--no_window_animation")
+ || opt.equals("--no-window-animation")) {
+ no_window_animation = true;
+ } else if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else if (opt.equals("--abi")) {
+ abi = getNextArgRequired();
+ } else {
+ err.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+
+ if (userId == UserHandle.USER_ALL) {
+ err.println("Error: Can't start instrumentation with user 'all'");
+ return -1;
+ }
+
+ String cnArg = getNextArgRequired();
+
+ ComponentName cn;
+ if (cnArg.contains("/")) {
+ cn = ComponentName.unflattenFromString(cnArg);
+ if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
+ } else {
+ List<InstrumentationInfo> infos = mPm.queryInstrumentation(null, 0).getList();
+
+ final int numInfos = infos == null ? 0: infos.size();
+ List<ComponentName> cns = new ArrayList<>();
+ for (int i = 0; i < numInfos; i++) {
+ InstrumentationInfo info = infos.get(i);
+
+ ComponentName c = new ComponentName(info.packageName, info.name);
+ if (cnArg.equals(info.packageName)) {
+ cns.add(c);
+ }
+ }
+
+ if (cns.size() == 0) {
+ throw new IllegalArgumentException("No instrumentation found for: " + cnArg);
+ } else if (cns.size() == 1) {
+ cn = cns.get(0);
+ } else {
+ StringBuilder cnsStr = new StringBuilder();
+ final int numCns = cns.size();
+ for (int i = 0; i < numCns; i++) {
+ cnsStr.append(cns.get(i).flattenToString());
+ cnsStr.append(", ");
+ }
+
+ // Remove last ", "
+ cnsStr.setLength(cnsStr.length() - 2);
+
+ throw new IllegalArgumentException("Found multiple instrumentations: "
+ + cnsStr.toString());
+ }
+ }
+
+ InstrumentationWatcher watcher = null;
+ UiAutomationConnection connection = null;
+ if (wait) {
+ watcher = new InstrumentationWatcher(mInterface, pw);
+ watcher.setRawOutput(rawMode);
+ // Don't yet know how to support this.
+ connection = null; //new UiAutomationConnection();
+ }
+
+ float[] oldAnims = null;
+ if (no_window_animation) {
+ oldAnims = wm.getAnimationScales();
+ wm.setAnimationScale(0, 0.0f);
+ wm.setAnimationScale(1, 0.0f);
+ }
+
+ if (abi != null) {
+ final String[] supportedAbis = Build.SUPPORTED_ABIS;
+ boolean matched = false;
+ for (String supportedAbi : supportedAbis) {
+ if (supportedAbi.equals(abi)) {
+ matched = true;
+ break;
+ }
+ }
+
+ if (!matched) {
+ throw new RuntimeException(
+ "INSTRUMENTATION_FAILED: Unsupported instruction set " + abi);
+ }
+ }
+
+ if (!mInterface.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId,
+ abi)) {
+ throw new RuntimeException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
+ }
+
+ if (watcher != null) {
+ if (!watcher.waitForFinish()) {
+ pw.println("INSTRUMENTATION_ABORTED: System has crashed.");
+ }
+ }
+
+ if (oldAnims != null) {
+ wm.setAnimationScales(oldAnims);
+ }
+ return 0;
+ }
+
+ int runTraceIpc(PrintWriter pw) throws RemoteException {
+ String op = getNextArgRequired();
+ if (op.equals("start")) {
+ return runTraceIpcStart(pw);
+ } else if (op.equals("stop")) {
+ return runTraceIpcStop(pw);
+ } else {
+ getErrPrintWriter().println("Error: unknown trace ipc command '" + op + "'");
+ return -1;
+ }
+ }
+
+ int runTraceIpcStart(PrintWriter pw) throws RemoteException {
+ pw.println("Starting IPC tracing.");
+ pw.flush();
+ mInterface.startBinderTracking();
+ return 0;
+ }
+
+ int runTraceIpcStop(PrintWriter pw) throws RemoteException {
+ final PrintWriter err = getErrPrintWriter();
+ String opt;
+ String filename = null;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("--dump-file")) {
+ filename = getNextArgRequired();
+ } else {
+ err.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ if (filename == null) {
+ err.println("Error: Specify filename to dump logs to.");
+ return -1;
+ }
+
+ File file = new File(filename);
+ file.delete();
+ ParcelFileDescriptor fd = openOutputFileForSystem(filename);
+ if (fd == null) {
+ return -1;
+ }
+
+ ;
+ if (!mInterface.stopBinderTrackingAndDump(fd)) {
+ err.println("STOP TRACE FAILED.");
+ return -1;
+ }
+
+ pw.println("Stopped IPC tracing. Dumping logs to: " + filename);
+ return 0;
+ }
+
+ static void removeWallOption() {
+ String props = SystemProperties.get("dalvik.vm.extra-opts");
+ if (props != null && props.contains("-Xprofile:wallclock")) {
+ props = props.replace("-Xprofile:wallclock", "");
+ props = props.trim();
+ SystemProperties.set("dalvik.vm.extra-opts", props);
+ }
+ }
+
+ private int runProfile(PrintWriter pw) throws RemoteException {
+ final PrintWriter err = getErrPrintWriter();
+ String profileFile = null;
+ boolean start = false;
+ boolean wall = false;
+ int userId = UserHandle.USER_CURRENT;
+ int profileType = 0;
+ mSamplingInterval = 0;
+
+ String process = null;
+
+ String cmd = getNextArgRequired();
+
+ if ("start".equals(cmd)) {
+ start = true;
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else if (opt.equals("--wall")) {
+ wall = true;
+ } else if (opt.equals("--sampling")) {
+ mSamplingInterval = Integer.parseInt(getNextArgRequired());
+ } else {
+ err.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ process = getNextArgRequired();
+ } else if ("stop".equals(cmd)) {
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ err.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ process = getNextArg();
+ } else {
+ // Compatibility with old syntax: process is specified first.
+ process = cmd;
+ cmd = getNextArgRequired();
+ if ("start".equals(cmd)) {
+ start = true;
+ } else if (!"stop".equals(cmd)) {
+ throw new IllegalArgumentException("Profile command " + process + " not valid");
+ }
+ }
+
+ if (userId == UserHandle.USER_ALL) {
+ err.println("Error: Can't profile with user 'all'");
+ return -1;
+ }
+
+ ParcelFileDescriptor fd = null;
+ ProfilerInfo profilerInfo = null;
+
+ if (start) {
+ profileFile = getNextArgRequired();
+ fd = openOutputFileForSystem(profileFile);
+ if (fd == null) {
+ return -1;
+ }
+ profilerInfo = new ProfilerInfo(profileFile, fd, mSamplingInterval, false);
+ }
+
+ try {
+ if (wall) {
+ // XXX doesn't work -- this needs to be set before booting.
+ String props = SystemProperties.get("dalvik.vm.extra-opts");
+ if (props == null || !props.contains("-Xprofile:wallclock")) {
+ props = props + " -Xprofile:wallclock";
+ //SystemProperties.set("dalvik.vm.extra-opts", props);
+ }
+ } else if (start) {
+ //removeWallOption();
+ }
+ if (!mInterface.profileControl(process, userId, start, profilerInfo, profileType)) {
+ wall = false;
+ err.println("PROFILE FAILED on process " + process);
+ return -1;
+ }
+ } finally {
+ if (!wall) {
+ //removeWallOption();
+ }
+ }
+ return 0;
+ }
+
+ int runDumpHeap(PrintWriter pw) throws RemoteException {
+ final PrintWriter err = getErrPrintWriter();
+ boolean managed = true;
+ int userId = UserHandle.USER_CURRENT;
+
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ if (userId == UserHandle.USER_ALL) {
+ err.println("Error: Can't dump heap with user 'all'");
+ return -1;
+ }
+ } else if (opt.equals("-n")) {
+ managed = false;
+ } else {
+ err.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ String process = getNextArgRequired();
+ String heapFile = getNextArgRequired();
+
+ File file = new File(heapFile);
+ file.delete();
+ ParcelFileDescriptor fd = openOutputFileForSystem(heapFile);
+ if (fd == null) {
+ return -1;
+ }
+
+ if (!mInterface.dumpHeap(process, userId, managed, heapFile, fd)) {
+ err.println("HEAP DUMP FAILED on process " + process);
+ return -1;
+ }
+ return 0;
+ }
+
+ int runSetDebugApp(PrintWriter pw) throws RemoteException {
+ boolean wait = false;
+ boolean persistent = false;
+
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("-w")) {
+ wait = true;
+ } else if (opt.equals("--persistent")) {
+ persistent = true;
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+
+ String pkg = getNextArgRequired();
+ mInterface.setDebugApp(pkg, wait, persistent);
+ return 0;
+ }
+
+ int runClearDebugApp(PrintWriter pw) throws RemoteException {
+ mInterface.setDebugApp(null, false, true);
+ return 0;
+ }
+
+ int runSetWatchHeap(PrintWriter pw) throws RemoteException {
+ String proc = getNextArgRequired();
+ String limit = getNextArgRequired();
+ mInterface.setDumpHeapDebugLimit(proc, 0, Long.parseLong(limit), null);
+ return 0;
+ }
+
+ int runClearWatchHeap(PrintWriter pw) throws RemoteException {
+ String proc = getNextArgRequired();
+ mInterface.setDumpHeapDebugLimit(proc, 0, -1, null);
+ return 0;
+ }
+
+ int runBugReport(PrintWriter pw) throws RemoteException {
+ String opt;
+ int bugreportType = ActivityManager.BUGREPORT_OPTION_FULL;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("--progress")) {
+ bugreportType = ActivityManager.BUGREPORT_OPTION_INTERACTIVE;
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ mInterface.requestBugReport(bugreportType);
+ pw.println("Your lovely bug report is being created; please be patient.");
return 0;
}
@@ -365,7 +1031,7 @@
if (opt.equals("--user")) {
userId = UserHandle.parseUserArg(getNextArgRequired());
} else {
- pw.println("Error: Unknown option: " + opt);
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
return -1;
}
}
@@ -381,7 +1047,7 @@
if (opt.equals("--user")) {
userId = UserHandle.parseUserArg(getNextArgRequired());
} else {
- pw.println("Error: Unknown option: " + opt);
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
return -1;
}
}
@@ -394,11 +1060,553 @@
return 0;
}
- int runWrite(PrintWriter pw) {
- mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
- "registerUidObserver()");
- mInternal.mRecentTasks.flush();
- pw.println("All tasks persisted.");
+ static final class MyActivityController extends IActivityController.Stub {
+ final IActivityManager mInterface;
+ final PrintWriter mPw;
+ final InputStream mInput;
+ final String mGdbPort;
+ final boolean mMonkey;
+
+ static final int STATE_NORMAL = 0;
+ static final int STATE_CRASHED = 1;
+ static final int STATE_EARLY_ANR = 2;
+ static final int STATE_ANR = 3;
+
+ int mState;
+
+ static final int RESULT_DEFAULT = 0;
+
+ static final int RESULT_CRASH_DIALOG = 0;
+ static final int RESULT_CRASH_KILL = 1;
+
+ static final int RESULT_EARLY_ANR_CONTINUE = 0;
+ static final int RESULT_EARLY_ANR_KILL = 1;
+
+ static final int RESULT_ANR_DIALOG = 0;
+ static final int RESULT_ANR_KILL = 1;
+ static final int RESULT_ANR_WAIT = 1;
+
+ int mResult;
+
+ Process mGdbProcess;
+ Thread mGdbThread;
+ boolean mGotGdbPrint;
+
+ MyActivityController(IActivityManager iam, PrintWriter pw, InputStream input,
+ String gdbPort, boolean monkey) {
+ mInterface = iam;
+ mPw = pw;
+ mInput = input;
+ mGdbPort = gdbPort;
+ mMonkey = monkey;
+ }
+
+ @Override
+ public boolean activityResuming(String pkg) {
+ synchronized (this) {
+ mPw.println("** Activity resuming: " + pkg);
+ mPw.flush();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean activityStarting(Intent intent, String pkg) {
+ synchronized (this) {
+ mPw.println("** Activity starting: " + pkg);
+ mPw.flush();
+ }
+ return true;
+ }
+
+ @Override
+ public boolean appCrashed(String processName, int pid, String shortMsg, String longMsg,
+ long timeMillis, String stackTrace) {
+ synchronized (this) {
+ mPw.println("** ERROR: PROCESS CRASHED");
+ mPw.println("processName: " + processName);
+ mPw.println("processPid: " + pid);
+ mPw.println("shortMsg: " + shortMsg);
+ mPw.println("longMsg: " + longMsg);
+ mPw.println("timeMillis: " + timeMillis);
+ mPw.println("stack:");
+ mPw.print(stackTrace);
+ mPw.println("#");
+ mPw.flush();
+ int result = waitControllerLocked(pid, STATE_CRASHED);
+ return result == RESULT_CRASH_KILL ? false : true;
+ }
+ }
+
+ @Override
+ public int appEarlyNotResponding(String processName, int pid, String annotation) {
+ synchronized (this) {
+ mPw.println("** ERROR: EARLY PROCESS NOT RESPONDING");
+ mPw.println("processName: " + processName);
+ mPw.println("processPid: " + pid);
+ mPw.println("annotation: " + annotation);
+ mPw.flush();
+ int result = waitControllerLocked(pid, STATE_EARLY_ANR);
+ if (result == RESULT_EARLY_ANR_KILL) return -1;
+ return 0;
+ }
+ }
+
+ @Override
+ public int appNotResponding(String processName, int pid, String processStats) {
+ synchronized (this) {
+ mPw.println("** ERROR: PROCESS NOT RESPONDING");
+ mPw.println("processName: " + processName);
+ mPw.println("processPid: " + pid);
+ mPw.println("processStats:");
+ mPw.print(processStats);
+ mPw.println("#");
+ mPw.flush();
+ int result = waitControllerLocked(pid, STATE_ANR);
+ if (result == RESULT_ANR_KILL) return -1;
+ if (result == RESULT_ANR_WAIT) return 1;
+ return 0;
+ }
+ }
+
+ @Override
+ public int systemNotResponding(String message) {
+ synchronized (this) {
+ mPw.println("** ERROR: PROCESS NOT RESPONDING");
+ mPw.println("message: " + message);
+ mPw.println("#");
+ mPw.println("Allowing system to die.");
+ mPw.flush();
+ return -1;
+ }
+ }
+
+ void killGdbLocked() {
+ mGotGdbPrint = false;
+ if (mGdbProcess != null) {
+ mPw.println("Stopping gdbserver");
+ mPw.flush();
+ mGdbProcess.destroy();
+ mGdbProcess = null;
+ }
+ if (mGdbThread != null) {
+ mGdbThread.interrupt();
+ mGdbThread = null;
+ }
+ }
+
+ int waitControllerLocked(int pid, int state) {
+ if (mGdbPort != null) {
+ killGdbLocked();
+
+ try {
+ mPw.println("Starting gdbserver on port " + mGdbPort);
+ mPw.println("Do the following:");
+ mPw.println(" adb forward tcp:" + mGdbPort + " tcp:" + mGdbPort);
+ mPw.println(" gdbclient app_process :" + mGdbPort);
+ mPw.flush();
+
+ mGdbProcess = Runtime.getRuntime().exec(new String[] {
+ "gdbserver", ":" + mGdbPort, "--attach", Integer.toString(pid)
+ });
+ final InputStreamReader converter = new InputStreamReader(
+ mGdbProcess.getInputStream());
+ mGdbThread = new Thread() {
+ @Override
+ public void run() {
+ BufferedReader in = new BufferedReader(converter);
+ String line;
+ int count = 0;
+ while (true) {
+ synchronized (MyActivityController.this) {
+ if (mGdbThread == null) {
+ return;
+ }
+ if (count == 2) {
+ mGotGdbPrint = true;
+ MyActivityController.this.notifyAll();
+ }
+ }
+ try {
+ line = in.readLine();
+ if (line == null) {
+ return;
+ }
+ mPw.println("GDB: " + line);
+ mPw.flush();
+ count++;
+ } catch (IOException e) {
+ return;
+ }
+ }
+ }
+ };
+ mGdbThread.start();
+
+ // Stupid waiting for .5s. Doesn't matter if we end early.
+ try {
+ this.wait(500);
+ } catch (InterruptedException e) {
+ }
+
+ } catch (IOException e) {
+ mPw.println("Failure starting gdbserver: " + e);
+ mPw.flush();
+ killGdbLocked();
+ }
+ }
+ mState = state;
+ mPw.println("");
+ printMessageForState();
+ mPw.flush();
+
+ while (mState != STATE_NORMAL) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+
+ killGdbLocked();
+
+ return mResult;
+ }
+
+ void resumeController(int result) {
+ synchronized (this) {
+ mState = STATE_NORMAL;
+ mResult = result;
+ notifyAll();
+ }
+ }
+
+ void printMessageForState() {
+ switch (mState) {
+ case STATE_NORMAL:
+ mPw.println("Monitoring activity manager... available commands:");
+ break;
+ case STATE_CRASHED:
+ mPw.println("Waiting after crash... available commands:");
+ mPw.println("(c)ontinue: show crash dialog");
+ mPw.println("(k)ill: immediately kill app");
+ break;
+ case STATE_EARLY_ANR:
+ mPw.println("Waiting after early ANR... available commands:");
+ mPw.println("(c)ontinue: standard ANR processing");
+ mPw.println("(k)ill: immediately kill app");
+ break;
+ case STATE_ANR:
+ mPw.println("Waiting after ANR... available commands:");
+ mPw.println("(c)ontinue: show ANR dialog");
+ mPw.println("(k)ill: immediately kill app");
+ mPw.println("(w)ait: wait some more");
+ break;
+ }
+ mPw.println("(q)uit: finish monitoring");
+ }
+
+ void run() throws RemoteException {
+ try {
+ printMessageForState();
+ mPw.flush();
+
+ mInterface.setActivityController(this, mMonkey);
+ mState = STATE_NORMAL;
+
+ InputStreamReader converter = new InputStreamReader(mInput);
+ BufferedReader in = new BufferedReader(converter);
+ String line;
+
+ while ((line = in.readLine()) != null) {
+ boolean addNewline = true;
+ if (line.length() <= 0) {
+ addNewline = false;
+ } else if ("q".equals(line) || "quit".equals(line)) {
+ resumeController(RESULT_DEFAULT);
+ break;
+ } else if (mState == STATE_CRASHED) {
+ if ("c".equals(line) || "continue".equals(line)) {
+ resumeController(RESULT_CRASH_DIALOG);
+ } else if ("k".equals(line) || "kill".equals(line)) {
+ resumeController(RESULT_CRASH_KILL);
+ } else {
+ mPw.println("Invalid command: " + line);
+ }
+ } else if (mState == STATE_ANR) {
+ if ("c".equals(line) || "continue".equals(line)) {
+ resumeController(RESULT_ANR_DIALOG);
+ } else if ("k".equals(line) || "kill".equals(line)) {
+ resumeController(RESULT_ANR_KILL);
+ } else if ("w".equals(line) || "wait".equals(line)) {
+ resumeController(RESULT_ANR_WAIT);
+ } else {
+ mPw.println("Invalid command: " + line);
+ }
+ } else if (mState == STATE_EARLY_ANR) {
+ if ("c".equals(line) || "continue".equals(line)) {
+ resumeController(RESULT_EARLY_ANR_CONTINUE);
+ } else if ("k".equals(line) || "kill".equals(line)) {
+ resumeController(RESULT_EARLY_ANR_KILL);
+ } else {
+ mPw.println("Invalid command: " + line);
+ }
+ } else {
+ mPw.println("Invalid command: " + line);
+ }
+
+ synchronized (this) {
+ if (addNewline) {
+ mPw.println("");
+ }
+ printMessageForState();
+ mPw.flush();
+ }
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace(mPw);
+ mPw.flush();
+ } finally {
+ mInterface.setActivityController(null, mMonkey);
+ }
+ }
+ }
+
+ int runMonitor(PrintWriter pw) throws RemoteException {
+ String opt;
+ String gdbPort = null;
+ boolean monkey = false;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("--gdb")) {
+ gdbPort = getNextArgRequired();
+ } else if (opt.equals("-m")) {
+ monkey = true;
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+
+ MyActivityController controller = new MyActivityController(mInterface, pw,
+ getRawInputStream(), gdbPort, monkey);
+ controller.run();
+ return 0;
+ }
+
+ int runHang(PrintWriter pw) throws RemoteException {
+ String opt;
+ boolean allowRestart = false;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("--allow-restart")) {
+ allowRestart = true;
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+
+ pw.println("Hanging the system...");
+ pw.flush();
+ mInterface.hang(new Binder(), allowRestart);
+ return 0;
+ }
+
+ int runRestart(PrintWriter pw) throws RemoteException {
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+
+ pw.println("Restart the system...");
+ pw.flush();
+ mInterface.restart();
+ return 0;
+ }
+
+ int runIdleMaintenance(PrintWriter pw) throws RemoteException {
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+
+ pw.println("Performing idle maintenance...");
+ mInterface.sendIdleJobTrigger();
+ return 0;
+ }
+
+ int runScreenCompat(PrintWriter pw) throws RemoteException {
+ String mode = getNextArgRequired();
+ boolean enabled;
+ if ("on".equals(mode)) {
+ enabled = true;
+ } else if ("off".equals(mode)) {
+ enabled = false;
+ } else {
+ getErrPrintWriter().println("Error: enabled mode must be 'on' or 'off' at " + mode);
+ return -1;
+ }
+
+ String packageName = getNextArgRequired();
+ do {
+ try {
+ mInterface.setPackageScreenCompatMode(packageName, enabled
+ ? ActivityManager.COMPAT_MODE_ENABLED
+ : ActivityManager.COMPAT_MODE_DISABLED);
+ } catch (RemoteException e) {
+ }
+ packageName = getNextArg();
+ } while (packageName != null);
+ return 0;
+ }
+
+ int runPackageImportance(PrintWriter pw) throws RemoteException {
+ String packageName = getNextArgRequired();
+ int procState = mInterface.getPackageProcessState(packageName, "com.android.shell");
+ pw.println(ActivityManager.RunningAppProcessInfo.procStateToImportance(procState));
+ return 0;
+ }
+
+ int runToUri(PrintWriter pw, int flags) throws RemoteException {
+ Intent intent;
+ try {
+ intent = makeIntent(UserHandle.USER_CURRENT);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ pw.println(intent.toUri(flags));
+ return 0;
+ }
+
+ int runSwitchUser(PrintWriter pw) throws RemoteException {
+ String user = getNextArgRequired();
+ mInterface.switchUser(Integer.parseInt(user));
+ return 0;
+ }
+
+ int runGetCurrentUser(PrintWriter pw) throws RemoteException {
+ UserInfo currentUser = Preconditions.checkNotNull(mInterface.getCurrentUser(),
+ "Current user not set");
+ pw.println(currentUser.id);
+ return 0;
+ }
+
+ int runStartUser(PrintWriter pw) throws RemoteException {
+ String user = getNextArgRequired();
+ boolean success = mInterface.startUserInBackground(Integer.parseInt(user));
+ if (success) {
+ pw.println("Success: user started");
+ } else {
+ getErrPrintWriter().println("Error: could not start user");
+ }
+ return 0;
+ }
+
+ private static byte[] argToBytes(String arg) {
+ if (arg.equals("!")) {
+ return null;
+ } else {
+ return HexDump.hexStringToByteArray(arg);
+ }
+ }
+
+ int runUnlockUser(PrintWriter pw) throws RemoteException {
+ int userId = Integer.parseInt(getNextArgRequired());
+ byte[] token = argToBytes(getNextArgRequired());
+ byte[] secret = argToBytes(getNextArgRequired());
+ boolean success = mInterface.unlockUser(userId, token, secret, null);
+ if (success) {
+ pw.println("Success: user unlocked");
+ } else {
+ getErrPrintWriter().println("Error: could not unlock user");
+ }
+ return 0;
+ }
+
+ static final class StopUserCallback extends IStopUserCallback.Stub {
+ private boolean mFinished = false;
+
+ public synchronized void waitForFinish() {
+ try {
+ while (!mFinished) wait();
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override
+ public synchronized void userStopped(int userId) {
+ mFinished = true;
+ notifyAll();
+ }
+
+ @Override
+ public synchronized void userStopAborted(int userId) {
+ mFinished = true;
+ notifyAll();
+ }
+ }
+
+ int runStopUser(PrintWriter pw) throws RemoteException {
+ boolean wait = false;
+ boolean force = false;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ if ("-w".equals(opt)) {
+ wait = true;
+ } else if ("-f".equals(opt)) {
+ force = true;
+ } else {
+ getErrPrintWriter().println("Error: unknown option: " + opt);
+ return -1;
+ }
+ }
+ int user = Integer.parseInt(getNextArgRequired());
+ StopUserCallback callback = wait ? new StopUserCallback() : null;
+
+ int res = mInterface.stopUser(user, force, callback);
+ if (res != ActivityManager.USER_OP_SUCCESS) {
+ String txt = "";
+ switch (res) {
+ case ActivityManager.USER_OP_IS_CURRENT:
+ txt = " (Can't stop current user)";
+ break;
+ case ActivityManager.USER_OP_UNKNOWN_USER:
+ txt = " (Unknown user " + user + ")";
+ break;
+ case ActivityManager.USER_OP_ERROR_IS_SYSTEM:
+ txt = " (System user cannot be stopped)";
+ break;
+ case ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP:
+ txt = " (Can't stop user " + user
+ + " - one of its related users can't be stopped)";
+ break;
+ }
+ getErrPrintWriter().println("Switch failed: " + res + txt);
+ return -1;
+ } else if (callback != null) {
+ callback.waitForFinish();
+ }
+ return 0;
+ }
+
+ int runIsUserStopped(PrintWriter pw) {
+ int userId = UserHandle.parseUserArg(getNextArgRequired());
+ boolean stopped = mInternal.isUserStopped(userId);
+ pw.println(stopped);
+ return 0;
+ }
+
+ int runGetStartedUserState(PrintWriter pw) throws RemoteException {
+ mInternal.enforceCallingPermission(android.Manifest.permission.DUMP,
+ "runGetStartedUserState()");
+ final int userId = Integer.parseInt(getNextArgRequired());
+ try {
+ pw.println(mInternal.getStartedUserState(userId));
+ } catch (NullPointerException e) {
+ pw.println("User is not started: " + userId);
+ }
return 0;
}
@@ -458,6 +1666,802 @@
return 0;
}
+ private List<Configuration> getRecentConfigurations(int days) {
+ IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
+ Context.USAGE_STATS_SERVICE));
+ final long now = System.currentTimeMillis();
+ final long nDaysAgo = now - (days * 24 * 60 * 60 * 1000);
+ try {
+ @SuppressWarnings("unchecked")
+ ParceledListSlice<ConfigurationStats> configStatsSlice = usm.queryConfigurationStats(
+ UsageStatsManager.INTERVAL_BEST, nDaysAgo, now, "com.android.shell");
+ if (configStatsSlice == null) {
+ return Collections.emptyList();
+ }
+
+ final ArrayMap<Configuration, Integer> recentConfigs = new ArrayMap<>();
+ final List<ConfigurationStats> configStatsList = configStatsSlice.getList();
+ final int configStatsListSize = configStatsList.size();
+ for (int i = 0; i < configStatsListSize; i++) {
+ final ConfigurationStats stats = configStatsList.get(i);
+ final int indexOfKey = recentConfigs.indexOfKey(stats.getConfiguration());
+ if (indexOfKey < 0) {
+ recentConfigs.put(stats.getConfiguration(), stats.getActivationCount());
+ } else {
+ recentConfigs.setValueAt(indexOfKey,
+ recentConfigs.valueAt(indexOfKey) + stats.getActivationCount());
+ }
+ }
+
+ final Comparator<Configuration> comparator = new Comparator<Configuration>() {
+ @Override
+ public int compare(Configuration a, Configuration b) {
+ return recentConfigs.get(b).compareTo(recentConfigs.get(a));
+ }
+ };
+
+ ArrayList<Configuration> configs = new ArrayList<>(recentConfigs.size());
+ configs.addAll(recentConfigs.keySet());
+ Collections.sort(configs, comparator);
+ return configs;
+
+ } catch (RemoteException e) {
+ return Collections.emptyList();
+ }
+ }
+
+ int runGetConfig(PrintWriter pw) throws RemoteException {
+ int days = 14;
+ String option = getNextOption();
+ if (option != null) {
+ if (!option.equals("--days")) {
+ throw new IllegalArgumentException("unrecognized option " + option);
+ }
+
+ days = Integer.parseInt(getNextArgRequired());
+ if (days <= 0) {
+ throw new IllegalArgumentException("--days must be a positive integer");
+ }
+ }
+
+ Configuration config = mInterface.getConfiguration();
+ if (config == null) {
+ getErrPrintWriter().println("Activity manager has no configuration");
+ return -1;
+ }
+
+ pw.println("config: " + Configuration.resourceQualifierString(config));
+ pw.println("abi: " + TextUtils.join(",", Build.SUPPORTED_ABIS));
+
+ final List<Configuration> recentConfigs = getRecentConfigurations(days);
+ final int recentConfigSize = recentConfigs.size();
+ if (recentConfigSize > 0) {
+ pw.println("recentConfigs:");
+ }
+
+ for (int i = 0; i < recentConfigSize; i++) {
+ pw.println(" config: " + Configuration.resourceQualifierString(
+ recentConfigs.get(i)));
+ }
+ return 0;
+ }
+
+ int runSuppressResizeConfigChanges(PrintWriter pw) throws RemoteException {
+ boolean suppress = Boolean.valueOf(getNextArgRequired());
+ mInterface.suppressResizeConfigChanges(suppress);
+ return 0;
+ }
+
+ int runSetInactive(PrintWriter pw) throws RemoteException {
+ int userId = UserHandle.USER_CURRENT;
+
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ String packageName = getNextArgRequired();
+ String value = getNextArgRequired();
+
+ IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
+ Context.USAGE_STATS_SERVICE));
+ usm.setAppInactive(packageName, Boolean.parseBoolean(value), userId);
+ return 0;
+ }
+
+ int runGetInactive(PrintWriter pw) throws RemoteException {
+ int userId = UserHandle.USER_CURRENT;
+
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ String packageName = getNextArgRequired();
+
+ IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
+ Context.USAGE_STATS_SERVICE));
+ boolean isIdle = usm.isAppInactive(packageName, userId);
+ pw.println("Idle=" + isIdle);
+ return 0;
+ }
+
+ int runSendTrimMemory(PrintWriter pw) throws RemoteException {
+ int userId = UserHandle.USER_CURRENT;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ if (userId == UserHandle.USER_ALL) {
+ getErrPrintWriter().println("Error: Can't use user 'all'");
+ return -1;
+ }
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+
+ String proc = getNextArgRequired();
+ String levelArg = getNextArgRequired();
+ int level;
+ switch (levelArg) {
+ case "HIDDEN":
+ level = ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+ break;
+ case "RUNNING_MODERATE":
+ level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
+ break;
+ case "BACKGROUND":
+ level = ComponentCallbacks2.TRIM_MEMORY_BACKGROUND;
+ break;
+ case "RUNNING_LOW":
+ level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
+ break;
+ case "MODERATE":
+ level = ComponentCallbacks2.TRIM_MEMORY_MODERATE;
+ break;
+ case "RUNNING_CRITICAL":
+ level = ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL;
+ break;
+ case "COMPLETE":
+ level = ComponentCallbacks2.TRIM_MEMORY_COMPLETE;
+ break;
+ default:
+ getErrPrintWriter().println("Error: Unknown level option: " + levelArg);
+ return -1;
+ }
+ if (!mInterface.setProcessMemoryTrimLevel(proc, userId, level)) {
+ getErrPrintWriter().println("Unknown error: failed to set trim level");
+ return -1;
+ }
+ return 0;
+ }
+
+ int runStack(PrintWriter pw) throws RemoteException {
+ String op = getNextArgRequired();
+ switch (op) {
+ case "start":
+ return runStackStart(pw);
+ case "movetask":
+ return runStackMoveTask(pw);
+ case "resize":
+ return runStackResize(pw);
+ case "resize-animated":
+ return runStackResizeAnimated(pw);
+ case "resize-docked-stack":
+ return runStackResizeDocked(pw);
+ case "positiontask":
+ return runStackPositionTask(pw);
+ case "list":
+ return runStackList(pw);
+ case "info":
+ return runStackInfo(pw);
+ case "move-top-activity-to-pinned-stack":
+ return runMoveTopActivityToPinnedStack(pw);
+ case "size-docked-stack-test":
+ return runStackSizeDockedStackTest(pw);
+ case "remove":
+ return runStackRemove(pw);
+ default:
+ getErrPrintWriter().println("Error: unknown command '" + op + "'");
+ return -1;
+ }
+ }
+
+
+ private Rect getBounds() {
+ String leftStr = getNextArgRequired();
+ int left = Integer.parseInt(leftStr);
+ String topStr = getNextArgRequired();
+ int top = Integer.parseInt(topStr);
+ String rightStr = getNextArgRequired();
+ int right = Integer.parseInt(rightStr);
+ String bottomStr = getNextArgRequired();
+ int bottom = Integer.parseInt(bottomStr);
+ if (left < 0) {
+ getErrPrintWriter().println("Error: bad left arg: " + leftStr);
+ return null;
+ }
+ if (top < 0) {
+ getErrPrintWriter().println("Error: bad top arg: " + topStr);
+ return null;
+ }
+ if (right <= 0) {
+ getErrPrintWriter().println("Error: bad right arg: " + rightStr);
+ return null;
+ }
+ if (bottom <= 0) {
+ getErrPrintWriter().println("Error: bad bottom arg: " + bottomStr);
+ return null;
+ }
+ return new Rect(left, top, right, bottom);
+ }
+
+ int runStackStart(PrintWriter pw) throws RemoteException {
+ String displayIdStr = getNextArgRequired();
+ int displayId = Integer.parseInt(displayIdStr);
+ Intent intent;
+ try {
+ intent = makeIntent(UserHandle.USER_CURRENT);
+ } catch (URISyntaxException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+
+ IActivityContainer container = mInterface.createStackOnDisplay(displayId);
+ if (container != null) {
+ container.startActivity(intent);
+ }
+ return 0;
+ }
+
+ int runStackMoveTask(PrintWriter pw) throws RemoteException {
+ String taskIdStr = getNextArgRequired();
+ int taskId = Integer.parseInt(taskIdStr);
+ String stackIdStr = getNextArgRequired();
+ int stackId = Integer.parseInt(stackIdStr);
+ String toTopStr = getNextArgRequired();
+ final boolean toTop;
+ if ("true".equals(toTopStr)) {
+ toTop = true;
+ } else if ("false".equals(toTopStr)) {
+ toTop = false;
+ } else {
+ getErrPrintWriter().println("Error: bad toTop arg: " + toTopStr);
+ return -1;
+ }
+
+ mInterface.moveTaskToStack(taskId, stackId, toTop);
+ return 0;
+ }
+
+ int runStackResize(PrintWriter pw) throws RemoteException {
+ String stackIdStr = getNextArgRequired();
+ int stackId = Integer.parseInt(stackIdStr);
+ final Rect bounds = getBounds();
+ if (bounds == null) {
+ getErrPrintWriter().println("Error: invalid input bounds");
+ return -1;
+ }
+ return resizeStack(stackId, bounds, 0);
+ }
+
+ int runStackResizeAnimated(PrintWriter pw) throws RemoteException {
+ String stackIdStr = getNextArgRequired();
+ int stackId = Integer.parseInt(stackIdStr);
+ final Rect bounds;
+ if ("null".equals(peekNextArg())) {
+ bounds = null;
+ } else {
+ bounds = getBounds();
+ if (bounds == null) {
+ getErrPrintWriter().println("Error: invalid input bounds");
+ return -1;
+ }
+ }
+ return resizeStackUnchecked(stackId, bounds, 0, true);
+ }
+
+ int resizeStackUnchecked(int stackId, Rect bounds, int delayMs, boolean animate)
+ throws RemoteException {
+ try {
+ mInterface.resizeStack(stackId, bounds, false, false, animate, -1);
+ Thread.sleep(delayMs);
+ } catch (InterruptedException e) {
+ }
+ return 0;
+ }
+
+ int runStackResizeDocked(PrintWriter pw) throws RemoteException {
+ final Rect bounds = getBounds();
+ final Rect taskBounds = getBounds();
+ if (bounds == null || taskBounds == null) {
+ getErrPrintWriter().println("Error: invalid input bounds");
+ return -1;
+ }
+ mInterface.resizeDockedStack(bounds, taskBounds, null, null, null);
+ return 0;
+ }
+
+ int resizeStack(int stackId, Rect bounds, int delayMs) throws RemoteException {
+ if (bounds == null) {
+ getErrPrintWriter().println("Error: invalid input bounds");
+ return -1;
+ }
+ return resizeStackUnchecked(stackId, bounds, delayMs, false);
+ }
+
+ int runStackPositionTask(PrintWriter pw) throws RemoteException {
+ String taskIdStr = getNextArgRequired();
+ int taskId = Integer.parseInt(taskIdStr);
+ String stackIdStr = getNextArgRequired();
+ int stackId = Integer.parseInt(stackIdStr);
+ String positionStr = getNextArgRequired();
+ int position = Integer.parseInt(positionStr);
+
+ mInterface.positionTaskInStack(taskId, stackId, position);
+ return 0;
+ }
+
+ int runStackList(PrintWriter pw) throws RemoteException {
+ List<ActivityManager.StackInfo> stacks = mInterface.getAllStackInfos();
+ for (ActivityManager.StackInfo info : stacks) {
+ pw.println(info);
+ }
+ return 0;
+ }
+
+ int runStackInfo(PrintWriter pw) throws RemoteException {
+ String stackIdStr = getNextArgRequired();
+ int stackId = Integer.parseInt(stackIdStr);
+ ActivityManager.StackInfo info = mInterface.getStackInfo(stackId);
+ pw.println(info);
+ return 0;
+ }
+
+ int runStackRemove(PrintWriter pw) throws RemoteException {
+ String stackIdStr = getNextArgRequired();
+ int stackId = Integer.parseInt(stackIdStr);
+ mInterface.removeStack(stackId);
+ return 0;
+ }
+
+ int runMoveTopActivityToPinnedStack(PrintWriter pw) throws RemoteException {
+ int stackId = Integer.parseInt(getNextArgRequired());
+ final Rect bounds = getBounds();
+ if (bounds == null) {
+ getErrPrintWriter().println("Error: invalid input bounds");
+ return -1;
+ }
+
+ if (!mInterface.moveTopActivityToPinnedStack(stackId, bounds)) {
+ getErrPrintWriter().println("Didn't move top activity to pinned stack.");
+ return -1;
+ }
+ return 0;
+ }
+
+ int runStackSizeDockedStackTest(PrintWriter pw) throws RemoteException {
+ final PrintWriter err = getErrPrintWriter();
+ final int stepSize = Integer.parseInt(getNextArgRequired());
+ final String side = getNextArgRequired();
+ final String delayStr = getNextArg();
+ final int delayMs = (delayStr != null) ? Integer.parseInt(delayStr) : 0;
+
+ ActivityManager.StackInfo info = mInterface.getStackInfo(DOCKED_STACK_ID);
+ if (info == null) {
+ err.println("Docked stack doesn't exist");
+ return -1;
+ }
+ if (info.bounds == null) {
+ err.println("Docked stack doesn't have a bounds");
+ return -1;
+ }
+ Rect bounds = info.bounds;
+
+ final boolean horizontalGrowth = "l".equals(side) || "r".equals(side);
+ final int changeSize = (horizontalGrowth ? bounds.width() : bounds.height()) / 2;
+ int currentPoint;
+ switch (side) {
+ case "l":
+ currentPoint = bounds.left;
+ break;
+ case "r":
+ currentPoint = bounds.right;
+ break;
+ case "t":
+ currentPoint = bounds.top;
+ break;
+ case "b":
+ currentPoint = bounds.bottom;
+ break;
+ default:
+ err.println("Unknown growth side: " + side);
+ return -1;
+ }
+
+ final int startPoint = currentPoint;
+ final int minPoint = currentPoint - changeSize;
+ final int maxPoint = currentPoint + changeSize;
+
+ int maxChange;
+ pw.println("Shrinking docked stack side=" + side);
+ pw.flush();
+ while (currentPoint > minPoint) {
+ maxChange = Math.min(stepSize, currentPoint - minPoint);
+ currentPoint -= maxChange;
+ setBoundsSide(bounds, side, currentPoint);
+ int res = resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ if (res < 0) {
+ return res;
+ }
+ }
+
+ pw.println("Growing docked stack side=" + side);
+ pw.flush();
+ while (currentPoint < maxPoint) {
+ maxChange = Math.min(stepSize, maxPoint - currentPoint);
+ currentPoint += maxChange;
+ setBoundsSide(bounds, side, currentPoint);
+ int res = resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ if (res < 0) {
+ return res;
+ }
+ }
+
+ pw.println("Back to Original size side=" + side);
+ pw.flush();
+ while (currentPoint > startPoint) {
+ maxChange = Math.min(stepSize, currentPoint - startPoint);
+ currentPoint -= maxChange;
+ setBoundsSide(bounds, side, currentPoint);
+ int res = resizeStack(DOCKED_STACK_ID, bounds, delayMs);
+ if (res < 0) {
+ return res;
+ }
+ }
+ return 0;
+ }
+
+ void setBoundsSide(Rect bounds, String side, int value) {
+ switch (side) {
+ case "l":
+ bounds.left = value;
+ break;
+ case "r":
+ bounds.right = value;
+ break;
+ case "t":
+ bounds.top = value;
+ break;
+ case "b":
+ bounds.bottom = value;
+ break;
+ default:
+ getErrPrintWriter().println("Unknown set side: " + side);
+ break;
+ }
+ }
+
+ int runTask(PrintWriter pw) throws RemoteException {
+ String op = getNextArgRequired();
+ if (op.equals("lock")) {
+ return runTaskLock(pw);
+ } else if (op.equals("resizeable")) {
+ return runTaskResizeable(pw);
+ } else if (op.equals("resize")) {
+ return runTaskResize(pw);
+ } else if (op.equals("drag-task-test")) {
+ return runTaskDragTaskTest(pw);
+ } else if (op.equals("size-task-test")) {
+ return runTaskSizeTaskTest(pw);
+ } else {
+ getErrPrintWriter().println("Error: unknown command '" + op + "'");
+ return -1;
+ }
+ }
+
+ int runTaskLock(PrintWriter pw) throws RemoteException {
+ String taskIdStr = getNextArgRequired();
+ if (taskIdStr.equals("stop")) {
+ mInterface.stopLockTaskMode();
+ } else {
+ int taskId = Integer.parseInt(taskIdStr);
+ mInterface.startLockTaskMode(taskId);
+ }
+ pw.println("Activity manager is " + (mInterface.isInLockTaskMode() ? "" : "not ") +
+ "in lockTaskMode");
+ return 0;
+ }
+
+ int runTaskResizeable(PrintWriter pw) throws RemoteException {
+ final String taskIdStr = getNextArgRequired();
+ final int taskId = Integer.parseInt(taskIdStr);
+ final String resizeableStr = getNextArgRequired();
+ final int resizeableMode = Integer.parseInt(resizeableStr);
+ mInterface.setTaskResizeable(taskId, resizeableMode);
+ return 0;
+ }
+
+ int runTaskResize(PrintWriter pw) throws RemoteException {
+ final String taskIdStr = getNextArgRequired();
+ final int taskId = Integer.parseInt(taskIdStr);
+ final Rect bounds = getBounds();
+ if (bounds == null) {
+ getErrPrintWriter().println("Error: invalid input bounds");
+ return -1;
+ }
+ taskResize(taskId, bounds, 0, false);
+ return 0;
+ }
+
+ void taskResize(int taskId, Rect bounds, int delay_ms, boolean pretendUserResize)
+ throws RemoteException {
+ final int resizeMode = pretendUserResize ? RESIZE_MODE_USER : RESIZE_MODE_SYSTEM;
+ mInterface.resizeTask(taskId, bounds, resizeMode);
+ try {
+ Thread.sleep(delay_ms);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ int runTaskDragTaskTest(PrintWriter pw) throws RemoteException {
+ final int taskId = Integer.parseInt(getNextArgRequired());
+ final int stepSize = Integer.parseInt(getNextArgRequired());
+ final String delayStr = getNextArg();
+ final int delay_ms = (delayStr != null) ? Integer.parseInt(delayStr) : 0;
+ final ActivityManager.StackInfo stackInfo;
+ Rect taskBounds;
+ stackInfo = mInterface.getStackInfo(mInterface.getFocusedStackId());
+ taskBounds = mInterface.getTaskBounds(taskId);
+ final Rect stackBounds = stackInfo.bounds;
+ int travelRight = stackBounds.width() - taskBounds.width();
+ int travelLeft = -travelRight;
+ int travelDown = stackBounds.height() - taskBounds.height();
+ int travelUp = -travelDown;
+ int passes = 0;
+
+ // We do 2 passes to get back to the original location of the task.
+ while (passes < 2) {
+ // Move right
+ pw.println("Moving right...");
+ pw.flush();
+ travelRight = moveTask(taskId, taskBounds, stackBounds, stepSize,
+ travelRight, MOVING_FORWARD, MOVING_HORIZONTALLY, delay_ms);
+ pw.println("Still need to travel right by " + travelRight);
+
+ // Move down
+ pw.println("Moving down...");
+ pw.flush();
+ travelDown = moveTask(taskId, taskBounds, stackBounds, stepSize,
+ travelDown, MOVING_FORWARD, !MOVING_HORIZONTALLY, delay_ms);
+ pw.println("Still need to travel down by " + travelDown);
+
+ // Move left
+ pw.println("Moving left...");
+ pw.flush();
+ travelLeft = moveTask(taskId, taskBounds, stackBounds, stepSize,
+ travelLeft, !MOVING_FORWARD, MOVING_HORIZONTALLY, delay_ms);
+ pw.println("Still need to travel left by " + travelLeft);
+
+ // Move up
+ pw.println("Moving up...");
+ pw.flush();
+ travelUp = moveTask(taskId, taskBounds, stackBounds, stepSize,
+ travelUp, !MOVING_FORWARD, !MOVING_HORIZONTALLY, delay_ms);
+ pw.println("Still need to travel up by " + travelUp);
+
+ taskBounds = mInterface.getTaskBounds(taskId);
+ passes++;
+ }
+ return 0;
+ }
+
+ int moveTask(int taskId, Rect taskRect, Rect stackRect, int stepSize,
+ int maxToTravel, boolean movingForward, boolean horizontal, int delay_ms)
+ throws RemoteException {
+ int maxMove;
+ if (movingForward) {
+ while (maxToTravel > 0
+ && ((horizontal && taskRect.right < stackRect.right)
+ ||(!horizontal && taskRect.bottom < stackRect.bottom))) {
+ if (horizontal) {
+ maxMove = Math.min(stepSize, stackRect.right - taskRect.right);
+ maxToTravel -= maxMove;
+ taskRect.right += maxMove;
+ taskRect.left += maxMove;
+ } else {
+ maxMove = Math.min(stepSize, stackRect.bottom - taskRect.bottom);
+ maxToTravel -= maxMove;
+ taskRect.top += maxMove;
+ taskRect.bottom += maxMove;
+ }
+ taskResize(taskId, taskRect, delay_ms, false);
+ }
+ } else {
+ while (maxToTravel < 0
+ && ((horizontal && taskRect.left > stackRect.left)
+ ||(!horizontal && taskRect.top > stackRect.top))) {
+ if (horizontal) {
+ maxMove = Math.min(stepSize, taskRect.left - stackRect.left);
+ maxToTravel -= maxMove;
+ taskRect.right -= maxMove;
+ taskRect.left -= maxMove;
+ } else {
+ maxMove = Math.min(stepSize, taskRect.top - stackRect.top);
+ maxToTravel -= maxMove;
+ taskRect.top -= maxMove;
+ taskRect.bottom -= maxMove;
+ }
+ taskResize(taskId, taskRect, delay_ms, false);
+ }
+ }
+ // Return the remaining distance we didn't travel because we reached the target location.
+ return maxToTravel;
+ }
+
+ int getStepSize(int current, int target, int inStepSize, boolean greaterThanTarget) {
+ int stepSize = 0;
+ if (greaterThanTarget && target < current) {
+ current -= inStepSize;
+ stepSize = inStepSize;
+ if (target > current) {
+ stepSize -= (target - current);
+ }
+ }
+ if (!greaterThanTarget && target > current) {
+ current += inStepSize;
+ stepSize = inStepSize;
+ if (target < current) {
+ stepSize += (current - target);
+ }
+ }
+ return stepSize;
+ }
+
+ int runTaskSizeTaskTest(PrintWriter pw) throws RemoteException {
+ final int taskId = Integer.parseInt(getNextArgRequired());
+ final int stepSize = Integer.parseInt(getNextArgRequired());
+ final String delayStr = getNextArg();
+ final int delay_ms = (delayStr != null) ? Integer.parseInt(delayStr) : 0;
+ final ActivityManager.StackInfo stackInfo;
+ final Rect initialTaskBounds;
+ stackInfo = mInterface.getStackInfo(mInterface.getFocusedStackId());
+ initialTaskBounds = mInterface.getTaskBounds(taskId);
+ final Rect stackBounds = stackInfo.bounds;
+ stackBounds.inset(STACK_BOUNDS_INSET, STACK_BOUNDS_INSET);
+ final Rect currentTaskBounds = new Rect(initialTaskBounds);
+
+ // Size by top-left
+ pw.println("Growing top-left");
+ pw.flush();
+ do {
+ currentTaskBounds.top -= getStepSize(
+ currentTaskBounds.top, stackBounds.top, stepSize, GREATER_THAN_TARGET);
+
+ currentTaskBounds.left -= getStepSize(
+ currentTaskBounds.left, stackBounds.left, stepSize, GREATER_THAN_TARGET);
+
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
+ } while (stackBounds.top < currentTaskBounds.top
+ || stackBounds.left < currentTaskBounds.left);
+
+ // Back to original size
+ pw.println("Shrinking top-left");
+ pw.flush();
+ do {
+ currentTaskBounds.top += getStepSize(
+ currentTaskBounds.top, initialTaskBounds.top, stepSize, !GREATER_THAN_TARGET);
+
+ currentTaskBounds.left += getStepSize(
+ currentTaskBounds.left, initialTaskBounds.left, stepSize, !GREATER_THAN_TARGET);
+
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
+ } while (initialTaskBounds.top > currentTaskBounds.top
+ || initialTaskBounds.left > currentTaskBounds.left);
+
+ // Size by top-right
+ pw.println("Growing top-right");
+ pw.flush();
+ do {
+ currentTaskBounds.top -= getStepSize(
+ currentTaskBounds.top, stackBounds.top, stepSize, GREATER_THAN_TARGET);
+
+ currentTaskBounds.right += getStepSize(
+ currentTaskBounds.right, stackBounds.right, stepSize, !GREATER_THAN_TARGET);
+
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
+ } while (stackBounds.top < currentTaskBounds.top
+ || stackBounds.right > currentTaskBounds.right);
+
+ // Back to original size
+ pw.println("Shrinking top-right");
+ pw.flush();
+ do {
+ currentTaskBounds.top += getStepSize(
+ currentTaskBounds.top, initialTaskBounds.top, stepSize, !GREATER_THAN_TARGET);
+
+ currentTaskBounds.right -= getStepSize(currentTaskBounds.right, initialTaskBounds.right,
+ stepSize, GREATER_THAN_TARGET);
+
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
+ } while (initialTaskBounds.top > currentTaskBounds.top
+ || initialTaskBounds.right < currentTaskBounds.right);
+
+ // Size by bottom-left
+ pw.println("Growing bottom-left");
+ pw.flush();
+ do {
+ currentTaskBounds.bottom += getStepSize(
+ currentTaskBounds.bottom, stackBounds.bottom, stepSize, !GREATER_THAN_TARGET);
+
+ currentTaskBounds.left -= getStepSize(
+ currentTaskBounds.left, stackBounds.left, stepSize, GREATER_THAN_TARGET);
+
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
+ } while (stackBounds.bottom > currentTaskBounds.bottom
+ || stackBounds.left < currentTaskBounds.left);
+
+ // Back to original size
+ pw.println("Shrinking bottom-left");
+ pw.flush();
+ do {
+ currentTaskBounds.bottom -= getStepSize(currentTaskBounds.bottom,
+ initialTaskBounds.bottom, stepSize, GREATER_THAN_TARGET);
+
+ currentTaskBounds.left += getStepSize(
+ currentTaskBounds.left, initialTaskBounds.left, stepSize, !GREATER_THAN_TARGET);
+
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
+ } while (initialTaskBounds.bottom < currentTaskBounds.bottom
+ || initialTaskBounds.left > currentTaskBounds.left);
+
+ // Size by bottom-right
+ pw.println("Growing bottom-right");
+ pw.flush();
+ do {
+ currentTaskBounds.bottom += getStepSize(
+ currentTaskBounds.bottom, stackBounds.bottom, stepSize, !GREATER_THAN_TARGET);
+
+ currentTaskBounds.right += getStepSize(
+ currentTaskBounds.right, stackBounds.right, stepSize, !GREATER_THAN_TARGET);
+
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
+ } while (stackBounds.bottom > currentTaskBounds.bottom
+ || stackBounds.right > currentTaskBounds.right);
+
+ // Back to original size
+ pw.println("Shrinking bottom-right");
+ pw.flush();
+ do {
+ currentTaskBounds.bottom -= getStepSize(currentTaskBounds.bottom,
+ initialTaskBounds.bottom, stepSize, GREATER_THAN_TARGET);
+
+ currentTaskBounds.right -= getStepSize(currentTaskBounds.right, initialTaskBounds.right,
+ stepSize, GREATER_THAN_TARGET);
+
+ taskResize(taskId, currentTaskBounds, delay_ms, true);
+ } while (initialTaskBounds.bottom < currentTaskBounds.bottom
+ || initialTaskBounds.right < currentTaskBounds.right);
+ return 0;
+ }
+
+ int runWrite(PrintWriter pw) {
+ mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+ "registerUidObserver()");
+ mInternal.mRecentTasks.flush();
+ pw.println("All tasks persisted.");
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -497,43 +2501,189 @@
} else {
pw.println("Activity manager (activity) commands:");
pw.println(" help");
- pw.println(" Print this help text.");
+ pw.println(" Print this help text.");
pw.println(" start-activity [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]");
pw.println(" [--sampling INTERVAL] [-R COUNT] [-S]");
pw.println(" [--track-allocation] [--user <USER_ID> | current] <INTENT>");
- pw.println(" Start an Activity. Options are:");
- pw.println(" -D: enable debugging");
- pw.println(" -N: enable native debugging");
- pw.println(" -W: wait for launch to complete");
- pw.println(" --start-profiler <FILE>: start profiler and send results to <FILE>");
- pw.println(" --sampling INTERVAL: use sample profiling with INTERVAL microseconds");
- pw.println(" between samples (use with --start-profiler)");
- pw.println(" -P <FILE>: like above, but profiling stops when app goes idle");
- pw.println(" -R: repeat the activity launch <COUNT> times. Prior to each repeat,");
- pw.println(" the top activity will be finished.");
- pw.println(" -S: force stop the target app before starting the activity");
- pw.println(" --track-allocation: enable tracking of object allocations");
- pw.println(" --user <USER_ID> | current: Specify which user to run as; if not");
- pw.println(" specified then run as the current user.");
- pw.println(" --stack <STACK_ID>: Specify into which stack should the activity be put.");
+ pw.println(" Start an Activity. Options are:");
+ pw.println(" -D: enable debugging");
+ pw.println(" -N: enable native debugging");
+ pw.println(" -W: wait for launch to complete");
+ pw.println(" --start-profiler <FILE>: start profiler and send results to <FILE>");
+ pw.println(" --sampling INTERVAL: use sample profiling with INTERVAL microseconds");
+ pw.println(" between samples (use with --start-profiler)");
+ pw.println(" -P <FILE>: like above, but profiling stops when app goes idle");
+ pw.println(" -R: repeat the activity launch <COUNT> times. Prior to each repeat,");
+ pw.println(" the top activity will be finished.");
+ pw.println(" -S: force stop the target app before starting the activity");
+ pw.println(" --track-allocation: enable tracking of object allocations");
+ pw.println(" --user <USER_ID> | current: Specify which user to run as; if not");
+ pw.println(" specified then run as the current user.");
+ pw.println(" --stack <STACK_ID>: Specify into which stack should the activity be put.");
+ pw.println(" start-service [--user <USER_ID> | current] <INTENT>");
+ pw.println(" Start a Service. Options are:");
+ pw.println(" --user <USER_ID> | current: Specify which user to run as; if not");
+ pw.println(" specified then run as the current user.");
+ pw.println(" stop-service [--user <USER_ID> | current] <INTENT>");
+ pw.println(" Stop a Service. Options are:");
+ pw.println(" --user <USER_ID> | current: Specify which user to run as; if not");
+ pw.println(" specified then run as the current user.");
+ pw.println(" broadcast [--user <USER_ID> | all | current] <INTENT>");
+ pw.println(" Send a broadcast Intent. Options are:");
+ pw.println(" --user <USER_ID> | all | current: Specify which user to send to; if not");
+ pw.println(" specified then send to all users.");
+ pw.println(" --receiver-permission <PERMISSION>: Require receiver to hold permission.");
+ pw.println(" trace-ipc [start|stop] [--dump-file <FILE>]");
+ pw.println(" Trace IPC transactions.");
+ pw.println(" start: start tracing IPC transactions.");
+ pw.println(" stop: stop tracing IPC transactions and dump the results to file.");
+ pw.println(" --dump-file <FILE>: Specify the file the trace should be dumped to.");
+ pw.println(" profile [start|stop] [--user <USER_ID> current] [--sampling INTERVAL]");
+ pw.println(" <PROCESS> <FILE>");
+ pw.println(" Start and stop profiler on a process. The given <PROCESS> argument");
+ pw.println(" may be either a process name or pid. Options are:");
+ pw.println(" --user <USER_ID> | current: When supplying a process name,");
+ pw.println(" specify user of process to profile; uses current user if not specified.");
+ pw.println(" dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>");
+ pw.println(" Dump the heap of a process. The given <PROCESS> argument may");
+ pw.println(" be either a process name or pid. Options are:");
+ pw.println(" -n: dump native heap instead of managed heap");
+ pw.println(" --user <USER_ID> | current: When supplying a process name,");
+ pw.println(" specify user of process to dump; uses current user if not specified.");
+ pw.println(" set-debug-app [-w] [--persistent] <PACKAGE>");
+ pw.println(" Set application <PACKAGE> to debug. Options are:");
+ pw.println(" -w: wait for debugger when application starts");
+ pw.println(" --persistent: retain this value");
+ pw.println(" clear-debug-app");
+ pw.println(" Clear the previously set-debug-app.");
+ pw.println(" set-watch-heap <PROCESS> <MEM-LIMIT>");
+ pw.println(" Start monitoring pss size of <PROCESS>, if it is at or");
+ pw.println(" above <HEAP-LIMIT> then a heap dump is collected for the user to report.");
+ pw.println(" clear-watch-heap");
+ pw.println(" Clear the previously set-watch-heap.");
+ pw.println(" bug-report [--progress]");
+ pw.println(" Request bug report generation; will launch a notification");
+ pw.println(" when done to select where it should be delivered. Options are:");
+ pw.println(" --progress: will launch a notification right away to show its progress.");
pw.println(" force-stop [--user <USER_ID> | all | current] <PACKAGE>");
- pw.println(" Completely stop the given application package.");
+ pw.println(" Completely stop the given application package.");
pw.println(" kill [--user <USER_ID> | all | current] <PACKAGE>");
- pw.println(" Kill all processes associated with the given application.");
+ pw.println(" Kill all processes associated with the given application.");
pw.println(" kill-all");
- pw.println(" Kill all processes that are safe to kill (cached, etc).");
- pw.println(" write");
- pw.println(" Write all pending state to storage.");
- pw.println(" track-associations");
- pw.println(" Enable association tracking.");
- pw.println(" untrack-associations");
- pw.println(" Disable and clear association tracking.");
+ pw.println(" Kill all processes that are safe to kill (cached, etc).");
+ pw.println(" monitor [--gdb <port>]");
+ pw.println(" Start monitoring for crashes or ANRs.");
+ pw.println(" --gdb: start gdbserv on the given port at crash/ANR");
+ pw.println(" hang [--allow-restart]");
+ pw.println(" Hang the system.");
+ pw.println(" --allow-restart: allow watchdog to perform normal system restart");
+ pw.println(" restart");
+ pw.println(" Restart the user-space system.");
+ pw.println(" idle-maintenance");
+ pw.println(" Perform idle maintenance now.");
+ pw.println(" screen-compat [on|off] <PACKAGE>");
+ pw.println(" Control screen compatibility mode of <PACKAGE>.");
+ pw.println(" package-importance <PACKAGE>");
+ pw.println(" Print current importance of <PACKAGE>.");
+ pw.println(" to-uri [INTENT]");
+ pw.println(" Print the given Intent specification as a URI.");
+ pw.println(" to-intent-uri [INTENT]");
+ pw.println(" Print the given Intent specification as an intent: URI.");
+ pw.println(" to-app-uri [INTENT]");
+ pw.println(" Print the given Intent specification as an android-app: URI.");
+ pw.println(" switch-user <USER_ID>");
+ pw.println(" Switch to put USER_ID in the foreground, starting");
+ pw.println(" execution of that user if it is currently stopped.");
+ pw.println(" get-current-user");
+ pw.println(" Returns id of the current foreground user.");
+ pw.println(" start-user <USER_ID>");
+ pw.println(" Start USER_ID in background if it is currently stopped;");
+ pw.println(" use switch-user if you want to start the user in foreground");
+ pw.println(" unlock-user <USER_ID> [TOKEN_HEX]");
+ pw.println(" Attempt to unlock the given user using the given authorization token.");
+ pw.println(" stop-user [-w] [-f] <USER_ID>");
+ pw.println(" Stop execution of USER_ID, not allowing it to run any");
+ pw.println(" code until a later explicit start or switch to it.");
+ pw.println(" -w: wait for stop-user to complete.");
+ pw.println(" -f: force stop even if there are related users that cannot be stopped.");
pw.println(" is-user-stopped <USER_ID>");
- pw.println(" Returns whether <USER_ID> has been stopped or not.");
+ pw.println(" Returns whether <USER_ID> has been stopped or not.");
+ pw.println(" get-started-user-state <USER_ID>");
+ pw.println(" Gets the current state of the given started user.");
+ pw.println(" track-associations");
+ pw.println(" Enable association tracking.");
+ pw.println(" untrack-associations");
+ pw.println(" Disable and clear association tracking.");
pw.println(" lenient-background-check [<true|false>]");
- pw.println(" Optionally controls lenient background check mode, returns current mode.");
+ pw.println(" Optionally controls lenient background check mode, returns current mode.");
pw.println(" get-uid-state <UID>");
- pw.println(" Gets the process state of an app given its <UID>.");
+ pw.println(" Gets the process state of an app given its <UID>.");
+ pw.println(" get-config");
+ pw.println(" Rtrieve the configuration and any recent configurations of the device.");
+ pw.println(" suppress-resize-config-changes <true|false>");
+ pw.println(" Suppresses configuration changes due to user resizing an activity/task.");
+ pw.println(" set-inactive [--user <USER_ID>] <PACKAGE> true|false");
+ pw.println(" Sets the inactive state of an app.");
+ pw.println(" get-inactive [--user <USER_ID>] <PACKAGE>");
+ pw.println(" Returns the inactive state of an app.");
+ pw.println(" send-trim-memory [--user <USER_ID>] <PROCESS>");
+ pw.println(" [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]");
+ pw.println(" Send a memory trim event to a <PROCESS>.");
+ pw.println(" stack [COMMAND] [...]: sub-commands for operating on activity stacks.");
+ pw.println(" start <DISPLAY_ID> <INTENT>");
+ pw.println(" Start a new activity on <DISPLAY_ID> using <INTENT>");
+ pw.println(" movetask <TASK_ID> <STACK_ID> [true|false]");
+ pw.println(" Move <TASK_ID> from its current stack to the top (true) or");
+ pw.println(" bottom (false) of <STACK_ID>.");
+ pw.println(" resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>");
+ pw.println(" Change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.");
+ pw.println(" resize-animated <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>");
+ pw.println(" Same as resize, but allow animation.");
+ pw.println(" resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]");
+ pw.println(" Change docked stack to <LEFT,TOP,RIGHT,BOTTOM>");
+ pw.println(" and supplying temporary different task bounds indicated by");
+ pw.println(" <TASK_LEFT,TOP,RIGHT,BOTTOM>");
+ pw.println(" size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]");
+ pw.println(" Test command for sizing docked stack by");
+ pw.println(" <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom");
+ pw.println(" applying the optional [DELAY_MS] between each step.");
+ pw.println(" move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>");
+ pw.println(" Moves the top activity from");
+ pw.println(" <STACK_ID> to the pinned stack using <LEFT,TOP,RIGHT,BOTTOM> for the");
+ pw.println(" bounds of the pinned stack.");
+ pw.println(" positiontask <TASK_ID> <STACK_ID> <POSITION>");
+ pw.println(" Place <TASK_ID> in <STACK_ID> at <POSITION>");
+ pw.println(" list");
+ pw.println(" List all of the activity stacks and their sizes.");
+ pw.println(" info <STACK_ID>");
+ pw.println(" Display the information about activity stack <STACK_ID>.");
+ pw.println(" remove <STACK_ID>");
+ pw.println(" Remove stack <STACK_ID>.");
+ pw.println(" task [COMMAND] [...]: sub-commands for operating on activity tasks.");
+ pw.println(" lock <TASK_ID>");
+ pw.println(" Bring <TASK_ID> to the front and don't allow other tasks to run.");
+ pw.println(" lock stop");
+ pw.println(" End the current task lock.");
+ pw.println(" resizeable <TASK_ID> [0|1|2|3]");
+ pw.println(" Change resizeable mode of <TASK_ID> to one of the following:");
+ pw.println(" 0: unresizeable");
+ pw.println(" 1: crop_windows");
+ pw.println(" 2: resizeable");
+ pw.println(" 3: resizeable_and_pipable");
+ pw.println(" resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>");
+ pw.println(" Makes sure <TASK_ID> is in a stack with the specified bounds.");
+ pw.println(" Forces the task to be resizeable and creates a stack if no existing stack");
+ pw.println(" has the specified bounds.");
+ pw.println(" drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS]");
+ pw.println(" Test command for dragging/moving <TASK_ID> by");
+ pw.println(" <STEP_SIZE> increments around the screen applying the optional [DELAY_MS]");
+ pw.println(" between each step.");
+ pw.println(" size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS]");
+ pw.println(" Test command for sizing <TASK_ID> by <STEP_SIZE>");
+ pw.println(" increments within the screen applying the optional [DELAY_MS] between");
+ pw.println(" each step.");
+ pw.println(" write");
+ pw.println(" Write all pending state to storage.");
pw.println();
Intent.printIntentArgsHelp(pw, "");
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index e52671f..d89f02d 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -20,22 +20,38 @@
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.content.pm.ActivityInfo.FLAG_ON_TOP_LAUNCHER;
+import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
+import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
+import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SCREENSHOTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_THUMBNAILS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SCREENSHOTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_THUMBNAILS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS;
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import android.annotation.NonNull;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityOptions;
import android.app.PendingIntent;
@@ -50,6 +66,7 @@
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
+import android.os.Debug;
import android.os.IBinder;
import android.os.Message;
import android.os.PersistableBundle;
@@ -81,6 +98,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.List;
import java.util.Objects;
import org.xmlpull.v1.XmlPullParser;
@@ -92,12 +110,16 @@
*/
final class ActivityRecord {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
+ private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+ private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
+ private static final String TAG_SCREENSHOTS = TAG + POSTFIX_SCREENSHOTS;
private static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_THUMBNAILS = TAG + POSTFIX_THUMBNAILS;
+ private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
private static final boolean SHOW_ACTIVITY_START_TIME = true;
- final public static String RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
+ private static final String RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
private static final String ATTR_ID = "id";
private static final String TAG_INTENT = "intent";
@@ -150,11 +172,11 @@
long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity
long pauseTime; // last time we started pausing the activity
long launchTickTime; // base time for launch tick messages
- Configuration configuration; // configuration activity was last running in
+ private Configuration mLastReportedConfiguration; // configuration activity was last running in
// Overridden configuration by the activity task
- // WARNING: Reference points to {@link TaskRecord#mOverrideConfig}, so its internal state
- // should never be altered directly.
- Configuration taskConfigOverride;
+ // WARNING: Reference points to {@link TaskRecord#getMergedOverrideConfig}, so its internal
+ // state should never be altered directly.
+ private Configuration mLastReportedOverrideConfiguration;
CompatibilityInfo compat;// last used compatibility mode
ActivityRecord resultTo; // who started this entry, so will get our reply
final String resultWho; // additional identifier for use by resultTo.
@@ -231,6 +253,12 @@
// on the window.
int mRotationAnimationHint = -1;
+ /**
+ * Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)}
+ */
+ private final Configuration mTmpGlobalConfig = new Configuration();
+ private final Configuration mTmpTaskConfig = new Configuration();
+
private static String startingWindowStateToString(int state) {
switch (state) {
case STARTING_WINDOW_NOT_SHOWN:
@@ -279,8 +307,10 @@
pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes));
pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
- pw.print(prefix); pw.print("config="); pw.println(configuration);
- pw.print(prefix); pw.print("taskConfigOverride="); pw.println(taskConfigOverride);
+ pw.print(prefix); pw.print("mLastReportedConfiguration=");
+ pw.println(mLastReportedConfiguration);
+ pw.print(prefix); pw.print("mLastReportedOverrideConfiguration=");
+ pw.println(mLastReportedOverrideConfiguration);
if (resultTo != null || resultWho != null) {
pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
pw.print(" resultWho="); pw.print(resultWho);
@@ -401,15 +431,15 @@
}
}
- public boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
+ private boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
return crossesSizeThreshold(mHorizontalSizeConfigurations, firstDp, secondDp);
}
- public boolean crossesVerticalSizeThreshold(int firstDp, int secondDp) {
+ private boolean crossesVerticalSizeThreshold(int firstDp, int secondDp) {
return crossesSizeThreshold(mVerticalSizeConfigurations, firstDp, secondDp);
}
- public boolean crossesSmallestSizeThreshold(int firstDp, int secondDp) {
+ private boolean crossesSmallestSizeThreshold(int firstDp, int secondDp) {
return crossesSizeThreshold(mSmallestSizeConfigurations, firstDp, secondDp);
}
@@ -442,14 +472,14 @@
return false;
}
- public void setSizeConfigurations(int[] horizontalSizeConfiguration,
+ void setSizeConfigurations(int[] horizontalSizeConfiguration,
int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
mHorizontalSizeConfigurations = horizontalSizeConfiguration;
mVerticalSizeConfigurations = verticalSizeConfigurations;
mSmallestSizeConfigurations = smallestSizeConfigurations;
}
- void scheduleConfigurationChanged(Configuration config, boolean reportToActivity) {
+ private void scheduleConfigurationChanged(Configuration config, boolean reportToActivity) {
if (app == null || app.thread == null) {
return;
}
@@ -457,14 +487,15 @@
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + " " +
"reportToActivity=" + reportToActivity + " and config: " + config);
- app.thread.scheduleActivityConfigurationChanged(appToken, config, reportToActivity);
+ app.thread.scheduleActivityConfigurationChanged(appToken, new Configuration(config),
+ reportToActivity);
} catch (RemoteException e) {
// If process died, whatever.
}
}
void scheduleMultiWindowModeChanged() {
- if (task == null || task.stack == null || app == null || app.thread == null) {
+ if (task == null || task.getStack() == null || app == null || app.thread == null) {
return;
}
try {
@@ -476,20 +507,19 @@
}
void schedulePictureInPictureModeChanged() {
- if (task == null || task.stack == null || app == null || app.thread == null) {
+ if (task == null || task.getStack() == null || app == null || app.thread == null) {
return;
}
try {
app.thread.schedulePictureInPictureModeChanged(
- appToken, task.stack.mStackId == PINNED_STACK_ID);
+ appToken, task.getStackId() == PINNED_STACK_ID);
} catch (Exception e) {
// If process died, no one cares.
}
}
boolean isFreeform() {
- return task != null && task.stack != null
- && task.stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+ return task != null && task.getStackId() == FREEFORM_WORKSPACE_STACK_ID;
}
static class Token extends IApplicationToken.Stub {
@@ -528,7 +558,6 @@
if (r != null) {
if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + r);
r.nowVisible = false;
- return;
}
}
}
@@ -544,7 +573,7 @@
return false;
}
anrActivity = r.getWaitingHistoryRecordLocked();
- anrApp = r != null ? r.app : null;
+ anrApp = r.app;
}
return mService.inputDispatchingTimedOut(anrApp, anrActivity, r, false, reason);
}
@@ -561,12 +590,12 @@
}
}
- private static final ActivityRecord tokenToActivityRecordLocked(Token token) {
+ private static ActivityRecord tokenToActivityRecordLocked(Token token) {
if (token == null) {
return null;
}
ActivityRecord r = token.weakActivity.get();
- if (r == null || r.task == null || r.task.stack == null) {
+ if (r == null || r.getStack() == null) {
return null;
}
return r;
@@ -615,8 +644,8 @@
resolvedType = _resolvedType;
componentSpecified = _componentSpecified;
rootVoiceInteraction = _rootVoiceInteraction;
- configuration = _configuration;
- taskConfigOverride = Configuration.EMPTY;
+ mLastReportedConfiguration = new Configuration(_configuration);
+ mLastReportedOverrideConfiguration = new Configuration();
resultTo = _resultTo;
resultWho = _resultWho;
requestCode = _reqCode;
@@ -769,6 +798,12 @@
&& isHomeIntent(intent) && !isResolverActivity()) {
// This sure looks like a home activity!
mActivityType = HOME_ACTIVITY_TYPE;
+
+ if (info.resizeMode == RESIZE_MODE_FORCE_RESIZEABLE
+ || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
+ // We only allow home activities to be resizeable if they explicitly requested it.
+ info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
+ }
} else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
mActivityType = RECENTS_ACTIVITY_TYPE;
} else {
@@ -777,8 +812,9 @@
}
void setTask(TaskRecord newTask, TaskRecord taskToAffiliateWith) {
- if (task != null && task.removeActivity(this) && task != newTask && task.stack != null) {
- task.stack.removeTask(task, "setTask");
+ if (task != null && task.removeActivity(this) && task != newTask
+ && task.getStack() != null) {
+ task.getStack().removeTask(task, "setTask");
}
task = newTask;
setTaskToAffiliateWith(taskToAffiliateWith);
@@ -792,6 +828,13 @@
}
}
+ /**
+ * @return Stack value from current task, null if there is no task.
+ */
+ ActivityStack getStack() {
+ return task != null ? task.getStack() : null;
+ }
+
boolean changeWindowTranslucency(boolean toOpaque) {
if (fullscreen == toOpaque) {
return false;
@@ -825,7 +868,8 @@
}
boolean isInStackLocked() {
- return task != null && task.stack != null && task.stack.isInStackLocked(this) != null;
+ final ActivityStack stack = getStack();
+ return stack != null && stack.isInStackLocked(this) != null;
}
boolean isHomeActivity() {
@@ -848,11 +892,11 @@
}
boolean isFocusable() {
- return StackId.canReceiveKeys(task.stack.mStackId) || isAlwaysFocusable();
+ return StackId.canReceiveKeys(task.getStackId()) || isAlwaysFocusable();
}
boolean isResizeable() {
- return !isHomeActivity() && ActivityInfo.isResizeableMode(info.resizeMode);
+ return ActivityInfo.isResizeableMode(info.resizeMode);
}
boolean isResizeableOrForced() {
@@ -860,8 +904,9 @@
}
boolean isNonResizableOrForced() {
- return !isHomeActivity() && info.resizeMode != RESIZE_MODE_RESIZEABLE
- && info.resizeMode != RESIZE_MODE_RESIZEABLE_AND_PIPABLE;
+ return info.resizeMode != RESIZE_MODE_RESIZEABLE
+ && info.resizeMode != RESIZE_MODE_RESIZEABLE_AND_PIPABLE
+ && info.resizeMode != RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
}
boolean supportsPictureInPicture() {
@@ -869,22 +914,17 @@
}
boolean canGoInDockedStack() {
- return !isHomeActivity()
- && (isResizeableOrForced() || info.resizeMode == RESIZE_MODE_CROP_WINDOWS);
+ return !isHomeActivity() && isResizeableOrForced();
}
boolean isAlwaysFocusable() {
return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
}
- boolean isOnTopLauncher() {
- return isHomeActivity() && (info.flags & FLAG_ON_TOP_LAUNCHER) != 0;
- }
-
void makeFinishingLocked() {
if (!finishing) {
- if (task != null && task.stack != null
- && this == task.stack.getVisibleBehindActivity()) {
+ final ActivityStack stack = getStack();
+ if (stack != null && this == stack.getVisibleBehindActivity()) {
// A finishing activity should not remain as visible in the background
mStackSupervisor.requestVisibleBehindLocked(this, false);
}
@@ -931,7 +971,7 @@
}
}
- void addNewIntentLocked(ReferrerIntent intent) {
+ private void addNewIntentLocked(ReferrerIntent intent) {
if (newIntents == null) {
newIntents = new ArrayList<>();
}
@@ -948,7 +988,7 @@
intent, getUriPermissionsLocked(), userId);
final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
boolean unsent = true;
- final ActivityStack stack = task.stack;
+ final ActivityStack stack = getStack();
final boolean isTopActivityInStack =
stack != null && stack.topRunningActivityLocked() == this;
final boolean isTopActivityWhileSleeping =
@@ -1112,12 +1152,251 @@
"Setting thumbnail of " + this + " to " + newThumbnail);
boolean thumbnailUpdated = task.setLastThumbnailLocked(newThumbnail);
if (thumbnailUpdated && isPersistable()) {
- mStackSupervisor.mService.notifyTaskPersisterLocked(task, false);
+ service.notifyTaskPersisterLocked(task, false);
}
}
task.lastDescription = description;
}
+ final Bitmap screenshotActivityLocked() {
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "screenshotActivityLocked: " + this);
+ if (noDisplay) {
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tNo display");
+ return null;
+ }
+
+ final ActivityStack stack = getStack();
+ if (stack.isHomeStack()) {
+ // This is an optimization -- since we never show Home or Recents within Recents itself,
+ // we can just go ahead and skip taking the screenshot if this is the home stack.
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tHome stack");
+ return null;
+ }
+
+ int w = service.mThumbnailWidth;
+ int h = service.mThumbnailHeight;
+
+ if (w <= 0) {
+ Slog.e(TAG, "\tInvalid thumbnail dimensions: " + w + "x" + h);
+ return null;
+ }
+
+ if (stack.mStackId == DOCKED_STACK_ID && mStackSupervisor.mIsDockMinimized) {
+ // When the docked stack is minimized its app windows are cropped significantly so any
+ // screenshot taken will not display the apps contain. So, we avoid taking a screenshot
+ // in that case.
+ if (DEBUG_SCREENSHOTS) Slog.e(TAG, "\tIn minimized docked stack");
+ return null;
+ }
+
+ final float scale;
+ if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
+
+ // When this flag is set, we currently take the fullscreen screenshot of the activity but
+ // scaled to half the size. This gives us a "good-enough" fullscreen thumbnail to use within
+ // SystemUI while keeping memory usage low.
+ if (TAKE_FULLSCREEN_SCREENSHOTS) {
+ w = h = -1;
+ scale = service.mFullscreenThumbnailScale;
+ }
+
+ return service.mWindowManager.screenshotApplications(appToken, DEFAULT_DISPLAY, w, h,
+ scale);
+ }
+
+ void setVisible(boolean newVisible) {
+ visible = newVisible;
+ if (!visible && mUpdateTaskThumbnailWhenHidden) {
+ updateThumbnailLocked(screenshotActivityLocked(), null /* description */);
+ mUpdateTaskThumbnailWhenHidden = false;
+ }
+ service.mWindowManager.setAppVisibility(appToken, visible);
+ final ArrayList<ActivityContainer> containers = mChildContainers;
+ for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
+ final ActivityContainer container = containers.get(containerNdx);
+ container.setVisible(visible);
+ }
+ mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
+ }
+
+ /** Return true if the input activity should be made visible */
+ boolean shouldBeVisible(boolean behindTranslucentActivity, boolean stackVisibleBehind,
+ ActivityRecord visibleBehind, boolean behindFullscreenActivity) {
+ if (!okToShowLocked()) {
+ return false;
+ }
+
+ // mLaunchingBehind: Activities launching behind are at the back of the task stack
+ // but must be drawn initially for the animation as though they were visible.
+ final boolean activityVisibleBehind =
+ (behindTranslucentActivity || stackVisibleBehind) && visibleBehind == this;
+
+ boolean isVisible =
+ !behindFullscreenActivity || mLaunchTaskBehind || activityVisibleBehind;
+
+ if (service.mSupportsLeanbackOnly && isVisible && isRecentsActivity()) {
+ // On devices that support leanback only (Android TV), Recents activity can only be
+ // visible if the home stack is the focused stack or we are in split-screen mode.
+ isVisible = mStackSupervisor.getStack(DOCKED_STACK_ID) != null
+ || mStackSupervisor.isFocusedStack(getStack());
+ }
+
+ return isVisible;
+ }
+
+ void makeVisibleIfNeeded(ActivityRecord starting) {
+ // This activity is not currently visible, but is running. Tell it to become visible.
+ if (state == ActivityState.RESUMED || this == starting) {
+ if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
+ "Not making visible, r=" + this + " state=" + state + " starting=" + starting);
+ return;
+ }
+
+ // If this activity is paused, tell it to now show its window.
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+ "Making visible and scheduling visibility: " + this);
+ final ActivityStack stack = getStack();
+ try {
+ if (stack.mTranslucentActivityWaiting != null) {
+ updateOptionsLocked(returningOptions);
+ stack.mUndrawnActivitiesBelowTopTranslucent.add(this);
+ }
+ setVisible(true);
+ sleeping = false;
+ app.pendingUiClean = true;
+ app.thread.scheduleWindowVisibility(appToken, true /* showWindow */);
+ // The activity may be waiting for stop, but that is no longer appropriate for it.
+ mStackSupervisor.mStoppingActivities.remove(this);
+ mStackSupervisor.mGoingToSleepActivities.remove(this);
+ } catch (Exception e) {
+ // Just skip on any failure; we'll make it visible when it next restarts.
+ Slog.w(TAG, "Exception thrown making visibile: " + intent.getComponent(), e);
+ }
+ handleAlreadyVisible();
+ }
+
+ boolean handleAlreadyVisible() {
+ stopFreezingScreenLocked(false);
+ try {
+ if (returningOptions != null) {
+ app.thread.scheduleOnNewActivityOptions(appToken, returningOptions);
+ }
+ } catch(RemoteException e) {
+ }
+ return state == ActivityState.RESUMED;
+ }
+
+ static void activityResumedLocked(IBinder token) {
+ final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+ if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
+ if (r != null) {
+ r.icicle = null;
+ r.haveState = false;
+ }
+ }
+
+ /**
+ * Once we know that we have asked an application to put an activity in the resumed state
+ * (either by launching it or explicitly telling it), this function updates the rest of our
+ * state to match that fact.
+ */
+ void completeResumeLocked() {
+ final boolean wasVisible = visible;
+ visible = true;
+ if (!wasVisible) {
+ // Visibility has changed, so take a note of it so we call the TaskStackChangedListener
+ mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
+ }
+ idle = false;
+ results = null;
+ newIntents = null;
+ stopped = false;
+
+ if (isHomeActivity()) {
+ ProcessRecord app = task.mActivities.get(0).app;
+ if (app != null && app != service.mHomeProcess) {
+ service.mHomeProcess = app;
+ }
+ }
+
+ if (nowVisible) {
+ // We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now.
+ mStackSupervisor.reportActivityVisibleLocked(this);
+ mStackSupervisor.notifyActivityDrawnForKeyguard();
+ }
+
+ // Schedule an idle timeout in case the app doesn't do it for us.
+ mStackSupervisor.scheduleIdleTimeoutLocked(this);
+
+ mStackSupervisor.reportResumedActivityLocked(this);
+
+ resumeKeyDispatchingLocked();
+ final ActivityStack stack = getStack();
+ stack.mNoAnimActivities.clear();
+
+ // Mark the point when the activity is resuming
+ // TODO: To be more accurate, the mark should be before the onCreate,
+ // not after the onResume. But for subsequent starts, onResume is fine.
+ if (app != null) {
+ cpuTimeAtResume = service.mProcessCpuTracker.getCpuTimeForPid(app.pid);
+ } else {
+ cpuTimeAtResume = 0; // Couldn't get the cpu time of process
+ }
+
+ returningOptions = null;
+
+ if (stack.getVisibleBehindActivity() == this) {
+ // When resuming an activity, require it to call requestVisibleBehind() again.
+ stack.setVisibleBehindActivity(null /* ActivityRecord */);
+ }
+ mStackSupervisor.checkReadyForSleepLocked();
+ }
+
+ final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState,
+ CharSequence description) {
+ final ActivityStack stack = getStack();
+ if (state != ActivityState.STOPPING) {
+ Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this);
+ stack.mHandler.removeMessages(ActivityStack.STOP_TIMEOUT_MSG, this);
+ return;
+ }
+ if (newPersistentState != null) {
+ persistentState = newPersistentState;
+ service.notifyTaskPersisterLocked(task, false);
+ }
+ if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + icicle);
+ if (newIcicle != null) {
+ // If icicle is null, this is happening due to a timeout, so we haven't really saved
+ // the state.
+ icicle = newIcicle;
+ haveState = true;
+ launchCount = 0;
+ updateThumbnailLocked(null /* newThumbnail */, description);
+ }
+ if (!stopped) {
+ if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)");
+ stack.mHandler.removeMessages(ActivityStack.STOP_TIMEOUT_MSG, this);
+ stopped = true;
+ state = ActivityState.STOPPED;
+
+ service.mWindowManager.notifyAppStopped(appToken);
+
+ if (stack.getVisibleBehindActivity() == this) {
+ mStackSupervisor.requestVisibleBehindLocked(this, false /* visible */);
+ }
+ if (finishing) {
+ clearOptionsLocked();
+ } else {
+ if (deferRelaunchUntilPaused) {
+ stack.destroyActivityLocked(this, true /* removeFromApp */, "stop-config");
+ mStackSupervisor.resumeFocusedStackTopActivityLocked();
+ } else {
+ mStackSupervisor.updatePreviousProcessLocked(this);
+ }
+ }
+ }
+ }
+
void startLaunchTickingLocked() {
if (ActivityManagerService.IS_USER_BUILD) {
return;
@@ -1133,7 +1412,7 @@
return false;
}
- final ActivityStack stack = task.stack;
+ final ActivityStack stack = getStack();
if (stack == null) {
return false;
}
@@ -1146,7 +1425,7 @@
void finishLaunchTickingLocked() {
launchTickTime = 0;
- final ActivityStack stack = task.stack;
+ final ActivityStack stack = getStack();
if (stack != null) {
stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
}
@@ -1180,7 +1459,7 @@
if (displayStartTime != 0) {
reportLaunchTimeLocked(curTime);
}
- final ActivityStack stack = task.stack;
+ final ActivityStack stack = getStack();
if (fullyDrawnStartTime != 0 && stack != null) {
final long thisTime = curTime - fullyDrawnStartTime;
final long totalTime = stack.mFullyDrawnStartTime != 0
@@ -1212,7 +1491,7 @@
}
private void reportLaunchTimeLocked(final long curTime) {
- final ActivityStack stack = task.stack;
+ final ActivityStack stack = getStack();
if (stack == null) {
return;
}
@@ -1356,13 +1635,13 @@
static ActivityRecord isInStackLocked(IBinder token) {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
- return (r != null) ? r.task.stack.isInStackLocked(r) : null;
+ return (r != null) ? r.getStack().isInStackLocked(r) : null;
}
static ActivityStack getStackLocked(IBinder token) {
final ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- return r.task.stack;
+ return r.getStack();
}
return null;
}
@@ -1373,8 +1652,9 @@
// This would be redundant.
return false;
}
- if (task == null || task.stack == null || this == task.stack.mResumedActivity
- || this == task.stack.mPausingActivity || !haveState || !stopped) {
+ final ActivityStack stack = getStack();
+ if (stack == null || this == stack.mResumedActivity || this == stack.mPausingActivity
+ || !haveState || !stopped) {
// We're not ready for this kind of thing.
return false;
}
@@ -1424,6 +1704,255 @@
}
}
+ // TODO: now used only in one place to address race-condition. Remove when that will be fixed.
+ void setLastReportedConfiguration(@NonNull Configuration config) {
+ mLastReportedConfiguration.setTo(config);
+ }
+
+ /** Call when override config was sent to the Window Manager to update internal records. */
+ void onOverrideConfigurationSent() {
+ mLastReportedOverrideConfiguration.setTo(task.getMergedOverrideConfiguration());
+ }
+
+ /**
+ * Make sure the given activity matches the current configuration. Returns false if the activity
+ * had to be destroyed. Returns true if the configuration is the same, or the activity will
+ * remain running as-is for whatever reason. Ensures the HistoryRecord is updated with the
+ * correct configuration and all other bookkeeping is handled.
+ */
+ boolean ensureActivityConfigurationLocked(int globalChanges, boolean preserveWindow) {
+ final ActivityStack stack = getStack();
+ if (stack.mConfigWillChange) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Skipping config check (will change): " + this);
+ return true;
+ }
+
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Ensuring correct configuration: " + this);
+
+ // Short circuit: if the two configurations are equal (the common case), then there is
+ // nothing to do.
+ final Configuration newGlobalConfig = service.getGlobalConfiguration();
+ final Configuration newTaskMergedOverrideConfig = task.getMergedOverrideConfiguration();
+ if (mLastReportedConfiguration.equals(newGlobalConfig)
+ && mLastReportedOverrideConfiguration.equals(newTaskMergedOverrideConfig)
+ && !forceNewConfig) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Configuration unchanged in " + this);
+ return true;
+ }
+
+ // We don't worry about activities that are finishing.
+ if (finishing) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Configuration doesn't matter in finishing " + this);
+ stopFreezingScreenLocked(false);
+ return true;
+ }
+
+ // Okay we now are going to make this activity have the new config.
+ // But then we need to figure out how it needs to deal with that.
+ mTmpGlobalConfig.setTo(mLastReportedConfiguration);
+ mTmpTaskConfig.setTo(mLastReportedOverrideConfiguration);
+ mLastReportedConfiguration.setTo(newGlobalConfig);
+ mLastReportedOverrideConfiguration.setTo(newTaskMergedOverrideConfig);
+
+ int taskChanges = getTaskConfigurationChanges(this, newTaskMergedOverrideConfig,
+ mTmpTaskConfig);
+ final int changes = mTmpGlobalConfig.diff(newGlobalConfig) | taskChanges;
+ if (changes == 0 && !forceNewConfig) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Configuration no differences in " + this);
+ // There are no significant differences, so we won't relaunch but should still deliver
+ // the new configuration to the client process.
+ scheduleConfigurationChanged(newTaskMergedOverrideConfig, true);
+ return true;
+ }
+
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Configuration changes for " + this + " ; taskChanges="
+ + Configuration.configurationDiffToString(taskChanges) + ", allChanges="
+ + Configuration.configurationDiffToString(changes));
+
+ // If the activity isn't currently running, just leave the new configuration and it will
+ // pick that up next time it starts.
+ if (app == null || app.thread == null) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Configuration doesn't matter not running " + this);
+ stopFreezingScreenLocked(false);
+ forceNewConfig = false;
+ return true;
+ }
+
+ // Figure out how to handle the changes between the configurations.
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Checking to restart " + info.name + ": changed=0x"
+ + Integer.toHexString(changes) + ", handles=0x"
+ + Integer.toHexString(info.getRealConfigChanged())
+ + ", newGlobalConfig=" + newGlobalConfig
+ + ", newTaskMergedOverrideConfig=" + newTaskMergedOverrideConfig);
+
+ if ((changes&(~info.getRealConfigChanged())) != 0 || forceNewConfig) {
+ // Aha, the activity isn't handling the change, so DIE DIE DIE.
+ configChangeFlags |= changes;
+ startFreezingScreenLocked(app, globalChanges);
+ forceNewConfig = false;
+ preserveWindow &= isResizeOnlyChange(changes);
+ if (app == null || app.thread == null) {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Config is destroying non-running " + this);
+ stack.destroyActivityLocked(this, true, "config");
+ } else if (state == ActivityState.PAUSING) {
+ // A little annoying: we are waiting for this activity to finish pausing. Let's not
+ // do anything now, but just flag that it needs to be restarted when done pausing.
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Config is skipping already pausing " + this);
+ deferRelaunchUntilPaused = true;
+ preserveWindowOnDeferredRelaunch = preserveWindow;
+ return true;
+ } else if (state == ActivityState.RESUMED) {
+ // Try to optimize this case: the configuration is changing and we need to restart
+ // the top, resumed activity. Instead of doing the normal handshaking, just say
+ // "restart!".
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Config is relaunching resumed " + this);
+
+ if (DEBUG_STATES && !visible) {
+ Slog.v(TAG_STATES, "Config is relaunching resumed invisible activity " + this
+ + " called by " + Debug.getCallers(4));
+ }
+
+ relaunchActivityLocked(true /* andResume */, preserveWindow);
+ } else {
+ if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
+ "Config is relaunching non-resumed " + this);
+ relaunchActivityLocked(false /* andResume */, preserveWindow);
+ }
+
+ // All done... tell the caller we weren't able to keep this activity around.
+ return false;
+ }
+
+ // Default case: the activity can handle this new configuration, so hand it over.
+ // NOTE: We only forward the task override configuration as the system level configuration
+ // changes is always sent to all processes when they happen so it can just use whatever
+ // system level configuration it last got.
+ scheduleConfigurationChanged(newTaskMergedOverrideConfig, true);
+ stopFreezingScreenLocked(false);
+
+ return true;
+ }
+
+ private static int getTaskConfigurationChanges(ActivityRecord record, Configuration taskConfig,
+ Configuration oldTaskOverride) {
+ // If we went from full-screen to non-full-screen, make sure to use the correct
+ // configuration task diff, so the diff stays as small as possible.
+ if (Configuration.EMPTY.equals(oldTaskOverride)
+ && !Configuration.EMPTY.equals(taskConfig)) {
+ oldTaskOverride = record.task.extractOverrideConfig(record.mLastReportedConfiguration);
+ }
+
+ // Conversely, do the same when going the other direction.
+ if (Configuration.EMPTY.equals(taskConfig)
+ && !Configuration.EMPTY.equals(oldTaskOverride)) {
+ taskConfig = record.task.extractOverrideConfig(record.mLastReportedConfiguration);
+ }
+
+ // Determine what has changed. May be nothing, if this is a config that has come back from
+ // the app after going idle. In that case we just want to leave the official config object
+ // now in the activity and do nothing else.
+ int taskChanges = oldTaskOverride.diff(taskConfig, true /* skipUndefined */);
+ // We don't want to use size changes if they don't cross boundaries that are important to
+ // the app.
+ if ((taskChanges & CONFIG_SCREEN_SIZE) != 0) {
+ final boolean crosses = record.crossesHorizontalSizeThreshold(
+ oldTaskOverride.screenWidthDp, taskConfig.screenWidthDp)
+ || record.crossesVerticalSizeThreshold(
+ oldTaskOverride.screenHeightDp, taskConfig.screenHeightDp);
+ if (!crosses) {
+ taskChanges &= ~CONFIG_SCREEN_SIZE;
+ }
+ }
+ if ((taskChanges & CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
+ final int oldSmallest = oldTaskOverride.smallestScreenWidthDp;
+ final int newSmallest = taskConfig.smallestScreenWidthDp;
+ if (!record.crossesSmallestSizeThreshold(oldSmallest, newSmallest)) {
+ taskChanges &= ~CONFIG_SMALLEST_SCREEN_SIZE;
+ }
+ }
+ return taskChanges;
+ }
+
+ private static boolean isResizeOnlyChange(int change) {
+ return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION
+ | CONFIG_SCREEN_LAYOUT)) == 0;
+ }
+
+ void relaunchActivityLocked(boolean andResume, boolean preserveWindow) {
+ if (service.mSuppressResizeConfigChanges && preserveWindow) {
+ configChangeFlags = 0;
+ return;
+ }
+
+ List<ResultInfo> pendingResults = null;
+ List<ReferrerIntent> pendingNewIntents = null;
+ if (andResume) {
+ pendingResults = results;
+ pendingNewIntents = newIntents;
+ }
+ if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+ "Relaunching: " + this + " with results=" + pendingResults
+ + " newIntents=" + pendingNewIntents + " andResume=" + andResume
+ + " preserveWindow=" + preserveWindow);
+ EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
+ : EventLogTags.AM_RELAUNCH_ACTIVITY, userId, System.identityHashCode(this),
+ task.taskId, shortComponentName);
+
+ startFreezingScreenLocked(app, 0);
+
+ mStackSupervisor.removeChildActivityContainers(this);
+
+ try {
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
+ "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + this
+ + " callers=" + Debug.getCallers(6));
+ forceNewConfig = false;
+ mStackSupervisor.activityRelaunchingLocked(this);
+ app.thread.scheduleRelaunchActivity(appToken, pendingResults, pendingNewIntents,
+ configChangeFlags, !andResume,
+ new Configuration(service.getGlobalConfiguration()),
+ new Configuration(task.getMergedOverrideConfiguration()), preserveWindow);
+ // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
+ // pass in 'andResume' if this activity is currently resumed, which implies we aren't
+ // sleeping.
+ } catch (RemoteException e) {
+ if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
+ }
+
+ if (andResume) {
+ if (DEBUG_STATES) {
+ Slog.d(TAG_STATES, "Resumed after relaunch " + this);
+ }
+ results = null;
+ newIntents = null;
+ service.showUnsupportedZoomDialogIfNeededLocked(this);
+ service.showAskCompatModeDialogLocked(this);
+ } else {
+ service.mHandler.removeMessages(ActivityStack.PAUSE_TIMEOUT_MSG, this);
+ state = ActivityState.PAUSED;
+ // if the app is relaunched when it's stopped, and we're not resuming,
+ // put it back into stopped state.
+ if (stopped) {
+ getStack().addToStopping(this, true /* immediate */);
+ }
+ }
+
+ configChangeFlags = 0;
+ deferRelaunchUntilPaused = false;
+ preserveWindowOnDeferredRelaunch = false;
+ }
+
void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
out.attribute(null, ATTR_ID, String.valueOf(createTime));
out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 6b00c86..55066fd 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -22,26 +22,20 @@
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
-import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
-import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-import static android.content.res.Configuration.SCREENLAYOUT_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_APP;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RESULTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SCREENSHOTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
@@ -52,13 +46,11 @@
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_APP;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CLEANUP;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RESULTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SCREENSHOTS;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
@@ -69,7 +61,6 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN;
-import static com.android.server.am.ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS;
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.STARTING_WINDOW_REMOVED;
@@ -99,7 +90,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
-import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
@@ -110,7 +100,6 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -124,7 +113,6 @@
import android.view.Display;
import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.content.ReferrerIntent;
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService.ItemMatcher;
@@ -143,19 +131,17 @@
/**
* State and management of a single stack of activities.
*/
-final class ActivityStack {
+final class ActivityStack extends ConfigurationContainer {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_APP = TAG + POSTFIX_APP;
private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
- private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
private static final String TAG_RELEASE = TAG + POSTFIX_RELEASE;
private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
- private static final String TAG_SCREENSHOTS = TAG + POSTFIX_SCREENSHOTS;
private static final String TAG_STACK = TAG + POSTFIX_STACK;
private static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
@@ -170,36 +156,47 @@
// How long we wait until giving up on the last activity to pause. This
// is short because it directly impacts the responsiveness of starting the
// next activity.
- static final int PAUSE_TIMEOUT = 500;
+ private static final int PAUSE_TIMEOUT = 500;
// How long we wait for the activity to tell us it has stopped before
// giving up. This is a good amount of time because we really need this
// from the application in order to get its saved state.
- static final int STOP_TIMEOUT = 10 * 1000;
+ private static final int STOP_TIMEOUT = 10 * 1000;
// How long we wait until giving up on an activity telling us it has
// finished destroying itself.
- static final int DESTROY_TIMEOUT = 10 * 1000;
+ private static final int DESTROY_TIMEOUT = 10 * 1000;
// How long until we reset a task when the user returns to it. Currently
// disabled.
- static final long ACTIVITY_INACTIVE_RESET_TIME = 0;
-
- // How long between activity launches that we consider safe to not warn
- // the user about an unexpected activity being launched on top.
- static final long START_WARN_TIME = 5 * 1000;
+ private static final long ACTIVITY_INACTIVE_RESET_TIME = 0;
// Set to false to disable the preview that is shown while a new activity
// is being started.
- static final boolean SHOW_APP_STARTING_PREVIEW = true;
+ private static final boolean SHOW_APP_STARTING_PREVIEW = true;
// How long to wait for all background Activities to redraw following a call to
// convertToTranslucent().
- static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000;
+ private static final long TRANSLUCENT_CONVERSION_TIMEOUT = 2000;
// How many activities have to be scheduled to stop to force a stop pass.
private static final int MAX_STOPPING_TO_FORCE = 3;
+ @Override
+ protected int getChildCount() {
+ return mTaskHistory.size();
+ }
+
+ @Override
+ protected ConfigurationContainer getChildAt(int index) {
+ return mTaskHistory.get(index);
+ }
+
+ @Override
+ protected ConfigurationContainer getParent() {
+ return mActivityContainer.mActivityDisplay;
+ }
+
enum ActivityState {
INITIALIZING,
RESUMED,
@@ -218,18 +215,18 @@
static final int STACK_VISIBLE = 1;
// Stack is considered visible, but only becuase it has activity that is visible behind other
// activities and there is a specific combination of stacks.
- static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
+ private static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
/* The various modes for the method {@link #removeTask}. */
// Task is being completely removed from all stacks in the system.
- static final int REMOVE_TASK_MODE_DESTROYING = 0;
+ private static final int REMOVE_TASK_MODE_DESTROYING = 0;
// Task is being removed from this stack so we can add it to another stack. In the case we are
// moving we don't want to perform some operations on the task like removing it from window
// manager or recents.
static final int REMOVE_TASK_MODE_MOVING = 1;
// Similar to {@link #REMOVE_TASK_MODE_MOVING} and the task will be added to the top of its new
// stack and the new stack will be on top of all stacks.
- static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
+ private static final int REMOVE_TASK_MODE_MOVING_TO_TOP = 2;
// The height/width divide used when fitting a task within a bounds with method
// {@link #fitWithinBounds}.
@@ -239,7 +236,7 @@
private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
final ActivityManagerService mService;
- final WindowManagerService mWindowManager;
+ private final WindowManagerService mWindowManager;
private final RecentTasks mRecentTasks;
/**
@@ -286,13 +283,6 @@
*/
ActivityRecord mResumedActivity = null;
- /**
- * This is the last activity that has been started. It is only used to
- * identify when multiple activities are started at once so that the user
- * can be warned they may not be in the activity they think they are.
- */
- ActivityRecord mLastStartedActivity = null;
-
// The topmost Activity passed to convertToTranslucent(). When non-null it means we are
// waiting for all Activities in mUndrawnActivitiesBelowTopTranslucent to be removed as they
// are drawn. When the last member of mUndrawnActivitiesBelowTopTranslucent is removed the
@@ -300,7 +290,7 @@
// Activity.onTranslucentConversionComplete(false). If a timeout occurs prior to the last
// background activity being drawn then the same call will be made with a true value.
ActivityRecord mTranslucentActivityWaiting = null;
- private ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent = new ArrayList<>();
+ ArrayList<ActivityRecord> mUndrawnActivitiesBelowTopTranslucent = new ArrayList<>();
/**
* Set when we know we are going to be calling updateConfiguration()
@@ -313,11 +303,11 @@
// Current bounds of the stack or null if fullscreen.
Rect mBounds = null;
- boolean mUpdateBoundsDeferred;
- boolean mUpdateBoundsDeferredCalled;
- final Rect mDeferredBounds = new Rect();
- final Rect mDeferredTaskBounds = new Rect();
- final Rect mDeferredTaskInsetBounds = new Rect();
+ private boolean mUpdateBoundsDeferred;
+ private boolean mUpdateBoundsDeferredCalled;
+ private final Rect mDeferredBounds = new Rect();
+ private final Rect mDeferredTaskBounds = new Rect();
+ private final Rect mDeferredTaskInsetBounds = new Rect();
long mLaunchStartTime = 0;
long mFullyDrawnStartTime = 0;
@@ -338,7 +328,7 @@
private final Rect tempRect2 = new Rect();
/** Run all ActivityStacks through this */
- final ActivityStackSupervisor mStackSupervisor;
+ private final ActivityStackSupervisor mStackSupervisor;
private final LaunchingTaskPositioner mTaskPositioner;
@@ -351,7 +341,7 @@
static final int RELEASE_BACKGROUND_RESOURCES_TIMEOUT_MSG =
ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 7;
- static class ScheduleDestroyArgs {
+ private static class ScheduleDestroyArgs {
final ProcessRecord mOwner;
final String mReason;
ScheduleDestroyArgs(ProcessRecord owner, String reason) {
@@ -362,7 +352,7 @@
final Handler mHandler;
- final class ActivityStackHandler extends Handler {
+ private class ActivityStackHandler extends Handler {
ActivityStackHandler(Looper looper) {
super(looper);
@@ -407,7 +397,8 @@
Slog.w(TAG, "Activity stop timeout for " + r);
synchronized (mService) {
if (r.isInHistory()) {
- activityStoppedLocked(r, null, null, null);
+ r.activityStoppedLocked(null /* icicle */,
+ null /* persistentState */, null /* description */);
}
}
} break;
@@ -466,6 +457,7 @@
mTaskPositioner.setDisplay(activityDisplay.mDisplay);
mTaskPositioner.configure(mBounds);
}
+ onParentChanged();
if (mStackId == DOCKED_STACK_ID) {
// If we created a docked stack we want to resize it so it resizes all other stacks
@@ -482,6 +474,7 @@
mTaskPositioner.reset();
}
mWindowManager.detachStack(mStackId);
+ onParentChanged();
if (mStackId == DOCKED_STACK_ID) {
// If we removed a docked stack we want to resize it so it resizes all other stacks
// in the system to fullscreen.
@@ -490,7 +483,7 @@
}
}
- public void getDisplaySize(Point out) {
+ void getDisplaySize(Point out) {
mActivityContainer.mActivityDisplay.mDisplay.getSize(out);
}
@@ -644,9 +637,9 @@
return null;
}
final TaskRecord task = r.task;
- if (task != null && task.stack != null
- && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
- if (task.stack != this) Slog.w(TAG,
+ final ActivityStack stack = r.getStack();
+ if (stack != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
+ if (stack != this) Slog.w(TAG,
"Illegal state! task does not point to stack it is in.");
return r;
}
@@ -720,7 +713,7 @@
/**
* @param task If non-null, the task will be moved to the back of the stack.
* */
- void moveToBack(TaskRecord task) {
+ private void moveToBack(TaskRecord task) {
if (!isAttached()) {
return;
}
@@ -914,7 +907,7 @@
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to RESUMED: " + r + " (starting new instance)"
+ " callers=" + Debug.getCallers(5));
setResumedActivityLocked(r, "minimalResumeActivityLocked");
- completeResumeLocked(r);
+ r.completeResumeLocked();
setLaunchTime(r);
if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
"Launch completed; removing icicle of " + r.icicle);
@@ -955,7 +948,7 @@
}
}
- void clearLaunchTime(ActivityRecord r) {
+ private void clearLaunchTime(ActivityRecord r) {
// Make sure that there is no activity waiting for this to launch.
if (mStackSupervisor.mWaitingActivityLaunched.isEmpty()) {
r.displayStartTime = r.fullyDrawnStartTime = 0;
@@ -1037,50 +1030,6 @@
}
}
- public final Bitmap screenshotActivitiesLocked(ActivityRecord who) {
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "screenshotActivitiesLocked: " + who);
- if (who.noDisplay) {
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tNo display");
- return null;
- }
-
- if (isHomeStack()) {
- // This is an optimization -- since we never show Home or Recents within Recents itself,
- // we can just go ahead and skip taking the screenshot if this is the home stack.
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tHome stack");
- return null;
- }
-
- int w = mService.mThumbnailWidth;
- int h = mService.mThumbnailHeight;
-
- if (w <= 0) {
- Slog.e(TAG, "\tInvalid thumbnail dimensions: " + w + "x" + h);
- return null;
- }
-
- if (mStackId == DOCKED_STACK_ID && mStackSupervisor.mIsDockMinimized) {
- // When the docked stack is minimized its app windows are cropped significantly so any
- // screenshot taken will not display the apps contain. So, we avoid taking a screenshot
- // in that case.
- if (DEBUG_SCREENSHOTS) Slog.e(TAG, "\tIn minimized docked stack");
- return null;
- }
-
- float scale = 1f;
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
-
- // When this flag is set, we currently take the fullscreen screenshot of the activity but
- // scaled to half the size. This gives us a "good-enough" fullscreen thumbnail to use within
- // SystemUI while keeping memory usage low.
- if (TAKE_FULLSCREEN_SCREENSHOTS) {
- w = h = -1;
- scale = mService.mFullscreenThumbnailScale;
- }
-
- return mWindowManager.screenshotApplications(who.appToken, DEFAULT_DISPLAY, w, h, scale);
- }
-
/**
* Start pausing the currently resumed activity. It is an error to call this if there
* is already an activity being paused or there is no resumed activity.
@@ -1239,57 +1188,6 @@
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
- final void activityResumedLocked(IBinder token) {
- final ActivityRecord r = ActivityRecord.forTokenLocked(token);
- if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
- r.icicle = null;
- r.haveState = false;
- }
-
- final void activityStoppedLocked(ActivityRecord r, Bundle icicle,
- PersistableBundle persistentState, CharSequence description) {
- if (r.state != ActivityState.STOPPING) {
- Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r);
- mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
- return;
- }
- if (persistentState != null) {
- r.persistentState = persistentState;
- mService.notifyTaskPersisterLocked(r.task, false);
- }
- if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + r + ": " + icicle);
- if (icicle != null) {
- // If icicle is null, this is happening due to a timeout, so we
- // haven't really saved the state.
- r.icicle = icicle;
- r.haveState = true;
- r.launchCount = 0;
- r.updateThumbnailLocked(null, description);
- }
- if (!r.stopped) {
- if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + r + " (stop complete)");
- mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
- r.stopped = true;
- r.state = ActivityState.STOPPED;
-
- mWindowManager.notifyAppStopped(r.appToken);
-
- if (getVisibleBehindActivity() == r) {
- mStackSupervisor.requestVisibleBehindLocked(r, false);
- }
- if (r.finishing) {
- r.clearOptionsLocked();
- } else {
- if (r.deferRelaunchUntilPaused) {
- destroyActivityLocked(r, true, "stop-config");
- mStackSupervisor.resumeFocusedStackTopActivityLocked();
- } else {
- mStackSupervisor.updatePreviousProcessLocked(r);
- }
- }
- }
- }
-
private void completePauseLocked(boolean resumeNext, ActivityRecord resuming) {
ActivityRecord prev = mPausingActivity;
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
@@ -1310,7 +1208,7 @@
if (prev.deferRelaunchUntilPaused) {
// Complete the deferred relaunch that was waiting for pause to complete.
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Re-launching after pause: " + prev);
- relaunchActivityLocked(prev, prev.configChangeFlags, false,
+ prev.relaunchActivityLocked(false /* andResume */,
prev.preserveWindowOnDeferredRelaunch);
} else if (wasStopping) {
// We are also stopping, the stop request must have gone soon after the pause.
@@ -1387,7 +1285,7 @@
mStackSupervisor.ensureActivitiesVisibleLocked(resuming, 0, !PRESERVE_WINDOWS);
}
- private void addToStopping(ActivityRecord r, boolean immediate) {
+ void addToStopping(ActivityRecord r, boolean immediate) {
if (!mStackSupervisor.mStoppingActivities.contains(r)) {
mStackSupervisor.mStoppingActivities.add(r);
}
@@ -1408,72 +1306,6 @@
}
}
- /**
- * Once we know that we have asked an application to put an activity in
- * the resumed state (either by launching it or explicitly telling it),
- * this function updates the rest of our state to match that fact.
- */
- private void completeResumeLocked(ActivityRecord next) {
- next.visible = true;
- next.idle = false;
- next.results = null;
- next.newIntents = null;
- next.stopped = false;
-
- if (next.isHomeActivity()) {
- ProcessRecord app = next.task.mActivities.get(0).app;
- if (app != null && app != mService.mHomeProcess) {
- mService.mHomeProcess = app;
- }
- }
-
- if (next.nowVisible) {
- // We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now.
- mStackSupervisor.reportActivityVisibleLocked(next);
- mStackSupervisor.notifyActivityDrawnForKeyguard();
- }
-
- // schedule an idle timeout in case the app doesn't do it for us.
- mStackSupervisor.scheduleIdleTimeoutLocked(next);
-
- mStackSupervisor.reportResumedActivityLocked(next);
-
- next.resumeKeyDispatchingLocked();
- mNoAnimActivities.clear();
-
- // Mark the point when the activity is resuming
- // TODO: To be more accurate, the mark should be before the onCreate,
- // not after the onResume. But for subsequent starts, onResume is fine.
- if (next.app != null) {
- next.cpuTimeAtResume = mService.mProcessCpuTracker.getCpuTimeForPid(next.app.pid);
- } else {
- next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
- }
-
- next.returningOptions = null;
-
- if (getVisibleBehindActivity() == next) {
- // When resuming an activity, require it to call requestVisibleBehind() again.
- setVisibleBehindActivity(null);
- }
- mStackSupervisor.checkReadyForSleepLocked();
- }
-
- private void setVisible(ActivityRecord r, boolean visible) {
- r.visible = visible;
- if (!visible && r.mUpdateTaskThumbnailWhenHidden) {
- r.updateThumbnailLocked(r.task.stack.screenshotActivitiesLocked(r), null);
- r.mUpdateTaskThumbnailWhenHidden = false;
- }
- mWindowManager.setAppVisibility(r.appToken, visible);
- final ArrayList<ActivityContainer> containers = r.mChildContainers;
- for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
- ActivityContainer container = containers.get(containerNdx);
- container.setVisible(visible);
- }
- mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
- }
-
// Find the first visible activity above the passed activity and if it is translucent return it
// otherwise return null;
ActivityRecord findNextTranslucentActivity(ActivityRecord r) {
@@ -1482,7 +1314,7 @@
return null;
}
- ActivityStack stack = task.stack;
+ final ActivityStack stack = task.getStack();
if (stack == null) {
return null;
}
@@ -1526,7 +1358,7 @@
ArrayList<ActivityStack> stacks = mStacks;
final ActivityRecord parent = mActivityContainer.mParentActivity;
if (parent != null) {
- stacks = parent.task.stack.mStacks;
+ stacks = parent.getStack().mStacks;
}
if (stacks != null) {
for (int i = stacks.size() - 1; i >= 0; --i) {
@@ -1776,7 +1608,8 @@
// is finishing, we no longer change its visibility, but we still need to take
// the screenshots if startPausingLocked decided it should be taken.
if (r.mUpdateTaskThumbnailWhenHidden) {
- r.updateThumbnailLocked(screenshotActivitiesLocked(r), null);
+ r.updateThumbnailLocked(r.screenshotActivityLocked(),
+ null /* description */);
r.mUpdateTaskThumbnailWhenHidden = false;
}
continue;
@@ -1787,14 +1620,14 @@
}
aboveTop = false;
- if (shouldBeVisible(r, behindTranslucentActivity, stackVisibleBehind,
+ if (r.shouldBeVisible(behindTranslucentActivity, stackVisibleBehind,
visibleBehind, behindFullscreenActivity)) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Make visible? " + r
+ " finishing=" + r.finishing + " state=" + r.state);
// First: if this is not the current activity being started, make
// sure it matches the current configuration.
if (r != starting) {
- ensureActivityConfigurationLocked(r, 0, preserveWindows);
+ r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindows);
}
if (r.app == null || r.app.thread == null) {
@@ -1812,11 +1645,11 @@
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Skipping: already visible at " + r);
- if (handleAlreadyVisible(r)) {
+ if (r.handleAlreadyVisible()) {
resumeNextActivity = false;
}
} else {
- makeVisibleIfNeeded(starting, r);
+ r.makeVisibleIfNeeded(starting);
}
// Aggregate current change flags.
configChanges |= r.configChangeFlags;
@@ -1897,33 +1730,6 @@
}
}
- /** Return true if the input activity should be made visible */
- private boolean shouldBeVisible(ActivityRecord r, boolean behindTranslucentActivity,
- boolean stackVisibleBehind, ActivityRecord visibleBehind,
- boolean behindFullscreenActivity) {
-
- if (r == null || !r.okToShowLocked()) {
- return false;
- }
-
- // mLaunchingBehind: Activities launching behind are at the back of the task stack
- // but must be drawn initially for the animation as though they were visible.
- final boolean activityVisibleBehind =
- (behindTranslucentActivity || stackVisibleBehind) && visibleBehind == r;
-
- boolean isVisible =
- !behindFullscreenActivity || r.mLaunchTaskBehind || activityVisibleBehind;
-
- if (mService.mSupportsLeanbackOnly && isVisible && r.isRecentsActivity()) {
- // On devices that support leanback only (Android TV), Recents activity can only be
- // visible if the home stack is the focused stack or we are in split-screen mode.
- isVisible = mStackSupervisor.getStack(DOCKED_STACK_ID) != null
- || mStackSupervisor.isFocusedStack(this);
- }
-
- return isVisible;
- }
-
private void checkTranslucentActivityWaiting(ActivityRecord top) {
if (mTranslucentActivityWaiting != top) {
mUndrawnActivitiesBelowTopTranslucent.clear();
@@ -1951,7 +1757,7 @@
}
if (!r.visible || r.mLaunchTaskBehind) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Starting and making visible: " + r);
- setVisible(r, true);
+ r.setVisible(true);
}
if (r != starting) {
mStackSupervisor.startSpecificActivityLocked(r, andResume, false);
@@ -1970,7 +1776,7 @@
// keeping the screen frozen.
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state);
try {
- setVisible(r, false);
+ r.setVisible(false);
switch (r.state) {
case STOPPING:
case STOPPED:
@@ -2020,50 +1826,6 @@
return behindFullscreenActivity;
}
- private void makeVisibleIfNeeded(ActivityRecord starting, ActivityRecord r) {
-
- // This activity is not currently visible, but is running. Tell it to become visible.
- if (r.state == ActivityState.RESUMED || r == starting) {
- if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
- "Not making visible, r=" + r + " state=" + r.state + " starting=" + starting);
- return;
- }
-
- // If this activity is paused, tell it to now show its window.
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "Making visible and scheduling visibility: " + r);
- try {
- if (mTranslucentActivityWaiting != null) {
- r.updateOptionsLocked(r.returningOptions);
- mUndrawnActivitiesBelowTopTranslucent.add(r);
- }
- setVisible(r, true);
- r.sleeping = false;
- r.app.pendingUiClean = true;
- r.app.thread.scheduleWindowVisibility(r.appToken, true);
- // The activity may be waiting for stop, but that is no longer
- // appropriate for it.
- mStackSupervisor.mStoppingActivities.remove(r);
- mStackSupervisor.mGoingToSleepActivities.remove(r);
- } catch (Exception e) {
- // Just skip on any failure; we'll make it
- // visible when it next restarts.
- Slog.w(TAG, "Exception thrown making visibile: " + r.intent.getComponent(), e);
- }
- handleAlreadyVisible(r);
- }
-
- private boolean handleAlreadyVisible(ActivityRecord r) {
- r.stopFreezingScreenLocked(false);
- try {
- if (r.returningOptions != null) {
- r.app.thread.scheduleOnNewActivityOptions(r.appToken, r.returningOptions);
- }
- } catch(RemoteException e) {
- }
- return r.state == ActivityState.RESUMED;
- }
-
void convertActivityToTranslucent(ActivityRecord r) {
mTranslucentActivityWaiting = r;
mUndrawnActivitiesBelowTopTranslucent.clear();
@@ -2271,7 +2033,7 @@
}
final TaskRecord nextTask = next.task;
- if (prevTask != null && prevTask.stack == this &&
+ if (prevTask != null && prevTask.getStack() == this &&
prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
if (prevTask == nextTask) {
@@ -2524,7 +2286,7 @@
boolean notUpdated = true;
if (mStackSupervisor.isFocusedStack(this)) {
Configuration config = mWindowManager.updateOrientationFromAppTokens(
- mService.mGlobalConfiguration,
+ mService.getGlobalConfiguration(),
next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
if (config != null) {
next.frozenBeforeDestroy = true;
@@ -2549,7 +2311,7 @@
if (!next.visible || next.stopped) {
mWindowManager.setAppVisibility(next.appToken, true);
}
- completeResumeLocked(next);
+ next.completeResumeLocked();
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
@@ -2623,7 +2385,7 @@
// From this point on, if something goes wrong there is no way
// to recover the activity.
try {
- completeResumeLocked(next);
+ next.completeResumeLocked();
} catch (Exception e) {
// If any exception gets thrown, toss away this
// activity and try the next one.
@@ -2898,7 +2660,7 @@
* @param forceReset
* @return An ActivityOptions that needs to be processed.
*/
- final ActivityOptions resetTargetTaskIfNeededLocked(TaskRecord task, boolean forceReset) {
+ private ActivityOptions resetTargetTaskIfNeededLocked(TaskRecord task, boolean forceReset) {
ActivityOptions topOptions = null;
int replyChainEnd = -1;
@@ -3480,7 +3242,7 @@
return true;
}
- final void finishActivityResultsLocked(ActivityRecord r, int resultCode, Intent resultData) {
+ private void finishActivityResultsLocked(ActivityRecord r, int resultCode, Intent resultData) {
// send the result
ActivityRecord resultTo = r.resultTo;
if (resultTo != null) {
@@ -3625,7 +3387,7 @@
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
r.state = ActivityState.FINISHING;
final boolean finishingActivityInNonFocusedStack
- = r.task.stack != mStackSupervisor.getFocusedStack()
+ = r.getStack() != mStackSupervisor.getFocusedStack()
&& prevState == ActivityState.PAUSED && mode == FINISH_AFTER_VISIBLE;
if (mode == FINISH_IMMEDIATELY
@@ -3806,8 +3568,7 @@
*
* Note: Call before #removeActivityFromHistoryLocked.
*/
- final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices,
- boolean setState) {
+ private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) {
if (mResumedActivity == r) {
mResumedActivity = null;
}
@@ -3897,7 +3658,7 @@
/**
* Perform clean-up of service connections in an activity record.
*/
- final void cleanUpActivityServicesLocked(ActivityRecord r) {
+ private void cleanUpActivityServicesLocked(ActivityRecord r) {
// Throw away any services that have been bound by this activity.
if (r.connections != null) {
Iterator<ConnectionRecord> it = r.connections.iterator();
@@ -3915,7 +3676,7 @@
mHandler.sendMessage(msg);
}
- final void destroyActivitiesLocked(ProcessRecord owner, String reason) {
+ private void destroyActivitiesLocked(ProcessRecord owner, String reason) {
boolean lastIsOpaque = false;
boolean activityRemoved = false;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -4192,7 +3953,7 @@
}
}
- boolean removeHistoryRecordsForAppLocked(ProcessRecord app) {
+ private boolean removeHistoryRecordsForAppLocked(ProcessRecord app) {
removeHistoryRecordsForAppLocked(mLRUActivities, app, "mLRUActivities");
removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
"mStoppingActivities");
@@ -4283,7 +4044,7 @@
return hasVisibleActivities;
}
- final void updateTransitLocked(int transit, ActivityOptions options) {
+ private void updateTransitLocked(int transit, ActivityOptions options) {
if (options != null) {
ActivityRecord r = topRunningActivityLocked();
if (r != null && r.state != ActivityState.RESUMED) {
@@ -4295,7 +4056,7 @@
mWindowManager.prepareAppTransition(transit, false);
}
- void updateTaskMovement(TaskRecord task, boolean toFront) {
+ private void updateTaskMovement(TaskRecord task, boolean toFront) {
if (task.isPersistable) {
task.mLastTimeMoved = System.currentTimeMillis();
// Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
@@ -4504,8 +4265,7 @@
return true;
}
- static final void logStartActivity(int tag, ActivityRecord r,
- TaskRecord task) {
+ static void logStartActivity(int tag, ActivityRecord r, TaskRecord task) {
final Uri data = r.intent.getData();
final String strData = data != null ? data.toSafeString() : null;
@@ -4534,7 +4294,8 @@
(start.task == task) ? activities.indexOf(start) : activities.size() - 1;
for (; activityIndex >= 0; --activityIndex) {
final ActivityRecord r = activities.get(activityIndex);
- updatedConfig |= ensureActivityConfigurationLocked(r, 0, preserveWindow);
+ updatedConfig |= r.ensureActivityConfigurationLocked(0 /* globalChanges */,
+ preserveWindow);
if (r.fullscreen) {
behindFullscreen = true;
break;
@@ -4577,7 +4338,7 @@
}
}
- mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+ mTmpConfigs.put(task.taskId, task.getOverrideConfiguration());
mTmpBounds.put(task.taskId, task.mBounds);
if (tempTaskInsetBounds != null) {
mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds);
@@ -4631,245 +4392,6 @@
}
}
- /**
- * Make sure the given activity matches the current configuration. Returns false if the activity
- * had to be destroyed. Returns true if the configuration is the same, or the activity will
- * remain running as-is for whatever reason. Ensures the HistoryRecord is updated with the
- * correct configuration and all other bookkeeping is handled.
- */
- boolean ensureActivityConfigurationLocked(
- ActivityRecord r, int globalChanges, boolean preserveWindow) {
- if (mConfigWillChange) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Skipping config check (will change): " + r);
- return true;
- }
-
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Ensuring correct configuration: " + r);
-
- // Short circuit: if the two configurations are equal (the common case), then there is
- // nothing to do.
- final Configuration newConfig = mService.mGlobalConfiguration;
- r.task.sanitizeOverrideConfiguration(newConfig);
- final Configuration taskConfig = r.task.mOverrideConfig;
- if (r.configuration.equals(newConfig)
- && r.taskConfigOverride.equals(taskConfig)
- && !r.forceNewConfig) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration unchanged in " + r);
- return true;
- }
-
- // We don't worry about activities that are finishing.
- if (r.finishing) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration doesn't matter in finishing " + r);
- r.stopFreezingScreenLocked(false);
- return true;
- }
-
- // Okay we now are going to make this activity have the new config.
- // But then we need to figure out how it needs to deal with that.
- final Configuration oldConfig = r.configuration;
- final Configuration oldTaskOverride = r.taskConfigOverride;
- r.configuration = newConfig;
- r.taskConfigOverride = taskConfig;
-
- int taskChanges = getTaskConfigurationChanges(r, taskConfig, oldTaskOverride);
- final int changes = oldConfig.diff(newConfig) | taskChanges;
- if (changes == 0 && !r.forceNewConfig) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration no differences in " + r);
- // There are no significant differences, so we won't relaunch but should still deliver
- // the new configuration to the client process.
- r.scheduleConfigurationChanged(taskConfig, true);
- return true;
- }
-
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration changes for " + r + " ; taskChanges="
- + Configuration.configurationDiffToString(taskChanges) + ", allChanges="
- + Configuration.configurationDiffToString(changes));
-
- // If the activity isn't currently running, just leave the new
- // configuration and it will pick that up next time it starts.
- if (r.app == null || r.app.thread == null) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Configuration doesn't matter not running " + r);
- r.stopFreezingScreenLocked(false);
- r.forceNewConfig = false;
- return true;
- }
-
- // Figure out how to handle the changes between the configurations.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Checking to restart " + r.info.name + ": changed=0x"
- + Integer.toHexString(changes) + ", handles=0x"
- + Integer.toHexString(r.info.getRealConfigChanged()) + ", newConfig=" + newConfig
- + ", taskConfig=" + taskConfig);
-
- if ((changes&(~r.info.getRealConfigChanged())) != 0 || r.forceNewConfig) {
- // Aha, the activity isn't handling the change, so DIE DIE DIE.
- r.configChangeFlags |= changes;
- r.startFreezingScreenLocked(r.app, globalChanges);
- r.forceNewConfig = false;
- preserveWindow &= isResizeOnlyChange(changes);
- if (r.app == null || r.app.thread == null) {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is destroying non-running " + r);
- destroyActivityLocked(r, true, "config");
- } else if (r.state == ActivityState.PAUSING) {
- // A little annoying: we are waiting for this activity to finish pausing. Let's not
- // do anything now, but just flag that it needs to be restarted when done pausing.
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is skipping already pausing " + r);
- r.deferRelaunchUntilPaused = true;
- r.preserveWindowOnDeferredRelaunch = preserveWindow;
- return true;
- } else if (r.state == ActivityState.RESUMED) {
- // Try to optimize this case: the configuration is changing and we need to restart
- // the top, resumed activity. Instead of doing the normal handshaking, just say
- // "restart!".
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is relaunching resumed " + r);
-
- if (DEBUG_STATES && !r.visible) {
- Slog.v(TAG_STATES, "Config is relaunching resumed invisible activity " + r
- + " called by " + Debug.getCallers(4));
- }
-
- relaunchActivityLocked(r, r.configChangeFlags, true, preserveWindow);
- } else {
- if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
- "Config is relaunching non-resumed " + r);
- relaunchActivityLocked(r, r.configChangeFlags, false, preserveWindow);
- }
-
- // All done... tell the caller we weren't able to keep this activity around.
- return false;
- }
-
- // Default case: the activity can handle this new configuration, so hand it over.
- // NOTE: We only forward the task override configuration as the system level configuration
- // changes is always sent to all processes when they happen so it can just use whatever
- // system level configuration it last got.
- r.scheduleConfigurationChanged(taskConfig, true);
- r.stopFreezingScreenLocked(false);
-
- return true;
- }
-
- private int getTaskConfigurationChanges(ActivityRecord record, Configuration taskConfig,
- Configuration oldTaskOverride) {
-
- // If we went from full-screen to non-full-screen, make sure to use the correct
- // configuration task diff, so the diff stays as small as possible.
- if (Configuration.EMPTY.equals(oldTaskOverride)
- && !Configuration.EMPTY.equals(taskConfig)) {
- oldTaskOverride = record.task.extractOverrideConfig(record.configuration);
- }
-
- // Conversely, do the same when going the other direction.
- if (Configuration.EMPTY.equals(taskConfig)
- && !Configuration.EMPTY.equals(oldTaskOverride)) {
- taskConfig = record.task.extractOverrideConfig(record.configuration);
- }
-
- // Determine what has changed. May be nothing, if this is a config
- // that has come back from the app after going idle. In that case
- // we just want to leave the official config object now in the
- // activity and do nothing else.
- int taskChanges = oldTaskOverride.diff(taskConfig, true /* skipUndefined */);
- // We don't want to use size changes if they don't cross boundaries that are important to
- // the app.
- if ((taskChanges & CONFIG_SCREEN_SIZE) != 0) {
- final boolean crosses = record.crossesHorizontalSizeThreshold(
- oldTaskOverride.screenWidthDp, taskConfig.screenWidthDp)
- || record.crossesVerticalSizeThreshold(
- oldTaskOverride.screenHeightDp, taskConfig.screenHeightDp);
- if (!crosses) {
- taskChanges &= ~CONFIG_SCREEN_SIZE;
- }
- }
- if ((taskChanges & CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
- final int oldSmallest = oldTaskOverride.smallestScreenWidthDp;
- final int newSmallest = taskConfig.smallestScreenWidthDp;
- if (!record.crossesSmallestSizeThreshold(oldSmallest, newSmallest)) {
- taskChanges &= ~CONFIG_SMALLEST_SCREEN_SIZE;
- }
- }
- return taskChanges;
- }
-
- private static boolean isResizeOnlyChange(int change) {
- return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION
- | CONFIG_SCREEN_LAYOUT)) == 0;
- }
-
- private void relaunchActivityLocked(
- ActivityRecord r, int changes, boolean andResume, boolean preserveWindow) {
- if (mService.mSuppressResizeConfigChanges && preserveWindow) {
- r.configChangeFlags = 0;
- return;
- }
-
- List<ResultInfo> results = null;
- List<ReferrerIntent> newIntents = null;
- if (andResume) {
- results = r.results;
- newIntents = r.newIntents;
- }
- if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
- "Relaunching: " + r + " with results=" + results + " newIntents=" + newIntents
- + " andResume=" + andResume + " preserveWindow=" + preserveWindow);
- EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
- : EventLogTags.AM_RELAUNCH_ACTIVITY, r.userId, System.identityHashCode(r),
- r.task.taskId, r.shortComponentName);
-
- r.startFreezingScreenLocked(r.app, 0);
-
- mStackSupervisor.removeChildActivityContainers(r);
-
- try {
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
- "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r
- + " callers=" + Debug.getCallers(6));
- r.forceNewConfig = false;
- mStackSupervisor.activityRelaunchingLocked(r);
- r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
- !andResume, new Configuration(mService.mGlobalConfiguration),
- new Configuration(r.task.mOverrideConfig), preserveWindow);
- // Note: don't need to call pauseIfSleepingLocked() here, because
- // the caller will only pass in 'andResume' if this activity is
- // currently resumed, which implies we aren't sleeping.
- } catch (RemoteException e) {
- if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
- }
-
- if (andResume) {
- if (DEBUG_STATES) {
- Slog.d(TAG_STATES, "Resumed after relaunch " + r);
- }
- r.results = null;
- r.newIntents = null;
- mService.showUnsupportedZoomDialogIfNeededLocked(r);
- mService.showAskCompatModeDialogLocked(r);
- } else {
- mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
- r.state = ActivityState.PAUSED;
- // if the app is relaunched when it's stopped, and we're not resuming,
- // put it back into stopped state.
- if (r.stopped) {
- addToStopping(r, true /* immediate */);
- }
- }
-
- r.configChangeFlags = 0;
- r.deferRelaunchUntilPaused = false;
- r.preserveWindowOnDeferredRelaunch = false;
- }
-
boolean willActivityBeVisibleLocked(IBinder token) {
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
@@ -5023,7 +4545,7 @@
}
}
- public void unhandledBackLocked() {
+ void unhandledBackLocked() {
final int top = mTaskHistory.size() - 1;
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Performing unhandledBack(): top activity at " + top);
if (top >= 0) {
@@ -5223,7 +4745,7 @@
}
}
- task.stack = null;
+ task.setStack(null);
}
TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
@@ -5256,7 +4778,7 @@
void addTask(final TaskRecord task, final boolean toTop, String reason) {
final ActivityStack prevStack = preAddTask(task, reason, toTop);
- task.stack = this;
+ task.setStack(this);
if (toTop) {
insertTaskAtTop(task, null);
} else {
@@ -5268,9 +4790,9 @@
void positionTask(final TaskRecord task, int position) {
final ActivityRecord topRunningActivity = task.topRunningActivityLocked();
- final boolean wasResumed = topRunningActivity == task.stack.mResumedActivity;
+ final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity;
final ActivityStack prevStack = preAddTask(task, "positionTask", !ON_TOP);
- task.stack = this;
+ task.setStack(this);
insertTaskAtPosition(task, position);
postAddTask(task, prevStack);
if (wasResumed) {
@@ -5284,7 +4806,7 @@
}
private ActivityStack preAddTask(TaskRecord task, String reason, boolean toTop) {
- final ActivityStack prevStack = task.stack;
+ final ActivityStack prevStack = task.getStack();
if (prevStack != null && prevStack != this) {
prevStack.removeTask(task, reason,
toTop ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING);
@@ -5309,10 +4831,11 @@
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
- task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
- task.mResizeMode, r.isAlwaysFocusable(), task.isHomeTask(),
- r.appInfo.targetSdkVersion, r.mRotationAnimationHint, task.isOnTopLauncher());
- r.taskConfigOverride = task.mOverrideConfig;
+ task.voiceSession != null, r.mLaunchTaskBehind, bounds,
+ task.getOverrideConfiguration(), task.mResizeMode, r.isAlwaysFocusable(),
+ task.isHomeTask(), r.appInfo.targetSdkVersion, r.mRotationAnimationHint,
+ task.isOnTopLauncher());
+ r.onOverrideConfigurationSent();
}
void moveToFrontAndResumeStateIfNeeded(
@@ -5338,7 +4861,7 @@
* created on this stack which the activity is added to.
* */
void moveActivityToStack(ActivityRecord r) {
- final ActivityStack prevStack = r.task.stack;
+ final ActivityStack prevStack = r.getStack();
if (prevStack.mStackId == mStackId) {
// You are already in the right stack silly...
return;
@@ -5363,9 +4886,10 @@
private void setAppTask(ActivityRecord r, TaskRecord task) {
final Rect bounds = task.updateOverrideConfigurationFromLaunchBounds();
- mWindowManager.setAppTask(r.appToken, task.taskId, mStackId, bounds, task.mOverrideConfig,
- task.mResizeMode, task.isHomeTask(), task.isOnTopLauncher());
- r.taskConfigOverride = task.mOverrideConfig;
+ mWindowManager.setAppTask(r.appToken, task.taskId, mStackId, bounds,
+ task.getOverrideConfiguration(), task.mResizeMode, task.isHomeTask(),
+ task.isOnTopLauncher());
+ r.onOverrideConfigurationSent();
}
public int getStackId() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 67604d3..cd7481c 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -178,7 +178,8 @@
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
import static com.android.server.wm.AppTransition.TRANSIT_DOCK_TASK_FROM_RECENTS;
-public final class ActivityStackSupervisor implements DisplayListener {
+public final class ActivityStackSupervisor extends ConfigurationContainer
+ implements DisplayListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
@@ -412,6 +413,21 @@
private final ResizeDockedStackTimeout mResizeDockedStackTimeout;
+ @Override
+ protected int getChildCount() {
+ return mActivityDisplays.size();
+ }
+
+ @Override
+ protected ConfigurationContainer getChildAt(int index) {
+ return mActivityDisplays.valueAt(index);
+ }
+
+ @Override
+ protected ConfigurationContainer getParent() {
+ return null;
+ }
+
static class FindTaskResult {
ActivityRecord r;
boolean matchedByRootAffinity;
@@ -571,7 +587,7 @@
final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
if (parent != null) {
- stack = parent.task.stack;
+ stack = parent.getStack();
}
return stack == mFocusedStack;
}
@@ -584,7 +600,7 @@
final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
if (parent != null) {
- stack = parent.task.stack;
+ stack = parent.getStack();
}
return stack == mHomeStack.mStacks.get((mHomeStack.mStacks.size() - 1));
}
@@ -1182,7 +1198,7 @@
// just restarting it anyway.
if (checkConfig) {
Configuration config = mWindowManager.updateOrientationFromAppTokens(
- mService.mGlobalConfiguration,
+ mService.getGlobalConfiguration(),
r.mayFreezeScreenLocked(app) ? r.appToken : null);
// Deferring resume here because we're going to launch new activity shortly.
// We don't want to perform a redundant launch of the same record while ensuring
@@ -1210,7 +1226,7 @@
setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false);
}
- final ActivityStack stack = task.stack;
+ final ActivityStack stack = task.getStack();
try {
if (app.thread == null) {
throw new RemoteException();
@@ -1272,12 +1288,16 @@
app.pendingUiClean = true;
}
app.forceProcessStateUpTo(mService.mTopProcessState);
+ // Because we could be starting an Activity in the system process this may not go across
+ // a Binder interface which would create a new Configuration. Consequently we have to
+ // always create a new Configuration here.
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
- new Configuration(mService.mGlobalConfiguration),
- new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
- task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
- newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
+ new Configuration(mService.getGlobalConfiguration()),
+ new Configuration(task.getMergedOverrideConfiguration()), r.compat,
+ r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
+ r.persistentState, results, newIntents, !andResume,
+ mService.isNextTransitionForward(), profilerInfo);
if ((app.info.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
// This may be a heavy-weight process! Note that the package
@@ -1359,7 +1379,7 @@
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
- r.task.stack.setLaunchTime(r);
+ r.getStack().setLaunchTime(r);
if (app != null && app.thread != null) {
try {
@@ -1599,7 +1619,7 @@
// We'll update with whatever configuration it now says
// it used to launch.
if (config != null) {
- r.configuration = config;
+ r.setLastReportedConfiguration(config);
}
// We are now idle. If someone is waiting for a thumbnail from
@@ -1607,7 +1627,7 @@
r.idle = true;
//Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
- if (isFocusedStack(r.task.stack) || fromTimeout) {
+ if (isFocusedStack(r.getStack()) || fromTimeout) {
booting = checkFinishBootingLocked();
}
}
@@ -1645,7 +1665,7 @@
// waiting for the next one to start.
for (int i = 0; i < NS; i++) {
r = stops.get(i);
- final ActivityStack stack = r.task.stack;
+ final ActivityStack stack = r.getStack();
if (stack != null) {
if (r.finishing) {
stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
@@ -1659,7 +1679,7 @@
// waiting for the next one to start.
for (int i = 0; i < NF; i++) {
r = finishes.get(i);
- final ActivityStack stack = r.task.stack;
+ final ActivityStack stack = r.getStack();
if (stack != null) {
activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle");
}
@@ -1835,7 +1855,8 @@
// we'll just indicate that this task returns to the home task.
task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
}
- if (task.stack == null) {
+ ActivityStack currentStack = task.getStack();
+ if (currentStack == null) {
Slog.e(TAG, "findTaskToMoveToFrontLocked: can't move task="
+ task + " to front. Stack is null");
return;
@@ -1849,10 +1870,10 @@
if (stackId == INVALID_STACK_ID) {
stackId = task.getLaunchStackId();
}
- if (stackId != task.stack.mStackId) {
- final ActivityStack stack = moveTaskToStackUncheckedLocked(
- task, stackId, ON_TOP, !FORCE_FOCUS, reason);
- stackId = stack.mStackId;
+ if (stackId != currentStack.mStackId) {
+ currentStack = moveTaskToStackUncheckedLocked(task, stackId, ON_TOP,
+ !FORCE_FOCUS, reason);
+ stackId = currentStack.mStackId;
// moveTaskToStackUncheckedLocked() should already placed the task on top,
// still need moveTaskToFrontLocked() below for any transition settings.
}
@@ -1864,20 +1885,21 @@
// WM resizeTask must be done after the task is moved to the correct stack,
// because Task's setBounds() also updates dim layer's bounds, but that has
// dependency on the stack.
- mWindowManager.resizeTask(task.taskId, task.mBounds, task.mOverrideConfig,
- false /* relayout */, false /* forced */);
+ mWindowManager.resizeTask(task.taskId, task.mBounds,
+ task.getOverrideConfiguration(), false /* relayout */,
+ false /* forced */);
}
}
}
final ActivityRecord r = task.getTopActivity();
- task.stack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
+ currentStack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
r == null ? null : r.appTimeTracker, reason);
if (DEBUG_STACK) Slog.d(TAG_STACK,
- "findTaskToMoveToFront: moved to front of stack=" + task.stack);
+ "findTaskToMoveToFront: moved to front of stack=" + currentStack);
- handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+ handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, currentStack.mStackId,
forceNonResizeable);
}
@@ -2212,7 +2234,7 @@
// All we can do for now is update the bounds so it can be used when the task is
// added to window manager.
task.updateOverrideConfiguration(bounds);
- if (task.stack != null && task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) {
+ if (task.getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
// re-restore the task so it can have the proper stack association.
restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID);
}
@@ -2233,11 +2255,9 @@
if (updatedConfig) {
final ActivityRecord r = task.topRunningActivityLocked();
if (r != null) {
- final ActivityStack stack = task.stack;
- kept = stack.ensureActivityConfigurationLocked(r, 0, preserveWindow);
+ kept = r.ensureActivityConfigurationLocked(0 /* globalChanges */, preserveWindow);
if (!deferResume) {
-
// All other activities must be made visible with their correct configuration.
ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
if (!kept) {
@@ -2246,7 +2266,8 @@
}
}
}
- mWindowManager.resizeTask(task.taskId, task.mBounds, task.mOverrideConfig, kept, forced);
+ mWindowManager.resizeTask(task.taskId, task.mBounds, task.getOverrideConfiguration(), kept,
+ forced);
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
return kept;
@@ -2291,15 +2312,16 @@
stackId = FULLSCREEN_WORKSPACE_STACK_ID;
}
- if (task.stack != null) {
+ final ActivityStack currentStack = task.getStack();
+ if (currentStack != null) {
// Task has already been restored once. See if we need to do anything more
- if (task.stack.mStackId == stackId) {
+ if (currentStack.mStackId == stackId) {
// Nothing else to do since it is already restored in the right stack.
return true;
}
// Remove current stack association, so we can re-associate the task with the
// right stack below.
- task.stack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
+ currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
}
final ActivityStack stack =
@@ -2343,7 +2365,7 @@
}
final ActivityRecord r = task.topRunningActivityLocked();
- final ActivityStack prevStack = task.stack;
+ final ActivityStack prevStack = task.getStack();
final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
final boolean wasResumed = prevStack.mResumedActivity == r;
// In some cases the focused stack isn't the front stack. E.g. pinned stack.
@@ -2393,7 +2415,8 @@
return false;
}
- if (task.stack != null && task.stack.mStackId == stackId) {
+ final ActivityStack currentStack = task.getStack();
+ if (currentStack != null && currentStack.mStackId == stackId) {
// You are already in the right stack silly...
Slog.i(TAG, "moveTaskToStack: taskId=" + taskId + " already in stackId=" + stackId);
return true;
@@ -2405,7 +2428,7 @@
}
final ActivityRecord topActivity = task.getTopActivity();
- final int sourceStackId = task.stack != null ? task.stack.mStackId : INVALID_STACK_ID;
+ final int sourceStackId = task.getStackId();
final boolean mightReplaceWindow =
StackId.replaceWindowsOnTaskMove(sourceStackId, stackId) && topActivity != null;
if (mightReplaceWindow) {
@@ -2505,7 +2528,7 @@
try {
final TaskRecord task = r.task;
- if (r == task.stack.getVisibleBehindActivity()) {
+ if (r == task.getStack().getVisibleBehindActivity()) {
// An activity can't be pinned and visible behind at the same time. Go ahead and
// release it from been visible behind before pinning.
requestVisibleBehindLocked(r, false);
@@ -2555,13 +2578,13 @@
}
final TaskRecord task = r.task;
- if (task == null || task.stack == null) {
+ final ActivityStack stack = r.getStack();
+ if (stack == null) {
Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: r="
+ r + " task=" + task);
return false;
}
- final ActivityStack stack = task.stack;
if (stack == mFocusedStack && stack.topRunningActivityLocked() == r) {
if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
"moveActivityStackToFront: already on top, r=" + r);
@@ -2586,7 +2609,7 @@
task.updateOverrideConfigurationForStack(stack);
mWindowManager.positionTaskInStack(
- taskId, stackId, position, task.mBounds, task.mOverrideConfig);
+ taskId, stackId, position, task.mBounds, task.getOverrideConfiguration());
stack.positionTask(task, position);
// The task might have already been running and its visibility needs to be synchronized with
// the visibility of the stack / windows.
@@ -2771,7 +2794,7 @@
}
boolean reportResumedActivityLocked(ActivityRecord r) {
- final ActivityStack stack = r.task.stack;
+ final ActivityStack stack = r.getStack();
if (isFocusedStack(stack)) {
mService.updateUsageStats(r, true);
}
@@ -2795,7 +2818,7 @@
}
boolean requestVisibleBehindLocked(ActivityRecord r, boolean visible) {
- final ActivityStack stack = r.task.stack;
+ final ActivityStack stack = r.getStack();
if (stack == null) {
if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG_VISIBLE_BEHIND,
"requestVisibleBehind: r=" + r + " visible=" + visible + " stack is null");
@@ -2859,12 +2882,12 @@
}
// Called when WindowManager has finished animating the launchingBehind activity to the back.
- void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
+ private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
final TaskRecord task = r.task;
- final ActivityStack stack = task.stack;
+ final ActivityStack stack = task.getStack();
r.mLaunchTaskBehind = false;
- task.setLastThumbnailLocked(stack.screenshotActivitiesLocked(r));
+ task.setLastThumbnailLocked(r.screenshotActivityLocked());
mRecentTasks.addLocked(task);
mService.notifyTaskStackChangedLocked();
mWindowManager.setAppVisibility(r.appToken, false);
@@ -3606,7 +3629,7 @@
lockTaskModeState != LOCK_TASK_MODE_NONE);
resumeFocusedStackTopActivityLocked();
} else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
- handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+ handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.getStackId(),
true /* forceNonResizable */);
}
}
@@ -3715,7 +3738,7 @@
}
void scheduleReportPictureInPictureModeChangedIfNeeded(TaskRecord task, ActivityStack prevStack) {
- final ActivityStack stack = task.stack;
+ final ActivityStack stack = task.getStack();
if (prevStack == null || prevStack == stack
|| (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) {
return;
@@ -4227,7 +4250,7 @@
/** Exactly one of these classes per Display in the system. Capable of holding zero or more
* attached {@link ActivityStack}s */
- class ActivityDisplay {
+ class ActivityDisplay extends ConfigurationContainer {
/** Actual Display this object tracks. */
int mDisplayId;
Display mDisplay;
@@ -4287,6 +4310,21 @@
public String toString() {
return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
}
+
+ @Override
+ protected int getChildCount() {
+ return mStacks.size();
+ }
+
+ @Override
+ protected ConfigurationContainer getChildAt(int index) {
+ return mStacks.get(index);
+ }
+
+ @Override
+ protected ConfigurationContainer getParent() {
+ return ActivityStackSupervisor.this;
+ }
}
class VirtualActivityDisplay extends ActivityDisplay {
@@ -4392,7 +4430,7 @@
focusedStack != null ? focusedStack.topActivity() : null;
if (launchStackId != INVALID_STACK_ID) {
- if (task.stack.mStackId != launchStackId) {
+ if (task.getStackId() != launchStackId) {
moveTaskToStackLocked(
taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents",
ANIMATE);
@@ -4418,8 +4456,8 @@
mService.mActivityStarter.postStartActivityUncheckedProcessing(task.getTopActivity(),
ActivityManager.START_TASK_TO_FRONT,
- sourceRecord != null ? sourceRecord.task.stack.mStackId : INVALID_STACK_ID,
- sourceRecord, task.stack);
+ sourceRecord != null ? sourceRecord.task.getStackId() : INVALID_STACK_ID,
+ sourceRecord, task.getStack());
return ActivityManager.START_TASK_TO_FRONT;
}
callingUid = task.mCallingUid;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 028c6ac..a834af7 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -98,6 +98,7 @@
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.hardware.power.V1_0.PowerHint;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -360,7 +361,7 @@
}
}
- final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
+ final ActivityStack resultStack = resultRecord == null ? null : resultRecord.getStack();
if (err != START_SUCCESS) {
if (resultRecord != null) {
@@ -469,9 +470,9 @@
}
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
- intent, resolvedType, aInfo, mService.mGlobalConfiguration, resultRecord, resultWho,
- requestCode, componentSpecified, voiceSession != null, mSupervisor, container,
- options, sourceRecord);
+ intent, resolvedType, aInfo, mService.getGlobalConfiguration(), resultRecord,
+ resultWho, requestCode, componentSpecified, voiceSession != null, mSupervisor,
+ container, options, sourceRecord);
if (outActivity != null) {
outActivity[0] = r;
}
@@ -591,8 +592,9 @@
}
int startedActivityStackId = INVALID_STACK_ID;
- if (r.task != null && r.task.stack != null) {
- startedActivityStackId = r.task.stack.mStackId;
+ final ActivityStack currentStack = r.getStack();
+ if (currentStack != null) {
+ startedActivityStackId = currentStack.mStackId;
} else if (mTargetStack != null) {
startedActivityStackId = targetStack.mStackId;
}
@@ -780,7 +782,7 @@
stack = container.mStack;
}
stack.mConfigWillChange = globalConfig != null
- && mService.mGlobalConfiguration.diff(globalConfig) != 0;
+ && mService.getGlobalConfiguration().diff(globalConfig) != 0;
if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
"Starting activity when config will change = " + stack.mConfigWillChange);
@@ -1002,7 +1004,7 @@
curTop.task != null && mStartActivity != null &&
curTop.task != mStartActivity.task )) &&
mService.mLocalPowerManager != null) {
- mService.mLocalPowerManager.powerHint(PowerManagerInternal.POWER_HINT_LAUNCH, 1);
+ mService.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 1);
mPowerHintSent = true;
}
}
@@ -1010,7 +1012,7 @@
void sendPowerHintForLaunchEndIfNeeded() {
// Trigger launch power hint if activity is launched
if (mPowerHintSent && mService.mLocalPowerManager != null) {
- mService.mLocalPowerManager.powerHint(PowerManagerInternal.POWER_HINT_LAUNCH, 0);
+ mService.mLocalPowerManager.powerHint(PowerHint.LAUNCH, 0);
mPowerHintSent = false;
}
}
@@ -1099,10 +1101,12 @@
}
if (mStartActivity.packageName == null) {
- if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
- mStartActivity.resultTo.task.stack.sendActivityResultLocked(
- -1, mStartActivity.resultTo, mStartActivity.resultWho,
- mStartActivity.requestCode, RESULT_CANCELED, null);
+ final ActivityStack sourceStack = mStartActivity.resultTo != null
+ ? mStartActivity.resultTo.getStack() : null;
+ if (sourceStack != null) {
+ sourceStack.sendActivityResultLocked(-1 /* callingUid */, mStartActivity.resultTo,
+ mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED,
+ null /* data */);
}
ActivityOptions.abort(mOptions);
return START_CLASS_NOT_FOUND;
@@ -1312,15 +1316,17 @@
}
private void sendNewTaskResultRequestIfNeeded() {
- if (mStartActivity.resultTo != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
- && mStartActivity.resultTo.task.stack != null) {
+ final ActivityStack sourceStack = mStartActivity.resultTo != null
+ ? mStartActivity.resultTo.getStack() : null;
+ if (sourceStack != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
// For whatever reason this activity is being launched into a new task...
// yet the caller has requested a result back. Well, that is pretty messed up,
// so instead immediately send back a cancel and let the new task continue launched
// as normal without a dependency on its originator.
Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
- mStartActivity.resultTo.task.stack.sendActivityResultLocked(-1, mStartActivity.resultTo,
- mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED, null);
+ sourceStack.sendActivityResultLocked(-1 /* callingUid */, mStartActivity.resultTo,
+ mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED,
+ null /* data */);
mStartActivity.resultTo = null;
}
}
@@ -1328,7 +1334,7 @@
private void computeLaunchingTaskFlags() {
// If the caller is not coming from another activity, but has given us an explicit task into
// which they would like us to launch the new activity, then let's see about doing that.
- if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
+ if (mSourceRecord == null && mInTask != null && mInTask.getStack() != null) {
final Intent baseIntent = mInTask.getBaseIntent();
final ActivityRecord root = mInTask.getRootActivity();
if (baseIntent == null) {
@@ -1415,7 +1421,7 @@
return;
}
if (!mSourceRecord.finishing) {
- mSourceStack = mSourceRecord.task.stack;
+ mSourceStack = mSourceRecord.getStack();
return;
}
@@ -1474,7 +1480,7 @@
}
private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
- mTargetStack = intentActivity.task.stack;
+ mTargetStack = intentActivity.getStack();
mTargetStack.mLastPausedActivity = null;
// If the target task is not in the front, then we need to bring it to the front...
// except... well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
@@ -1606,7 +1612,7 @@
// is put in the right place.
mSourceRecord = intentActivity;
final TaskRecord task = mSourceRecord.task;
- if (task != null && task.stack == null) {
+ if (task != null && task.getStack() == null) {
// Target stack got cleared when we all activities were removed above.
// Go ahead and reset it.
mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
@@ -1722,18 +1728,19 @@
}
final TaskRecord sourceTask = mSourceRecord.task;
+ final ActivityStack sourceStack = mSourceRecord.getStack();
// We only want to allow changing stack if the target task is not the top one,
// otherwise we would move the launching task to the other side, rather than show
// two side by side.
- final boolean moveStackAllowed = sourceTask.stack.topTask() != sourceTask;
+ final boolean moveStackAllowed = sourceStack.topTask() != sourceTask;
if (moveStackAllowed) {
mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
mOptions);
}
if (mTargetStack == null) {
- mTargetStack = sourceTask.stack;
- } else if (mTargetStack != sourceTask.stack) {
+ mTargetStack = sourceStack;
+ } else if (mTargetStack != sourceStack) {
mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId,
ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
}
@@ -1800,7 +1807,7 @@
if (mLaunchBounds != null) {
mInTask.updateOverrideConfiguration(mLaunchBounds);
int stackId = mInTask.getLaunchStackId();
- if (stackId != mInTask.stack.mStackId) {
+ if (stackId != mInTask.getStackId()) {
final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(
mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
stackId = stack.mStackId;
@@ -1809,7 +1816,7 @@
mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
}
}
- mTargetStack = mInTask.stack;
+ mTargetStack = mInTask.getStack();
mTargetStack.moveTaskToFrontLocked(
mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");
@@ -1916,10 +1923,10 @@
return stack;
}
- if (task != null && task.stack != null) {
- stack = task.stack;
- if (stack.isOnHomeDisplay()) {
- if (mSupervisor.mFocusedStack != stack) {
+ final ActivityStack currentStack = task != null ? task.getStack() : null;
+ if (currentStack != null) {
+ if (currentStack.isOnHomeDisplay()) {
+ if (mSupervisor.mFocusedStack != currentStack) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
"computeStackFocus: Setting " + "focused stack to r=" + r
+ " task=" + task);
@@ -1929,7 +1936,7 @@
+ mSupervisor.mFocusedStack);
}
}
- return stack;
+ return currentStack;
}
final ActivityStackSupervisor.ActivityContainer container = r.mInitialActivityContainer;
@@ -1980,7 +1987,7 @@
// We are reusing a task, keep the stack!
if (mReuseTask != null) {
- return mReuseTask.stack;
+ return mReuseTask.getStack();
}
final int launchStackId =
@@ -2001,7 +2008,7 @@
// The parent activity doesn't want to launch the activity on top of itself, but
// instead tries to put it onto other side in side-by-side mode.
- final ActivityStack parentStack = task != null ? task.stack
+ final ActivityStack parentStack = task != null ? task.getStack()
: r.mInitialActivityContainer != null ? r.mInitialActivityContainer.mStack
: mSupervisor.mFocusedStack;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 3b4b8d6..4e69162 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -228,7 +228,8 @@
public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
final Intent intent = r.intent;
for (int i = mParallelBroadcasts.size() - 1; i >= 0; i--) {
- if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
+ final Intent curIntent = mParallelBroadcasts.get(i).intent;
+ if (intent.filterEquals(curIntent)) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"***** DROPPING PARALLEL ["
+ mQueueName + "]: " + intent);
@@ -267,7 +268,7 @@
r.receiver = app.thread.asBinder();
r.curApp = app;
- app.curReceiver = r;
+ app.curReceivers.add(r);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
mService.updateLruProcessLocked(app, false, null);
mService.updateOomAdjLocked();
@@ -295,7 +296,7 @@
"Process cur broadcast " + r + ": NOT STARTED!");
r.receiver = null;
r.curApp = null;
- app.curReceiver = null;
+ app.curReceivers.remove(r);
}
}
}
@@ -396,8 +397,8 @@
}
r.receiver = null;
r.intent.setComponent(null);
- if (r.curApp != null && r.curApp.curReceiver == r) {
- r.curApp.curReceiver = null;
+ if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
+ r.curApp.curReceivers.remove(r);
}
if (r.curFilter != null) {
r.curFilter.receiverList.curBroadcast = null;
@@ -650,7 +651,7 @@
// things that directly call the IActivityManager API, which
// are already core system stuff so don't matter for this.
r.curApp = filter.receiverList.app;
- filter.receiverList.app.curReceiver = r;
+ filter.receiverList.app.curReceivers.add(r);
mService.updateOomAdjLocked(r.curApp);
}
}
@@ -678,7 +679,7 @@
r.curFilter = null;
filter.receiverList.curBroadcast = null;
if (filter.receiverList.app != null) {
- filter.receiverList.app.curReceiver = null;
+ filter.receiverList.app.curReceivers.remove(r);
}
}
}
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index 3437ae6..1e7911a 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -219,6 +219,9 @@
int _resultCode, String _resultData, Bundle _resultExtras, boolean _serialized,
boolean _sticky, boolean _initialSticky,
int _userId) {
+ if (_intent == null) {
+ throw new NullPointerException("Can't construct with a null intent");
+ }
queue = _queue;
intent = _intent;
targetComp = _intent.getComponent();
diff --git a/services/core/java/com/android/server/am/CompatModePackages.java b/services/core/java/com/android/server/am/CompatModePackages.java
index 0b282ed..bfc0456 100644
--- a/services/core/java/com/android/server/am/CompatModePackages.java
+++ b/services/core/java/com/android/server/am/CompatModePackages.java
@@ -38,6 +38,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -197,18 +198,19 @@
}
public CompatibilityInfo compatibilityInfoForPackageLocked(ApplicationInfo ai) {
- CompatibilityInfo ci = new CompatibilityInfo(ai, mService.mGlobalConfiguration.screenLayout,
- mService.mGlobalConfiguration.smallestScreenWidthDp,
+ final Configuration globalConfig = mService.getGlobalConfiguration();
+ CompatibilityInfo ci = new CompatibilityInfo(ai, globalConfig.screenLayout,
+ globalConfig.smallestScreenWidthDp,
(getPackageFlags(ai.packageName)&COMPAT_FLAG_ENABLED) != 0);
//Slog.i(TAG, "*********** COMPAT FOR PKG " + ai.packageName + ": " + ci);
return ci;
}
public int computeCompatModeLocked(ApplicationInfo ai) {
- boolean enabled = (getPackageFlags(ai.packageName)&COMPAT_FLAG_ENABLED) != 0;
- CompatibilityInfo info = new CompatibilityInfo(ai,
- mService.mGlobalConfiguration.screenLayout,
- mService.mGlobalConfiguration.smallestScreenWidthDp, enabled);
+ final boolean enabled = (getPackageFlags(ai.packageName)&COMPAT_FLAG_ENABLED) != 0;
+ final Configuration globalConfig = mService.getGlobalConfiguration();
+ final CompatibilityInfo info = new CompatibilityInfo(ai, globalConfig.screenLayout,
+ globalConfig.smallestScreenWidthDp, enabled);
if (info.alwaysSupportsScreen()) {
return ActivityManager.COMPAT_MODE_NEVER;
}
@@ -383,7 +385,8 @@
}
if (starting != null) {
- stack.ensureActivityConfigurationLocked(starting, 0, false);
+ starting.ensureActivityConfigurationLocked(0 /* globalChanges */,
+ false /* preserveWindow */);
// And we need to make sure at this point that all other activities
// are made visible with the correct configuration.
stack.ensureActivitiesVisibleLocked(starting, 0, !PRESERVE_WINDOWS);
@@ -408,8 +411,9 @@
out.startTag(null, "compat-packages");
final IPackageManager pm = AppGlobals.getPackageManager();
- final int screenLayout = mService.mGlobalConfiguration.screenLayout;
- final int smallestScreenWidthDp = mService.mGlobalConfiguration.smallestScreenWidthDp;
+ final Configuration globalConfig = mService.getGlobalConfiguration();
+ final int screenLayout = globalConfig.screenLayout;
+ final int smallestScreenWidthDp = globalConfig.smallestScreenWidthDp;
final Iterator<Map.Entry<String, Integer>> it = pkgs.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Integer> entry = it.next();
diff --git a/services/core/java/com/android/server/am/ConfigurationContainer.java b/services/core/java/com/android/server/am/ConfigurationContainer.java
new file mode 100644
index 0000000..30f5309
--- /dev/null
+++ b/services/core/java/com/android/server/am/ConfigurationContainer.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import android.content.res.Configuration;
+
+/**
+ * Contains common logic for classes that have override configurations and are organized in a
+ * hierarchy.
+ */
+abstract class ConfigurationContainer<E extends ConfigurationContainer> {
+
+ /** Contains override configuration settings applied to this configuration container. */
+ private Configuration mOverrideConfiguration = new Configuration();
+
+ /**
+ * Contains full configuration applied to this configuration container. Corresponds to full
+ * parent's config with applied {@link #mOverrideConfiguration}.
+ */
+ private Configuration mFullConfiguration = new Configuration();
+
+ /**
+ * Contains merged override configuration settings from the top of the hierarchy down to this
+ * particular instance. It is different from {@link #mFullConfiguration} because it starts from
+ * topmost container's override config instead of global config.
+ */
+ private Configuration mMergedOverrideConfiguration = new Configuration();
+
+ /**
+ * Returns full configuration applied to this configuration container.
+ * This method should be used for getting settings applied in each particular level of the
+ * hierarchy.
+ */
+ Configuration getConfiguration() {
+ return mFullConfiguration;
+ }
+
+ /**
+ * Notify that parent config changed and we need to update full configuration.
+ * @see #mFullConfiguration
+ */
+ void onConfigurationChanged(Configuration newParentConfig) {
+ mFullConfiguration.setTo(newParentConfig);
+ mFullConfiguration.updateFrom(mOverrideConfiguration);
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ConfigurationContainer child = getChildAt(i);
+ child.onConfigurationChanged(mFullConfiguration);
+ }
+ }
+
+ /** Returns override configuration applied to this configuration container. */
+ Configuration getOverrideConfiguration() {
+ return mOverrideConfiguration;
+ }
+
+ /**
+ * Update override configuration and recalculate full config.
+ * @see #mOverrideConfiguration
+ * @see #mFullConfiguration
+ */
+ void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
+ mOverrideConfiguration.setTo(overrideConfiguration);
+ // Update full configuration of this container and all its children.
+ final ConfigurationContainer parent = getParent();
+ onConfigurationChanged(parent != null ? parent.getConfiguration() : Configuration.EMPTY);
+ // Update merged override config of this container and all its children.
+ onMergedOverrideConfigurationChanged();
+ }
+
+ /**
+ * Get merged override configuration from the top of the hierarchy down to this particular
+ * instance. This should be reported to client as override config.
+ */
+ Configuration getMergedOverrideConfiguration() {
+ return mMergedOverrideConfiguration;
+ }
+
+ /**
+ * Update merged override configuration based on corresponding parent's config and notify all
+ * its children. If there is no parent, merged override configuration will set equal to current
+ * override config.
+ * @see #mMergedOverrideConfiguration
+ */
+ private void onMergedOverrideConfigurationChanged() {
+ final ConfigurationContainer parent = getParent();
+ if (parent != null) {
+ mMergedOverrideConfiguration.setTo(parent.getMergedOverrideConfiguration());
+ mMergedOverrideConfiguration.updateFrom(mOverrideConfiguration);
+ } else {
+ mMergedOverrideConfiguration.setTo(mOverrideConfiguration);
+ }
+ for (int i = getChildCount() - 1; i >= 0; --i) {
+ final ConfigurationContainer child = getChildAt(i);
+ child.onMergedOverrideConfigurationChanged();
+ }
+ }
+
+ /**
+ * Must be called when new parent for the container was set.
+ */
+ void onParentChanged() {
+ final ConfigurationContainer parent = getParent();
+ // Update full configuration of this container and all its children.
+ onConfigurationChanged(parent != null ? parent.mFullConfiguration : Configuration.EMPTY);
+ // Update merged override configuration of this container and all its children.
+ onMergedOverrideConfigurationChanged();
+ }
+
+ abstract protected int getChildCount();
+
+ abstract protected E getChildAt(int index);
+
+ abstract protected ConfigurationContainer getParent();
+}
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 9c08453..c494171 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -296,9 +296,10 @@
}
break;
case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
- if (key.activity.task.stack != null) {
- key.activity.task.stack.sendActivityResultLocked(-1, key.activity,
- key.who, key.requestCode, code, finalIntent);
+ final ActivityStack stack = key.activity.getStack();
+ if (stack != null) {
+ stack.sendActivityResultLocked(-1, key.activity, key.who,
+ key.requestCode, code, finalIntent);
}
break;
case ActivityManager.INTENT_SENDER_BROADCAST:
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 3fffefb..49fe79c 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -143,7 +143,7 @@
Bundle instrumentationArguments;// as given to us
ComponentName instrumentationResultClass;// copy of instrumentationClass
boolean usingWrapper; // Set to true when process was launched with a wrapper attached
- BroadcastRecord curReceiver;// receiver currently running in the app
+ final ArraySet<BroadcastRecord> curReceivers = new ArraySet<BroadcastRecord>();// receivers currently running in the app
long lastWakeTime; // How long proc held wake lock at last check
long lastCpuTime; // How long proc has run CPU at last check
long curCpuTime; // How long proc has run CPU most recently
@@ -427,8 +427,11 @@
pw.print(prefix); pw.print(" - "); pw.println(conProviders.get(i).toShortString());
}
}
- if (curReceiver != null) {
- pw.print(prefix); pw.print("curReceiver="); pw.println(curReceiver);
+ if (!curReceivers.isEmpty()) {
+ pw.print(prefix); pw.println("Current Receivers:");
+ for (int i=0; i < curReceivers.size(); i++) {
+ pw.print(prefix); pw.print(" - "); pw.println(curReceivers.valueAt(i));
+ }
}
if (receivers.size() > 0) {
pw.print(prefix); pw.println("Receivers:");
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index beb863b..bc9bda2f 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -129,7 +129,8 @@
}
void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
- if (task != null && task.stack != null && task.stack.isHomeStack()) {
+ final ActivityStack stack = task != null ? task.getStack() : null;
+ if (stack != null && stack.isHomeStack()) {
// Never persist the home stack.
return;
}
@@ -147,8 +148,9 @@
}
}
for (int i = size() - 1; i >= 0; i--) {
- TaskRecord task = get(i);
- if (task.isPersistable && (task.stack == null || !task.stack.isHomeStack())) {
+ final TaskRecord task = get(i);
+ final ActivityStack stack = task.getStack();
+ if (task.isPersistable && (stack == null || !stack.isHomeStack())) {
// Set of persisted taskIds for task.userId should not be null here
// TODO Investigate why it can happen. For now initialize with an empty set
if (mPersistedTaskIds.get(task.userId) == null) {
@@ -618,10 +620,12 @@
final Intent intent = task.intent;
final boolean document = intent != null && intent.isDocument();
int maxRecents = task.maxRecents - 1;
+ final ActivityStack stack = task.getStack();
for (int i = 0; i < recentsCount; i++) {
final TaskRecord tr = get(i);
+ final ActivityStack trStack = tr.getStack();
if (task != tr) {
- if (task.stack != null && tr.stack != null && task.stack != tr.stack) {
+ if (stack != null && trStack != null && stack != trStack) {
continue;
}
if (task.userId != tr.userId) {
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 43eb251..0817f0d 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -639,8 +639,9 @@
final TaskRecord task = mRecentTasks.get(taskNdx);
if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task +
" persistable=" + task.isPersistable);
+ final ActivityStack stack = task.getStack();
if ((task.isPersistable || task.inRecents)
- && (task.stack == null || !task.stack.isHomeStack())) {
+ && (stack == null || !stack.isHomeStack())) {
if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
persistentTaskIds.add(task.taskId);
} else {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 6cc4d73..77d0db3 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -56,6 +56,8 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -67,15 +69,13 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
import static android.content.pm.ActivityInfo.FLAG_ON_TOP_LAUNCHER;
+import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-import static android.content.res.Configuration.SCREENLAYOUT_LONG_MASK;
-import static android.content.res.Configuration.SCREENLAYOUT_SIZE_MASK;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
@@ -93,18 +93,18 @@
import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
-final class TaskRecord {
+final class TaskRecord extends ConfigurationContainer {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
- static final String ATTR_TASKID = "task_id";
+ private static final String ATTR_TASKID = "task_id";
private static final String TAG_INTENT = "intent";
private static final String TAG_AFFINITYINTENT = "affinity_intent";
- static final String ATTR_REALACTIVITY = "real_activity";
- static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
+ private static final String ATTR_REALACTIVITY = "real_activity";
+ private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
private static final String ATTR_ORIGACTIVITY = "orig_activity";
private static final String TAG_ACTIVITY = "activity";
private static final String ATTR_AFFINITY = "affinity";
@@ -121,7 +121,7 @@
private static final String ATTR_LASTDESCRIPTION = "last_description";
private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
- static final String ATTR_TASK_AFFILIATION = "task_affiliation";
+ private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
@@ -137,7 +137,7 @@
private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
static final int INVALID_TASK_ID = -1;
- static final int INVALID_MIN_SIZE = -1;
+ private static final int INVALID_MIN_SIZE = -1;
final int taskId; // Unique identifier for this task.
String affinity; // The affinity name for this task, or null; may change identity.
@@ -173,8 +173,8 @@
// Based on the {@link ActivityInfo#resizeMode} of the root activity.
boolean mTemporarilyUnresizable; // Separate flag from mResizeMode used to suppress resize
// changes on a temporary basis.
- int mLockTaskMode; // Which tasklock mode to launch this task in. One of
- // ActivityManager.LOCK_TASK_LAUNCH_MODE_*
+ private int mLockTaskMode; // Which tasklock mode to launch this task in. One of
+ // ActivityManager.LOCK_TASK_LAUNCH_MODE_*
private boolean mPrivileged; // The root activity application of this task holds
// privileged permissions.
private boolean mIsOnTopLauncher; // Whether this task is an on-top launcher. See
@@ -202,8 +202,8 @@
/** List of all activities in the task arranged in history order */
final ArrayList<ActivityRecord> mActivities;
- /** Current stack */
- ActivityStack stack;
+ /** Current stack. Setter must always be used to update the value. */
+ private ActivityStack mStack;
/** Takes on same set of values as ActivityRecord.mActivityType */
int taskType;
@@ -223,7 +223,7 @@
private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
/** If original intent did not allow relinquishing task identity, save that information */
- boolean mNeverRelinquishIdentity = true;
+ private boolean mNeverRelinquishIdentity = true;
// Used in the unique case where we are clearing the task in order to reuse it. In that case we
// do not want to delete the stack when the task goes empty.
@@ -271,8 +271,8 @@
// This number will be assigned when we evaluate OOM scores for all visible tasks.
int mLayerRank = -1;
- /** Contains configurations settings that are different from the parent's configuration. */
- Configuration mOverrideConfig = Configuration.EMPTY;
+ /** Helper object used for updating override configuration. */
+ private Configuration mTmpConfig = new Configuration();
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
@@ -402,7 +402,7 @@
private void setIntent(Intent _intent, ActivityInfo info) {
if (intent == null) {
mNeverRelinquishIdentity =
- (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0;
+ (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
} else if (mNeverRelinquishIdentity) {
return;
}
@@ -527,6 +527,38 @@
mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId;
}
+ ActivityStack getStack() {
+ return mStack;
+ }
+
+ /** Must be used for setting parent stack because it performs configuration updates. */
+ void setStack(ActivityStack stack) {
+ mStack = stack;
+ onParentChanged();
+ }
+
+ /**
+ * @return Id of current stack, {@link INVALID_STACK_ID} if no stack is set.
+ */
+ int getStackId() {
+ return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
+ }
+
+ @Override
+ protected int getChildCount() {
+ return 0;
+ }
+
+ @Override
+ protected ConfigurationContainer getChildAt(int index) {
+ return null;
+ }
+
+ @Override
+ protected ConfigurationContainer getParent() {
+ return mStack;
+ }
+
// Close up recents linked list.
void closeRecentsChain() {
if (mPrevAffiliate != null) {
@@ -576,23 +608,26 @@
* @return whether the thumbnail was set
*/
boolean setLastThumbnailLocked(Bitmap thumbnail) {
- final Configuration serviceConfig = mService.mGlobalConfiguration;
int taskWidth = 0;
int taskHeight = 0;
if (mBounds != null) {
// Non-fullscreen tasks
taskWidth = mBounds.width();
taskHeight = mBounds.height();
- } else if (stack != null) {
+ } else if (mStack != null) {
// Fullscreen tasks
final Point displaySize = new Point();
- stack.getDisplaySize(displaySize);
+ mStack.getDisplaySize(displaySize);
taskWidth = displaySize.x;
taskHeight = displaySize.y;
} else {
Slog.e(TAG, "setLastThumbnailLocked() called on Task without stack");
}
- return setLastThumbnailLocked(thumbnail, taskWidth, taskHeight, serviceConfig.orientation);
+ // We need to provide the current orientation of the display on which this task resides,
+ // not the orientation of the task.
+ final int orientation =
+ getStack().mActivityContainer.mActivityDisplay.getConfiguration().orientation;
+ return setLastThumbnailLocked(thumbnail, taskWidth, taskHeight, orientation);
}
/**
@@ -681,7 +716,7 @@
}
ActivityRecord topRunningActivityLocked() {
- if (stack != null) {
+ if (mStack != null) {
for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord r = mActivities.get(activityNdx);
if (!r.finishing && r.okToShowLocked()) {
@@ -693,7 +728,7 @@
}
ActivityRecord topRunningActivityWithStartingWindowLocked() {
- if (stack != null) {
+ if (mStack != null) {
for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord r = mActivities.get(activityNdx);
if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
@@ -817,7 +852,7 @@
mService.notifyTaskPersisterLocked(this, false);
}
- if (stack != null && stack.mStackId == PINNED_STACK_ID) {
+ if (getStackId() == PINNED_STACK_ID) {
// We normally notify listeners of task stack changes on pause, however pinned stack
// activities are normally in the paused state so no notification will be sent there
// before the activity is removed. We send it here so instead.
@@ -849,13 +884,13 @@
if (r.finishing) {
continue;
}
- if (stack == null) {
+ if (mStack == null) {
// Task was restored from persistent storage.
r.takeFromHistory();
mActivities.remove(activityNdx);
--activityNdx;
--numActivities;
- } else if (stack.finishActivityLocked(
+ } else if (mStack.finishActivityLocked(
r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) {
--activityNdx;
--numActivities;
@@ -910,7 +945,7 @@
if (opts != null) {
ret.updateOptionsLocked(opts);
}
- if (stack != null && stack.finishActivityLocked(
+ if (mStack != null && mStack.finishActivityLocked(
r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
--activityNdx;
--numActivities;
@@ -924,8 +959,8 @@
&& (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
&& !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
if (!ret.finishing) {
- if (stack != null) {
- stack.finishActivityLocked(
+ if (mStack != null) {
+ mStack.finishActivityLocked(
ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
}
return null;
@@ -939,11 +974,11 @@
return null;
}
- public TaskThumbnail getTaskThumbnailLocked() {
- if (stack != null) {
- final ActivityRecord resumedActivity = stack.mResumedActivity;
+ TaskThumbnail getTaskThumbnailLocked() {
+ if (mStack != null) {
+ final ActivityRecord resumedActivity = mStack.mResumedActivity;
if (resumedActivity != null && resumedActivity.task == this) {
- final Bitmap thumbnail = stack.screenshotActivitiesLocked(resumedActivity);
+ final Bitmap thumbnail = resumedActivity.screenshotActivityLocked();
setLastThumbnailLocked(thumbnail);
}
}
@@ -952,7 +987,7 @@
return taskThumbnail;
}
- public void removeTaskActivitiesLocked() {
+ void removeTaskActivitiesLocked() {
// Just remove the entire task.
performClearTaskAtIndexLocked(0);
}
@@ -1032,20 +1067,16 @@
}
boolean isResizeable() {
- return !isHomeTask() && (mService.mForceResizableActivities
- || ActivityInfo.isResizeableMode(mResizeMode)) && !mTemporarilyUnresizable;
+ return (mService.mForceResizableActivities || ActivityInfo.isResizeableMode(mResizeMode))
+ && !mTemporarilyUnresizable;
}
boolean isOnTopLauncher() {
return isHomeTask() && mIsOnTopLauncher;
}
- boolean inCropWindowsResizeMode() {
- return !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
- }
-
boolean canGoInDockedStack() {
- return isResizeable() || inCropWindowsResizeMode();
+ return isResizeable();
}
/**
@@ -1072,12 +1103,12 @@
// utility activities.
int activityNdx;
final int numActivities = mActivities.size();
- final boolean relinquish = numActivities == 0 ? false :
- (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0;
+ final boolean relinquish = numActivities != 0 &&
+ (mActivities.get(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0;
for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
++activityNdx) {
final ActivityRecord r = mActivities.get(activityNdx);
- if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
+ if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
// This will be the top activity for determining taskDescription. Pre-inc to
// overcome initial decrement below.
++activityNdx;
@@ -1132,7 +1163,7 @@
continue;
}
effectiveNdx = activityNdx;
- if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
+ if ((r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
break;
}
}
@@ -1327,8 +1358,6 @@
callingPackage = attrValue;
} else if (ATTR_RESIZE_MODE.equals(attrName)) {
resizeMode = Integer.parseInt(attrValue);
- resizeMode = (resizeMode == RESIZE_MODE_CROP_WINDOWS)
- ? RESIZE_MODE_FORCE_RESIZEABLE : resizeMode;
} else if (ATTR_PRIVILEGED.equals(attrName)) {
privileged = Boolean.parseBoolean(attrValue);
} else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
@@ -1417,7 +1446,7 @@
// If the task has no requested minimal size, we'd like to enforce a minimal size
// so that the user can not render the task too small to manipulate. We don't need
// to do this for the pinned stack as the bounds are controlled by the system.
- if (stack.mStackId != PINNED_STACK_ID) {
+ if (getStackId() != PINNED_STACK_ID) {
if (minWidth == INVALID_MIN_SIZE) {
minWidth = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask;
}
@@ -1472,16 +1501,17 @@
if (Objects.equals(mBounds, bounds)) {
return false;
}
- final Configuration oldConfig = mOverrideConfig;
+ mTmpConfig.setTo(getOverrideConfiguration());
final boolean oldFullscreen = mFullscreen;
+ final Configuration newConfig = getOverrideConfiguration();
mFullscreen = bounds == null;
if (mFullscreen) {
- if (mBounds != null && StackId.persistTaskBounds(stack.mStackId)) {
+ if (mBounds != null && StackId.persistTaskBounds(mStack.mStackId)) {
mLastNonFullscreenBounds = mBounds;
}
mBounds = null;
- mOverrideConfig = Configuration.EMPTY;
+ newConfig.unset();
} else {
mTmpRect.set(bounds);
adjustForMinimalTaskDimensions(mTmpRect);
@@ -1490,18 +1520,19 @@
} else {
mBounds.set(mTmpRect);
}
- if (stack == null || StackId.persistTaskBounds(stack.mStackId)) {
+ if (mStack == null || StackId.persistTaskBounds(mStack.mStackId)) {
mLastNonFullscreenBounds = mBounds;
}
- mOverrideConfig = calculateOverrideConfig(mTmpRect, insetBounds,
+ calculateOverrideConfig(newConfig, mTmpRect, insetBounds,
mTmpRect.right != bounds.right, mTmpRect.bottom != bounds.bottom);
}
+ onOverrideConfigurationChanged(newConfig);
if (mFullscreen != oldFullscreen) {
mService.mStackSupervisor.scheduleReportMultiWindowModeChanged(this);
}
- return !mOverrideConfig.equals(oldConfig);
+ return !mTmpConfig.equals(newConfig);
}
private void subtractNonDecorInsets(Rect inOutBounds, Rect inInsetBounds,
@@ -1526,8 +1557,9 @@
inOutBounds.inset(leftInset, topInset, rightInset, bottomInset);
}
- private Configuration calculateOverrideConfig(Rect bounds, Rect insetBounds,
- boolean overrideWidth, boolean overrideHeight) {
+ /** Clears passed config and fills it with new override values. */
+ private void calculateOverrideConfig(Configuration config, Rect bounds, Rect insetBounds,
+ boolean overrideWidth, boolean overrideHeight) {
mTmpNonDecorBounds.set(bounds);
mTmpStableBounds.set(bounds);
subtractNonDecorInsets(
@@ -1537,16 +1569,16 @@
mTmpStableBounds, insetBounds != null ? insetBounds : bounds,
overrideWidth, overrideHeight);
- // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen area,
+ // For calculating screenWidthDp, screenHeightDp, we use the stable inset screen area,
// i.e. the screen area without the system bars.
- final Configuration serviceConfig = mService.mGlobalConfiguration;
- final Configuration config = new Configuration(Configuration.EMPTY);
- // TODO(multidisplay): Update Dp to that of display stack is on.
- final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+ // Additionally task dimensions should not be bigger than its parents dimensions.
+ final Configuration parentConfig = getParent().getConfiguration();
+ config.unset();
+ final float density = parentConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
config.screenWidthDp =
- Math.min((int)(mTmpStableBounds.width() / density), serviceConfig.screenWidthDp);
+ Math.min((int)(mTmpStableBounds.width() / density), parentConfig.screenWidthDp);
config.screenHeightDp =
- Math.min((int)(mTmpStableBounds.height() / density), serviceConfig.screenHeightDp);
+ Math.min((int)(mTmpStableBounds.height() / density), parentConfig.screenHeightDp);
// TODO: Orientation?
config.orientation = (config.screenWidthDp <= config.screenHeightDp)
@@ -1558,14 +1590,15 @@
// never go away in Honeycomb.
final int compatScreenWidthDp = (int)(mTmpNonDecorBounds.width() / density);
final int compatScreenHeightDp = (int)(mTmpNonDecorBounds.height() / density);
- final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout);
+ // We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start override
+ // calculation with partial default.
+ final int sl = Configuration.SCREENLAYOUT_LONG_YES | Configuration.SCREENLAYOUT_SIZE_XLARGE;
final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
- final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);;
+ final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
config.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
config.smallestScreenWidthDp = mService.mWindowManager.getSmallestWidthForTaskBounds(
insetBounds != null ? insetBounds : bounds);
- return config;
}
/**
@@ -1574,12 +1607,14 @@
* {@param config}.
*/
Configuration extractOverrideConfig(Configuration config) {
- final Configuration extracted = new Configuration(Configuration.EMPTY);
+ final Configuration extracted = new Configuration();
extracted.screenWidthDp = config.screenWidthDp;
extracted.screenHeightDp = config.screenHeightDp;
extracted.smallestScreenWidthDp = config.smallestScreenWidthDp;
extracted.orientation = config.orientation;
- extracted.screenLayout = config.screenLayout;
+ // We're only overriding LONG, SIZE and COMPAT parts of screenLayout.
+ extracted.screenLayout = config.screenLayout & (Configuration.SCREENLAYOUT_LONG_MASK
+ | Configuration.SCREENLAYOUT_SIZE_MASK | Configuration.SCREENLAYOUT_COMPAT_NEEDED);
return extracted;
}
@@ -1592,29 +1627,6 @@
return bounds;
}
- /**
- * Update fields that are not overridden for task from global configuration.
- *
- * @param globalConfig global configuration to update from.
- */
- void sanitizeOverrideConfiguration(Configuration globalConfig) {
- // If it's fullscreen, the override config should be empty and we should leave it alone.
- if (mFullscreen) {
- return;
- }
-
- // screenLayout field is set in #calculateOverrideConfig but only part of it is really
- // overridden - aspect ratio and size. Other flags (like layout direction) can be updated
- // separately in global config and they also must be updated in override config.
- int overrideScreenLayout = mOverrideConfig.screenLayout;
- int newScreenLayout = globalConfig.screenLayout;
- newScreenLayout = (newScreenLayout & ~SCREENLAYOUT_LONG_MASK)
- | (overrideScreenLayout & SCREENLAYOUT_LONG_MASK);
- newScreenLayout = (newScreenLayout & ~SCREENLAYOUT_SIZE_MASK)
- | (overrideScreenLayout & SCREENLAYOUT_SIZE_MASK);
- mOverrideConfig.screenLayout = newScreenLayout;
- }
-
static Rect validateBounds(Rect bounds) {
if (bounds != null && bounds.isEmpty()) {
Slog.wtf(TAG, "Received strange task bounds: " + bounds, new Throwable());
@@ -1626,7 +1638,7 @@
/** Updates the task's bounds and override configuration to match what is expected for the
* input stack. */
void updateOverrideConfigurationForStack(ActivityStack inStack) {
- if (stack != null && stack == inStack) {
+ if (mStack != null && mStack == inStack) {
return;
}
@@ -1670,17 +1682,17 @@
return null;
}
- if (stack == null) {
+ if (mStack == null) {
return null;
}
- final int stackId = stack.mStackId;
+ final int stackId = mStack.mStackId;
if (stackId == HOME_STACK_ID
|| stackId == FULLSCREEN_WORKSPACE_STACK_ID
|| (stackId == DOCKED_STACK_ID && !isResizeable())) {
- return isResizeable() ? stack.mBounds : null;
+ return isResizeable() ? mStack.mBounds : null;
} else if (!StackId.persistTaskBounds(stackId)) {
- return stack.mBounds;
+ return mStack.mBounds;
}
return mLastNonFullscreenBounds;
}
@@ -1688,7 +1700,7 @@
boolean canMatchRootAffinity() {
// We don't allow root affinity matching on the pinned stack as no other task should
// be launching in it based on affinity.
- return rootAffinity != null && (stack == null || stack.mStackId != PINNED_STACK_ID);
+ return rootAffinity != null && getStackId() != PINNED_STACK_ID;
}
void dump(PrintWriter pw, String prefix) {
@@ -1779,9 +1791,7 @@
if (lastDescription != null) {
pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
}
- if (stack != null) {
- pw.print(prefix); pw.print("stackId="); pw.println(stack.mStackId);
- }
+ pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
pw.print(" isResizeable=" + isResizeable());
@@ -1798,7 +1808,7 @@
sb.append(" U=");
sb.append(userId);
sb.append(" StackId=");
- sb.append(stack != null ? stack.mStackId : INVALID_STACK_ID);
+ sb.append(getStackId());
sb.append(" sz=");
sb.append(mActivities.size());
sb.append('}');
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index ba42d3f..9697855 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -115,7 +115,7 @@
// Amount of time we wait for observers to handle a user switch before
// giving up on them and unfreezing the screen.
- static final int USER_SWITCH_TIMEOUT = 2 * 1000;
+ static final int USER_SWITCH_TIMEOUT = 3 * 1000;
private final Object mLock;
private final Injector mInjector;
@@ -1103,6 +1103,7 @@
mCurWaitingUserSwitchCallbacks = curWaitingUserSwitchCallbacks;
}
final AtomicInteger waitingCallbacksCount = new AtomicInteger(observerCount);
+ final long dispatchStartedTime = SystemClock.elapsedRealtime();
for (int i = 0; i < observerCount; i++) {
try {
// Prepend with unique prefix to guarantee that keys are unique
@@ -1114,6 +1115,11 @@
@Override
public void sendResult(Bundle data) throws RemoteException {
synchronized (mLock) {
+ long delay = SystemClock.elapsedRealtime() - dispatchStartedTime;
+ if (delay > USER_SWITCH_TIMEOUT) {
+ Slog.wtf(TAG, "User switch timeout: observer " + name
+ + " sent result after " + delay + " ms");
+ }
// Early return if this session is no longer valid
if (curWaitingUserSwitchCallbacks
!= mCurWaitingUserSwitchCallbacks) {
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index ff8014c..48238b6 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -87,7 +87,7 @@
state = newState;
}
- private static String stateToString(int state) {
+ static String stateToString(int state) {
switch (state) {
case STATE_BOOTING: return "BOOTING";
case STATE_RUNNING_LOCKED: return "RUNNING_LOCKED";
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 66aa403..5772a57 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -20,7 +20,6 @@
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IActivityManager;
-import android.content.BroadcastReceiver;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ContentProvider;
@@ -28,7 +27,6 @@
import android.content.IOnPrimaryClipChangedListener;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -47,23 +45,57 @@
import android.util.Slog;
import android.util.SparseArray;
+import com.android.server.SystemService;
+
import java.util.HashSet;
import java.util.List;
/**
* Implementation of the clipboard for copy and paste.
*/
-public class ClipboardService extends IClipboard.Stub {
+public class ClipboardService extends SystemService {
private static final String TAG = "ClipboardService";
- private final Context mContext;
private final IActivityManager mAm;
private final IUserManager mUm;
private final PackageManager mPm;
private final AppOpsManager mAppOps;
private final IBinder mPermissionOwner;
+ private final SparseArray<PerUserClipboard> mClipboards = new SparseArray<>();
+
+ /**
+ * Instantiates the clipboard.
+ */
+ public ClipboardService(Context context) {
+ super(context);
+
+ mAm = ActivityManagerNative.getDefault();
+ mPm = getContext().getPackageManager();
+ mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
+ mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
+ IBinder permOwner = null;
+ try {
+ permOwner = mAm.newUriPermissionOwner("clipboard");
+ } catch (RemoteException e) {
+ Slog.w("clipboard", "AM dead", e);
+ }
+ mPermissionOwner = permOwner;
+ }
+
+ @Override
+ public void onStart() {
+ publishBinderService(Context.CLIPBOARD_SERVICE, new ClipboardImpl());
+ }
+
+ @Override
+ public void onCleanupUser(int userId) {
+ synchronized (mClipboards) {
+ mClipboards.remove(userId);
+ }
+ }
+
private class ListenerInfo {
final int mUid;
final String mPackageName;
@@ -89,52 +121,141 @@
}
}
- private SparseArray<PerUserClipboard> mClipboards = new SparseArray<PerUserClipboard>();
+ private class ClipboardImpl extends IClipboard.Stub {
+ @Override
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ try {
+ return super.onTransact(code, data, reply, flags);
+ } catch (RuntimeException e) {
+ if (!(e instanceof SecurityException)) {
+ Slog.wtf("clipboard", "Exception: ", e);
+ }
+ throw e;
+ }
- /**
- * Instantiates the clipboard.
- */
- public ClipboardService(Context context) {
- mContext = context;
- mAm = ActivityManagerNative.getDefault();
- mPm = context.getPackageManager();
- mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
- mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
- IBinder permOwner = null;
- try {
- permOwner = mAm.newUriPermissionOwner("clipboard");
- } catch (RemoteException e) {
- Slog.w("clipboard", "AM dead", e);
}
- mPermissionOwner = permOwner;
- // Remove the clipboard if a user is removed
- IntentFilter userFilter = new IntentFilter();
- userFilter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_USER_REMOVED.equals(action)) {
- removeClipboard(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+ @Override
+ public void setPrimaryClip(ClipData clip, String callingPackage) {
+ synchronized (this) {
+ if (clip != null && clip.getItemCount() <= 0) {
+ throw new IllegalArgumentException("No items");
+ }
+ final int callingUid = Binder.getCallingUid();
+ if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid,
+ callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ return;
+ }
+ checkDataOwnerLocked(clip, callingUid);
+ final int userId = UserHandle.getUserId(callingUid);
+ PerUserClipboard clipboard = getClipboard(userId);
+ revokeUris(clipboard);
+ setPrimaryClipInternal(clipboard, clip);
+ List<UserInfo> related = getRelatedProfiles(userId);
+ if (related != null) {
+ int size = related.size();
+ if (size > 1) { // Related profiles list include the current profile.
+ boolean canCopy = false;
+ try {
+ canCopy = !mUm.getUserRestrictions(userId).getBoolean(
+ UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote Exception calling UserManager: " + e);
+ }
+ // Copy clip data to related users if allowed. If disallowed, then remove
+ // primary clip in related users to prevent pasting stale content.
+ if (!canCopy) {
+ clip = null;
+ } else {
+ // We want to fix the uris of the related user's clip without changing the
+ // uris of the current user's clip.
+ // So, copy the ClipData, and then copy all the items, so that nothing
+ // is shared in memmory.
+ clip = new ClipData(clip);
+ for (int i = clip.getItemCount() - 1; i >= 0; i--) {
+ clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
+ }
+ clip.fixUrisLight(userId);
+ }
+ for (int i = 0; i < size; i++) {
+ int id = related.get(i).id;
+ if (id != userId) {
+ setPrimaryClipInternal(getClipboard(id), clip);
+ }
+ }
+ }
}
}
- }, userFilter);
- }
-
- @Override
- public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- try {
- return super.onTransact(code, data, reply, flags);
- } catch (RuntimeException e) {
- if (!(e instanceof SecurityException)) {
- Slog.wtf("clipboard", "Exception: ", e);
- }
- throw e;
}
-
- }
+
+ @Override
+ public ClipData getPrimaryClip(String pkg) {
+ synchronized (this) {
+ if (mAppOps.noteOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
+ pkg) != AppOpsManager.MODE_ALLOWED) {
+ return null;
+ }
+ addActiveOwnerLocked(Binder.getCallingUid(), pkg);
+ return getClipboard().primaryClip;
+ }
+ }
+
+ @Override
+ public ClipDescription getPrimaryClipDescription(String callingPackage) {
+ synchronized (this) {
+ if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
+ callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ return null;
+ }
+ PerUserClipboard clipboard = getClipboard();
+ return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null;
+ }
+ }
+
+ @Override
+ public boolean hasPrimaryClip(String callingPackage) {
+ synchronized (this) {
+ if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
+ callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ return false;
+ }
+ return getClipboard().primaryClip != null;
+ }
+ }
+
+ @Override
+ public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
+ String callingPackage) {
+ synchronized (this) {
+ getClipboard().primaryClipListeners.register(listener,
+ new ListenerInfo(Binder.getCallingUid(), callingPackage));
+ }
+ }
+
+ @Override
+ public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
+ synchronized (this) {
+ getClipboard().primaryClipListeners.unregister(listener);
+ }
+ }
+
+ @Override
+ public boolean hasClipboardText(String callingPackage) {
+ synchronized (this) {
+ if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
+ callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ return false;
+ }
+ PerUserClipboard clipboard = getClipboard();
+ if (clipboard.primaryClip != null) {
+ CharSequence text = clipboard.primaryClip.getItemAt(0).getText();
+ return text != null && text.length() > 0;
+ }
+ return false;
+ }
+ }
+ };
private PerUserClipboard getClipboard() {
return getClipboard(UserHandle.getCallingUserId());
@@ -151,64 +272,6 @@
}
}
- private void removeClipboard(int userId) {
- synchronized (mClipboards) {
- mClipboards.remove(userId);
- }
- }
-
- public void setPrimaryClip(ClipData clip, String callingPackage) {
- synchronized (this) {
- if (clip != null && clip.getItemCount() <= 0) {
- throw new IllegalArgumentException("No items");
- }
- final int callingUid = Binder.getCallingUid();
- if (mAppOps.noteOp(AppOpsManager.OP_WRITE_CLIPBOARD, callingUid,
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return;
- }
- checkDataOwnerLocked(clip, callingUid);
- final int userId = UserHandle.getUserId(callingUid);
- PerUserClipboard clipboard = getClipboard(userId);
- revokeUris(clipboard);
- setPrimaryClipInternal(clipboard, clip);
- List<UserInfo> related = getRelatedProfiles(userId);
- if (related != null) {
- int size = related.size();
- if (size > 1) { // Related profiles list include the current profile.
- boolean canCopy = false;
- try {
- canCopy = !mUm.getUserRestrictions(userId).getBoolean(
- UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote Exception calling UserManager: " + e);
- }
- // Copy clip data to related users if allowed. If disallowed, then remove
- // primary clip in related users to prevent pasting stale content.
- if (!canCopy) {
- clip = null;
- } else {
- // We want to fix the uris of the related user's clip without changing the
- // uris of the current user's clip.
- // So, copy the ClipData, and then copy all the items, so that nothing
- // is shared in memmory.
- clip = new ClipData(clip);
- for (int i = clip.getItemCount() - 1; i >= 0; i--) {
- clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i)));
- }
- clip.fixUrisLight(userId);
- }
- for (int i = 0; i < size; i++) {
- int id = related.get(i).id;
- if (id != userId) {
- setPrimaryClipInternal(getClipboard(id), clip);
- }
- }
- }
- }
- }
- }
-
List<UserInfo> getRelatedProfiles(int userId) {
final List<UserInfo> related;
final long origId = Binder.clearCallingIdentity();
@@ -251,67 +314,6 @@
Binder.restoreCallingIdentity(ident);
}
}
-
- public ClipData getPrimaryClip(String pkg) {
- synchronized (this) {
- if (mAppOps.noteOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
- pkg) != AppOpsManager.MODE_ALLOWED) {
- return null;
- }
- addActiveOwnerLocked(Binder.getCallingUid(), pkg);
- return getClipboard().primaryClip;
- }
- }
-
- public ClipDescription getPrimaryClipDescription(String callingPackage) {
- synchronized (this) {
- if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return null;
- }
- PerUserClipboard clipboard = getClipboard();
- return clipboard.primaryClip != null ? clipboard.primaryClip.getDescription() : null;
- }
- }
-
- public boolean hasPrimaryClip(String callingPackage) {
- synchronized (this) {
- if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return false;
- }
- return getClipboard().primaryClip != null;
- }
- }
-
- public void addPrimaryClipChangedListener(IOnPrimaryClipChangedListener listener,
- String callingPackage) {
- synchronized (this) {
- getClipboard().primaryClipListeners.register(listener,
- new ListenerInfo(Binder.getCallingUid(), callingPackage));
- }
- }
-
- public void removePrimaryClipChangedListener(IOnPrimaryClipChangedListener listener) {
- synchronized (this) {
- getClipboard().primaryClipListeners.unregister(listener);
- }
- }
-
- public boolean hasClipboardText(String callingPackage) {
- synchronized (this) {
- if (mAppOps.checkOp(AppOpsManager.OP_READ_CLIPBOARD, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return false;
- }
- PerUserClipboard clipboard = getClipboard();
- if (clipboard.primaryClip != null) {
- CharSequence text = clipboard.primaryClip.getItemAt(0).getText();
- return text != null && text.length() > 0;
- }
- return false;
- }
- }
private final void checkUriOwnerLocked(Uri uri, int uid) {
if (!"content".equals(uri.getScheme())) {
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index e7198d3..363d7cb 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -134,7 +134,9 @@
@Override
// Called concurrently by multiple binder threads.
- public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs) {
+ // This method must not block or perform long-running operations.
+ public synchronized void onDnsEvent(int netId, int eventType, int returnCode, int latencyMs,
+ String hostname, String[] ipAddresses, int ipAddressesCount, int uid) {
maybeVerboseLog(String.format("onDnsEvent(%d, %d, %d, %d)",
netId, eventType, returnCode, latencyMs));
@@ -146,6 +148,14 @@
batch.addResult((byte) eventType, (byte) returnCode, latencyMs);
}
+ @Override
+ // Called concurrently by multiple binder threads.
+ // This method must not block or perform long-running operations.
+ public synchronized void onConnectEvent(int netId, int latencyMs, String ipAddr, int port,
+ int uid) {
+ maybeVerboseLog(String.format("onConnectEvent(%d, %d)", netId, latencyMs));
+ }
+
public synchronized void dump(PrintWriter writer) {
IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
pw.println(TAG + ":");
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 50faf3b..921fd23 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -405,11 +405,13 @@
// Check carrier config for entitlement checks
final CarrierConfigManager configManager = (CarrierConfigManager) mContext
.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
- CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
-
- if (!isEntitlementCheckRequired) {
- return false;
+ if (configManager != null && configManager.getConfig() != null) {
+ // we do have a CarrierConfigManager and it has a config.
+ boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
+ CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
+ if (!isEntitlementCheckRequired) {
+ return false;
+ }
}
return (provisionApp.length == 2);
}
@@ -895,7 +897,7 @@
}
} else {
mUsbTetherRequested = true;
- usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS);
+ usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
}
} else {
final long ident = Binder.clearCallingIdentity();
@@ -905,7 +907,7 @@
Binder.restoreCallingIdentity(ident);
}
if (mRndisEnabled) {
- usbManager.setCurrentFunction(null);
+ usbManager.setCurrentFunction(null, false);
}
mUsbTetherRequested = false;
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index ede3bda..afc6247 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -27,6 +27,8 @@
import android.annotation.UserIdInt;
import android.app.AppGlobals;
import android.app.AppOpsManager;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -76,6 +78,7 @@
import android.util.ArraySet;
import android.util.Log;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.LegacyVpnInfo;
@@ -241,12 +244,14 @@
/**
* Update current state, dispaching event to listeners.
*/
- private void updateState(DetailedState detailedState, String reason) {
+ @VisibleForTesting
+ protected void updateState(DetailedState detailedState, String reason) {
if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason);
mNetworkInfo.setDetailedState(detailedState, reason, null);
if (mNetworkAgent != null) {
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
}
+ updateAlwaysOnNotification(detailedState);
}
/**
@@ -280,7 +285,10 @@
}
mLockdown = (mAlwaysOn && lockdown);
- if (!isCurrentPreparedPackage(packageName)) {
+ if (isCurrentPreparedPackage(packageName)) {
+ updateAlwaysOnNotification(mNetworkInfo.getDetailedState());
+ } else {
+ // Prepare this app. The notification will update as a side-effect of updateState().
prepareInternal(packageName);
}
maybeRegisterPackageChangeReceiverLocked(packageName);
@@ -682,22 +690,19 @@
}
}
- private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) {
- networkInfo.setIsAvailable(false);
- networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
+ private void agentDisconnect(NetworkAgent networkAgent) {
if (networkAgent != null) {
+ NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
+ networkInfo.setIsAvailable(false);
+ networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
networkAgent.sendNetworkInfo(networkInfo);
}
}
- private void agentDisconnect(NetworkAgent networkAgent) {
- NetworkInfo networkInfo = new NetworkInfo(mNetworkInfo);
- agentDisconnect(networkInfo, networkAgent);
- }
-
private void agentDisconnect() {
if (mNetworkInfo.isConnected()) {
- agentDisconnect(mNetworkInfo, mNetworkAgent);
+ mNetworkInfo.setIsAvailable(false);
+ updateState(DetailedState.DISCONNECTED, "agentDisconnect");
mNetworkAgent = null;
}
}
@@ -1250,6 +1255,43 @@
}
}
+ private void updateAlwaysOnNotification(DetailedState networkState) {
+ final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
+ updateAlwaysOnNotificationInternal(visible);
+ }
+
+ @VisibleForTesting
+ protected void updateAlwaysOnNotificationInternal(boolean visible) {
+ final UserHandle user = UserHandle.of(mUserHandle);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final NotificationManager notificationManager = NotificationManager.from(mContext);
+ if (!visible) {
+ notificationManager.cancelAsUser(TAG, 0, user);
+ return;
+ }
+ final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS);
+ final PendingIntent configIntent = PendingIntent.getActivityAsUser(
+ mContext, /* request */ 0, intent,
+ PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
+ null, user);
+ final Notification.Builder builder = new Notification.Builder(mContext)
+ .setDefaults(0)
+ .setSmallIcon(R.drawable.vpn_connected)
+ .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
+ .setContentText(mContext.getString(R.string.vpn_lockdown_config))
+ .setContentIntent(configIntent)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setPriority(Notification.PRIORITY_LOW)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setOngoing(true)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color));
+ notificationManager.notifyAsUser(TAG, 0, builder.build(), user);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private native int jniCreate(int mtu);
private native String jniGetName(int tun);
private native int jniSetAddresses(String interfaze, String addresses);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 2d6bef4..72feab7 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -795,7 +795,17 @@
* Use {@link AuthorityInfo#UNDEFINED} to sync all authorities.
*/
public void scheduleSync(Account requestedAccount, int userId, int reason,
- String requestedAuthority, Bundle extras, int targetSyncState) {
+ String requestedAuthority, Bundle extras, int targetSyncState) {
+ scheduleSync(requestedAccount, userId, reason, requestedAuthority, extras, targetSyncState,
+ 0 /* min delay */);
+ }
+
+ /**
+ * @param minDelayMillis The sync can't land before this delay expires.
+ */
+ private void scheduleSync(Account requestedAccount, int userId, int reason,
+ String requestedAuthority, Bundle extras, int targetSyncState,
+ final long minDelayMillis) {
final boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
if (extras == null) {
extras = new Bundle();
@@ -906,7 +916,7 @@
if (result != null
&& result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT)) {
scheduleSync(account.account, userId, reason, authority,
- finalExtras, targetSyncState);
+ finalExtras, targetSyncState, minDelayMillis);
}
}
));
@@ -967,7 +977,8 @@
postScheduleSyncMessage(
new SyncOperation(account.account, account.userId,
owningUid, owningPackage, reason, source,
- authority, newExtras, allowParallelSyncs)
+ authority, newExtras, allowParallelSyncs),
+ minDelayMillis
);
} else if (targetSyncState == AuthorityInfo.UNDEFINED
|| targetSyncState == isSyncable) {
@@ -982,7 +993,8 @@
postScheduleSyncMessage(
new SyncOperation(account.account, account.userId,
owningUid, owningPackage, reason, source,
- authority, extras, allowParallelSyncs)
+ authority, extras, allowParallelSyncs),
+ minDelayMillis
);
}
}
@@ -1088,14 +1100,14 @@
}
/**
- * Schedule sync based on local changes to a provider. Occurs within interval
- * [LOCAL_SYNC_DELAY, 2*LOCAL_SYNC_DELAY].
+ * Schedule sync based on local changes to a provider. We wait for at least LOCAL_SYNC_DELAY
+ * ms to batch syncs.
*/
public void scheduleLocalSync(Account account, int userId, int reason, String authority) {
final Bundle extras = new Bundle();
extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
scheduleSync(account, userId, reason, authority, extras,
- AuthorityInfo.UNDEFINED);
+ AuthorityInfo.UNDEFINED, LOCAL_SYNC_DELAY);
}
public SyncAdapterType[] getSyncAdapterTypes(int userId) {
@@ -1152,9 +1164,10 @@
mSyncHandler.sendMessageDelayed(monitorMessage, SYNC_MONITOR_WINDOW_LENGTH_MILLIS);
}
- private void postScheduleSyncMessage(SyncOperation syncOperation) {
- mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_SCHEDULE_SYNC, syncOperation)
- .sendToTarget();
+ private void postScheduleSyncMessage(SyncOperation syncOperation, long minDelayMillis) {
+ ScheduleSyncMessagePayload payload =
+ new ScheduleSyncMessagePayload(syncOperation, minDelayMillis);
+ mSyncHandler.obtainMessage(mSyncHandler.MESSAGE_SCHEDULE_SYNC, payload).sendToTarget();
}
/**
@@ -1194,6 +1207,16 @@
}
}
+ private static class ScheduleSyncMessagePayload {
+ final SyncOperation syncOperation;
+ final long minDelayMillis;
+
+ ScheduleSyncMessagePayload(SyncOperation syncOperation, long minDelayMillis) {
+ this.syncOperation = syncOperation;
+ this.minDelayMillis = minDelayMillis;
+ }
+ }
+
private void clearBackoffSetting(EndPoint target) {
Pair<Long, Long> backoff = mSyncStorageEngine.getBackoff(target);
if (backoff != null && backoff.first == SyncStorageEngine.NOT_IN_BACKOFF_MODE &&
@@ -1262,7 +1285,7 @@
if (!op.isPeriodic && op.target.matchesSpec(target)) {
count++;
getJobScheduler().cancel(op.jobId);
- postScheduleSyncMessage(op);
+ postScheduleSyncMessage(op, 0 /* min delay */);
}
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -2417,8 +2440,10 @@
mDataConnectionIsConnected = readDataConnectionState();
switch (msg.what) {
case MESSAGE_SCHEDULE_SYNC:
- SyncOperation op = (SyncOperation) msg.obj;
- scheduleSyncOperationH(op);
+ ScheduleSyncMessagePayload syncPayload =
+ (ScheduleSyncMessagePayload) msg.obj;
+ SyncOperation op = syncPayload.syncOperation;
+ scheduleSyncOperationH(op, syncPayload.minDelayMillis);
break;
case MESSAGE_START_SYNC:
@@ -3101,7 +3126,8 @@
maybeRescheduleSync(syncResult, syncOperation);
} else {
// create a normal sync instance that will respect adapter backoffs
- postScheduleSyncMessage(syncOperation.createOneTimeSyncOperation());
+ postScheduleSyncMessage(syncOperation.createOneTimeSyncOperation(),
+ 0 /* min delay */);
}
historyMessage = ContentResolver.syncErrorToString(
syncResultToErrorNumber(syncResult));
diff --git a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
index cca9f10..353f450 100644
--- a/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
+++ b/services/core/java/com/android/server/emergency/EmergencyAffordanceService.java
@@ -99,6 +99,7 @@
};
private boolean mSimNeedsEmergencyAffordance;
private boolean mNetworkNeedsEmergencyAffordance;
+ private boolean mVoiceCapable;
private void requestCellScan() {
mHandler.obtainMessage(CELL_INFO_STATE_CHANGED).sendToTarget();
@@ -125,8 +126,8 @@
private void updateEmergencyAffordanceNeeded() {
synchronized (mLock) {
- mEmergencyAffordanceNeeded = mSimNeedsEmergencyAffordance ||
- mNetworkNeedsEmergencyAffordance;
+ mEmergencyAffordanceNeeded = mVoiceCapable && (mSimNeedsEmergencyAffordance ||
+ mNetworkNeedsEmergencyAffordance);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
mEmergencyAffordanceNeeded ? 1 : 0);
@@ -157,6 +158,11 @@
public void onBootPhase(int phase) {
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+ mVoiceCapable = mTelephonyManager.isVoiceCapable();
+ if (!mVoiceCapable) {
+ updateEmergencyAffordanceNeeded();
+ return;
+ }
mSubscriptionManager = SubscriptionManager.from(mContext);
HandlerThread thread = new HandlerThread(TAG);
thread.start();
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index 87da866..5297589 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -115,6 +115,7 @@
final int result = daemon.authenticate(mOpId, getGroupId());
if (result != 0) {
Slog.w(TAG, "startAuthentication failed, result=" + result);
+ MetricsLogger.histogram(getContext(), "fingeprintd_auth_start_error", result);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
return result;
}
diff --git a/services/core/java/com/android/server/fingerprint/EnrollClient.java b/services/core/java/com/android/server/fingerprint/EnrollClient.java
index 6a533c9..640a46f 100644
--- a/services/core/java/com/android/server/fingerprint/EnrollClient.java
+++ b/services/core/java/com/android/server/fingerprint/EnrollClient.java
@@ -88,6 +88,7 @@
final int result = daemon.enroll(mCryptoToken, getGroupId(), timeout);
if (result != 0) {
Slog.w(TAG, "startEnroll failed, result=" + result);
+ MetricsLogger.histogram(getContext(), "fingerprintd_enroll_start_error", result);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
return result;
}
diff --git a/services/core/java/com/android/server/fingerprint/EnumerateClient.java b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
index 52dbd5d..26b1916 100644
--- a/services/core/java/com/android/server/fingerprint/EnumerateClient.java
+++ b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
@@ -23,6 +23,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
+import com.android.internal.logging.MetricsLogger;
/**
* A class to keep track of the enumeration state for a given client.
@@ -43,6 +44,7 @@
if (result != 0) {
Slog.w(TAG, "start enumerate for user " + getTargetUserId()
+ " failed, result=" + result);
+ MetricsLogger.histogram(getContext(), "fingerprintd_enum_start_error", result);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
return result;
}
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 5addffb..cda063d 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -194,7 +194,9 @@
@Override
public void binderDied() {
Slog.v(TAG, "fingerprintd died");
+ MetricsLogger.count(mContext, "fingerprintd_died", 1);
mDaemon = null;
+ mCurrentUserId = UserHandle.USER_CURRENT;
handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
}
@@ -210,6 +212,7 @@
updateActiveGroup(ActivityManager.getCurrentUser(), null);
} else {
Slog.w(TAG, "Failed to open Fingerprint HAL!");
+ MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
mDaemon = null;
}
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java
index bcf2264..f939f41 100644
--- a/services/core/java/com/android/server/fingerprint/RemovalClient.java
+++ b/services/core/java/com/android/server/fingerprint/RemovalClient.java
@@ -24,6 +24,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
+import com.android.internal.logging.MetricsLogger;
/**
* A class to keep track of the remove state for a given client.
@@ -46,6 +47,7 @@
final int result = daemon.remove(mFingerId, getGroupId());
if (result != 0) {
Slog.w(TAG, "startRemove with id = " + mFingerId + " failed, result=" + result);
+ MetricsLogger.histogram(getContext(), "fingerprintd_remove_start_error", result);
onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
return result;
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 5dc9d02..72ee218 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -2011,6 +2011,9 @@
@ServiceThreadOnly
void standby() {
assertRunOnServiceThread();
+ if (!canGoToStandby()) {
+ return;
+ }
mStandbyMessageReceived = true;
mPowerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0);
// PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets
@@ -2038,10 +2041,13 @@
@ServiceThreadOnly
private void onStandby(final int standbyAction) {
assertRunOnServiceThread();
- if (!canGoToStandby()) return;
mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY;
invokeVendorCommandListenersOnControlStateChanged(false,
HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY);
+ if (!canGoToStandby()) {
+ mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY;
+ return;
+ }
final List<HdmiCecLocalDevice> devices = getAllLocalDevices();
disableDevices(new PendingActionClearedCallback() {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index fe3a02d..970da99 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -216,7 +216,7 @@
private static final int DEFAULT_FG_JOB_COUNT = 4;
private static final int DEFAULT_BG_NORMAL_JOB_COUNT = 6;
private static final int DEFAULT_BG_MODERATE_JOB_COUNT = 4;
- private static final int DEFAULT_BG_LOW_JOB_COUNT = 2;
+ private static final int DEFAULT_BG_LOW_JOB_COUNT = 1;
private static final int DEFAULT_BG_CRITICAL_JOB_COUNT = 1;
/**
@@ -428,7 +428,18 @@
}
cancelJobsForUid(pkgUid, true);
}
- } catch (RemoteException e) { /* cannot happen */ }
+ } catch (RemoteException|IllegalArgumentException e) {
+ /*
+ * IllegalArgumentException means that the package doesn't exist.
+ * This arises when PACKAGE_CHANGED broadcast delivery has lagged
+ * behind outright uninstall, so by the time we try to act it's gone.
+ * We don't need to act on this PACKAGE_CHANGED when this happens;
+ * we'll get a PACKAGE_REMOVED later and clean up then.
+ *
+ * RemoteException can't actually happen; the package manager is
+ * running in this same process.
+ */
+ }
break;
}
}
@@ -906,7 +917,11 @@
private boolean isCurrentlyActiveLocked(JobStatus job) {
for (int i=0; i<mActiveServices.size(); i++) {
JobServiceContext serviceContext = mActiveServices.get(i);
- final JobStatus running = serviceContext.getRunningJob();
+ // The 'unsafe' direct-internal-reference running-job inspector is okay to
+ // use here because we are already holding the necessary lock *and* we
+ // immediately discard the returned object reference, if any; we return
+ // only a boolean state indicator to the caller.
+ final JobStatus running = serviceContext.getRunningJobUnsafeLocked();
if (running != null && running.matches(job.getUid(), job.getJobId())) {
return true;
}
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 27f397d..b089ba7 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -231,6 +231,15 @@
return job == null ? null : new JobStatus(job);
}
+ /**
+ * Internal non-cloning inspection of the currently running job, if any. The lock
+ * must be held when calling this *and* for the entire lifetime of using its returned
+ * JobStatus object!
+ */
+ JobStatus getRunningJobUnsafeLocked() {
+ return mRunningJob;
+ }
+
/** Called externally when a job that was scheduled for execution should be cancelled. */
void cancelExecutingJob(int reason) {
mCallbackHandler.obtainMessage(MSG_CANCEL, reason, 0 /* unused */).sendToTarget();
diff --git a/services/core/java/com/android/server/lights/Light.java b/services/core/java/com/android/server/lights/Light.java
index b18a181..0bab86b 100644
--- a/services/core/java/com/android/server/lights/Light.java
+++ b/services/core/java/com/android/server/lights/Light.java
@@ -16,25 +16,28 @@
package com.android.server.lights;
+import android.hardware.light.V2_0.Flash;
+import android.hardware.light.V2_0.Brightness;
+
public abstract class Light {
- public static final int LIGHT_FLASH_NONE = 0;
- public static final int LIGHT_FLASH_TIMED = 1;
- public static final int LIGHT_FLASH_HARDWARE = 2;
+ public static final int LIGHT_FLASH_NONE = Flash.NONE;
+ public static final int LIGHT_FLASH_TIMED = Flash.TIMED;
+ public static final int LIGHT_FLASH_HARDWARE = Flash.HARDWARE;
/**
* Light brightness is managed by a user setting.
*/
- public static final int BRIGHTNESS_MODE_USER = 0;
+ public static final int BRIGHTNESS_MODE_USER = Brightness.USER;
/**
* Light brightness is managed by a light sensor.
*/
- public static final int BRIGHTNESS_MODE_SENSOR = 1;
+ public static final int BRIGHTNESS_MODE_SENSOR = Brightness.SENSOR;
/**
* Low-persistence light mode.
*/
- public static final int BRIGHTNESS_MODE_LOW_PERSISTENCE = 2;
+ public static final int BRIGHTNESS_MODE_LOW_PERSISTENCE = Brightness.LOW_PERSISTENCE;
public abstract void setBrightness(int brightness);
public abstract void setBrightness(int brightness, int brightnessMode);
diff --git a/services/core/java/com/android/server/lights/LightsManager.java b/services/core/java/com/android/server/lights/LightsManager.java
index 2f20509..be20a44 100644
--- a/services/core/java/com/android/server/lights/LightsManager.java
+++ b/services/core/java/com/android/server/lights/LightsManager.java
@@ -16,16 +16,18 @@
package com.android.server.lights;
+import android.hardware.light.V2_0.Type;
+
public abstract class LightsManager {
- public static final int LIGHT_ID_BACKLIGHT = 0;
- public static final int LIGHT_ID_KEYBOARD = 1;
- public static final int LIGHT_ID_BUTTONS = 2;
- public static final int LIGHT_ID_BATTERY = 3;
- public static final int LIGHT_ID_NOTIFICATIONS = 4;
- public static final int LIGHT_ID_ATTENTION = 5;
- public static final int LIGHT_ID_BLUETOOTH = 6;
- public static final int LIGHT_ID_WIFI = 7;
- public static final int LIGHT_ID_COUNT = 8;
+ public static final int LIGHT_ID_BACKLIGHT = Type.BACKLIGHT;
+ public static final int LIGHT_ID_KEYBOARD = Type.KEYBOARD;
+ public static final int LIGHT_ID_BUTTONS = Type.BUTTONS;
+ public static final int LIGHT_ID_BATTERY = Type.BATTERY;
+ public static final int LIGHT_ID_NOTIFICATIONS = Type.NOTIFICATIONS;
+ public static final int LIGHT_ID_ATTENTION = Type.ATTENTION;
+ public static final int LIGHT_ID_BLUETOOTH = Type.BLUETOOTH;
+ public static final int LIGHT_ID_WIFI = Type.WIFI;
+ public static final int LIGHT_ID_COUNT = Type.COUNT;
public abstract Light getLight(int id);
}
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index ca64817..bba0a50 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -133,7 +133,7 @@
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x"
+ Integer.toHexString(color) + ")");
try {
- setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
+ setLight_native(mId, color, mode, onMS, offMS, brightnessMode);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
@@ -155,8 +155,6 @@
public LightsService(Context context) {
super(context);
- mNativePointer = init_native();
-
for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
mLights[i] = new LightImpl(i);
}
@@ -217,7 +215,7 @@
private final LightsManager mService = new LightsManager() {
@Override
public Light getLight(int id) {
- if (id < LIGHT_ID_COUNT) {
+ if (0 <= id && id < LIGHT_ID_COUNT) {
return mLights[id];
} else {
return null;
@@ -225,12 +223,6 @@
}
};
- @Override
- protected void finalize() throws Throwable {
- finalize_native(mNativePointer);
- super.finalize();
- }
-
private Handler mH = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -239,11 +231,6 @@
}
};
- private static native long init_native();
- private static native void finalize_native(long ptr);
-
- static native void setLight_native(long ptr, int light, int color, int mode,
+ static native void setLight_native(int light, int color, int mode,
int onMS, int offMS, int brightnessMode);
-
- private long mNativePointer;
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 7580cf4..ae98077 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -452,8 +452,12 @@
new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
- requestUtcTime();
- xtraDownloadRequest();
+ if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
+ requestUtcTime();
+ }
+ if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
+ xtraDownloadRequest();
+ }
}
};
@@ -1002,6 +1006,11 @@
}
private void handleDownloadXtraData() {
+ if (!mSupportsXtra) {
+ // native code reports xtra not supported, don't try
+ Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported");
+ return;
+ }
if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
// already downloading data
return;
@@ -2125,9 +2134,7 @@
handleInjectNtpTime();
break;
case DOWNLOAD_XTRA_DATA:
- if (mSupportsXtra) {
- handleDownloadXtraData();
- }
+ handleDownloadXtraData();
break;
case INJECT_NTP_TIME_FINISHED:
mInjectNtpTimePending = STATE_IDLE;
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 547cc51..2bccfee 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2046,25 +2046,30 @@
@Override
public void setRestrictBackground(boolean restrictBackground) {
- mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- final long token = Binder.clearCallingIdentity();
+ Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setRestrictBackground");
try {
- maybeRefreshTrustedTime();
- synchronized (mUidRulesFirstLock) {
- if (restrictBackground == mRestrictBackground) {
- // Ideally, UI should never allow this scenario...
- Slog.w(TAG, "setRestrictBackground: already " + restrictBackground);
- return;
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ maybeRefreshTrustedTime();
+ synchronized (mUidRulesFirstLock) {
+ if (restrictBackground == mRestrictBackground) {
+ // Ideally, UI should never allow this scenario...
+ Slog.w(TAG, "setRestrictBackground: already " + restrictBackground);
+ return;
+ }
+ setRestrictBackgroundUL(restrictBackground);
}
- setRestrictBackgroundUL(restrictBackground);
+
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
+ mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0)
+ .sendToTarget();
} finally {
- Binder.restoreCallingIdentity(token);
+ Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
-
- mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_CHANGED, restrictBackground ? 1 : 0, 0)
- .sendToTarget();
}
private void setRestrictBackgroundUL(boolean restrictBackground) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0c7c8aa..61bf3bd 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -30,6 +30,7 @@
import static android.service.notification.NotificationRankerService.REASON_PACKAGE_CHANGED;
import static android.service.notification.NotificationRankerService.REASON_PACKAGE_SUSPENDED;
import static android.service.notification.NotificationRankerService.REASON_PROFILE_TURNED_OFF;
+import static android.service.notification.NotificationRankerService.REASON_SNOOZED;
import static android.service.notification.NotificationRankerService.REASON_UNAUTOBUNDLED;
import static android.service.notification.NotificationRankerService.REASON_USER_STOPPED;
import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
@@ -309,6 +310,8 @@
private float mMaxPackageEnqueueRate = DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE;
private String mSystemNotificationSound;
+ private SnoozeHelper mSnoozeHelper;
+
private static class Archive {
final int mBufferSize;
final ArrayDeque<StatusBarNotification> mBuffer;
@@ -999,6 +1002,22 @@
sendRegisteredOnlyBroadcast(NotificationManager.ACTION_NOTIFICATION_POLICY_CHANGED);
}
});
+ mSnoozeHelper = new SnoozeHelper(getContext(), new SnoozeHelper.Callback() {
+ @Override
+ public void repost(int userId, NotificationRecord r) {
+ try {
+ if (DBG) {
+ Slog.d(TAG, "Reposting " + r.getKey());
+ }
+ enqueueNotificationInternal(r.sbn.getPackageName(), r.sbn.getOpPkg(),
+ r.sbn.getUid(), r.sbn.getInitialPid(), r.sbn.getTag(), r.sbn.getId(),
+ r.sbn.getNotification(), new int[1], userId);
+ } catch (Exception e) {
+ Slog.e(TAG, "Cannot un-snooze notification", e);
+ }
+ }
+ }, mUserProfiles);
+
final File systemDir = new File(Environment.getDataDirectory(), "system");
mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
@@ -1810,6 +1829,13 @@
}
}
+ /**
+ * Allow an INotificationListener to simulate clearing (dismissing) a single notification.
+ *
+ * {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
private void cancelNotificationFromListenerLocked(ManagedServiceInfo info,
int callingUid, int callingPid, String pkg, String tag, int id, int userId) {
cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
@@ -1819,6 +1845,23 @@
}
/**
+ * Allow an INotificationListener to snooze a single notification.
+ *
+ * @param token The binder for the listener, to check that the caller is allowed
+ */
+ @Override
+ public void snoozeNotificationFromListener(INotificationListener token, String key,
+ long snoozeUntil) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
+ snoozeNotificationInt(key, snoozeUntil, info);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
* Allow an INotificationListener to simulate clearing (dismissing) a single notification.
*
* {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
@@ -2592,6 +2635,11 @@
pw.println("\n Notification ranker services:");
mRankerServices.dump(pw, filter);
}
+
+ if (!zenOnly) {
+ mSnoozeHelper.dump(pw, filter);
+ }
+
pw.println("\n Policy access:");
pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
@@ -2765,6 +2813,16 @@
public void run() {
synchronized (mNotificationList) {
+ if (mSnoozeHelper.isSnoozed(userId, r.sbn.getPackageName(), r.getKey())) {
+ // TODO: log to event log
+ if (DBG) {
+ Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
+ }
+ mSnoozeHelper.update(userId, r);
+ savePolicyFile();
+ return;
+ }
+
final StatusBarNotification n = r.sbn;
if (DBG) Slog.d(TAG, "EnqueueNotificationRunnable.run for: " + n.getKey());
NotificationRecord old = mNotificationsByKey.get(n.getKey());
@@ -3578,6 +3636,11 @@
cancelGroupChildrenLocked(r, callingUid, callingPid, listenerName,
REASON_GROUP_SUMMARY_CANCELED, sendDelete);
updateLightsLocked();
+ } else {
+ final boolean wasSnoozed = mSnoozeHelper.cancel(userId, pkg, tag, id);
+ if (wasSnoozed) {
+ savePolicyFile();
+ }
}
}
}
@@ -3641,7 +3704,7 @@
if (pkg != null && !r.sbn.getPackageName().equals(pkg)) {
continue;
}
- if (channelId == null || !channelId.equals(r.getChannel().getId())) {
+ if (channelId != null && !channelId.equals(r.getChannel().getId())) {
continue;
}
if (canceledNotifications == null) {
@@ -3654,6 +3717,7 @@
mNotificationList.remove(i);
cancelNotificationLocked(r, false, reason);
}
+ mSnoozeHelper.cancel(userId, pkg);
if (doit && canceledNotifications != null) {
final int M = canceledNotifications.size();
for (int i = 0; i < M; i++) {
@@ -3668,6 +3732,28 @@
}
}
+ void snoozeNotificationInt(String key, long until, ManagedServiceInfo listener) {
+ String listenerName = listener == null ? null : listener.component.toShortString();
+ // TODO: write to event log
+ if (DBG) {
+ Slog.d(TAG, String.format("snooze event(%s, %d, %s)", key, until,
+ listenerName));
+ }
+ if (until < System.currentTimeMillis()) {
+ return;
+ }
+ synchronized (mNotificationList) {
+ final NotificationRecord r = mNotificationsByKey.get(key);
+ if (r != null) {
+ mNotificationList.remove(r);
+ cancelNotificationLocked(r, false, REASON_SNOOZED);
+ updateLightsLocked();
+ mSnoozeHelper.snooze(r, r.getUser().getIdentifier(), until);
+ savePolicyFile();
+ }
+ }
+ }
+
void cancelAllLocked(int callingUid, int callingPid, int userId, int reason,
ManagedServiceInfo listener, boolean includeCurrentProfiles) {
String listenerName = listener == null ? null : listener.component.toShortString();
@@ -3699,6 +3785,7 @@
canceledNotifications.add(r);
}
}
+ mSnoozeHelper.cancel(userId, includeCurrentProfiles);
int M = canceledNotifications != null ? canceledNotifications.size() : 0;
for (int i = 0; i < M; i++) {
cancelGroupChildrenLocked(canceledNotifications.get(i), callingUid, callingPid,
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 7182da1..d59115e 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -162,6 +162,7 @@
r = mRestoredWithoutUids.get(name);
if (r == null) {
r = new Record();
+ r.pkg = name;
mRestoredWithoutUids.put(name, r);
}
} else {
@@ -606,7 +607,7 @@
}
public void onPackagesChanged(boolean removingPackage, String[] pkgList) {
- if (!removingPackage || pkgList == null || pkgList.length == 0
+ if (removingPackage || pkgList == null || pkgList.length == 0
|| mRestoredWithoutUids.isEmpty()) {
return; // nothing to do
}
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
new file mode 100644
index 0000000..738403e
--- /dev/null
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.service.notification.StatusBarNotification;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Date;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * NotificationManagerService helper for handling snoozed notifications.
+ */
+public class SnoozeHelper {
+ private static final String TAG = "SnoozeHelper";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final String INDENT = " ";
+
+ private static final String REPOST_ACTION = SnoozeHelper.class.getSimpleName() + ".EVALUATE";
+ private static final int REQUEST_CODE_REPOST = 1;
+ private static final String REPOST_SCHEME = "repost";
+ private static final String EXTRA_PKG = "pkg";
+ private static final String EXTRA_KEY = "key";
+ private static final String EXTRA_USER_ID = "userId";
+
+ private final Context mContext;
+ private AlarmManager mAm;
+ private final ManagedServices.UserProfiles mUserProfiles;
+
+ // User id : package name : notification key : record.
+ private ArrayMap<Integer, ArrayMap<String, ArrayMap<String, NotificationRecord>>>
+ mSnoozedNotifications = new ArrayMap<>();
+ private Callback mCallback;
+
+ public SnoozeHelper(Context context, Callback callback,
+ ManagedServices.UserProfiles userProfiles) {
+ mContext = context;
+ IntentFilter filter = new IntentFilter(REPOST_ACTION);
+ filter.addDataScheme(REPOST_SCHEME);
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+ mAm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ mCallback = callback;
+ mUserProfiles = userProfiles;
+ }
+
+ protected boolean isSnoozed(int userId, String pkg, String key) {
+ return mSnoozedNotifications.containsKey(userId)
+ && mSnoozedNotifications.get(userId).containsKey(pkg)
+ && mSnoozedNotifications.get(userId).get(pkg).containsKey(key);
+ }
+
+ /**
+ * Records a notification that should be snoozed until the given time and schedules an alarm
+ * to repost at that time.
+ */
+ protected void snooze(NotificationRecord record, int userId, long until) {
+ ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
+ mSnoozedNotifications.get(userId);
+ if (records == null) {
+ records = new ArrayMap<>();
+ }
+ ArrayMap<String, NotificationRecord> pkgRecords = records.get(record.sbn.getPackageName());
+ if (pkgRecords == null) {
+ pkgRecords = new ArrayMap<>();
+ }
+ pkgRecords.put(record.getKey(), record);
+ records.put(record.sbn.getPackageName(), pkgRecords);
+ mSnoozedNotifications.put(userId, records);
+ if (DEBUG) {
+ Slog.d(TAG, "Snoozing " + record.getKey() + " until " + new Date(until));
+ }
+ scheduleRepost(record.sbn.getPackageName(), record.getKey(), userId, until);
+ }
+
+
+ protected boolean cancel(int userId, String pkg, String tag, int id) {
+ if (mSnoozedNotifications.containsKey(userId)) {
+ ArrayMap<String, NotificationRecord> recordsForPkg =
+ mSnoozedNotifications.get(userId).get(pkg);
+ if (recordsForPkg != null) {
+ final Set<Map.Entry<String, NotificationRecord>> records = recordsForPkg.entrySet();
+ String key = null;
+ for (Map.Entry<String, NotificationRecord> record : records) {
+ final StatusBarNotification sbn = record.getValue().sbn;
+ if (Objects.equals(sbn.getTag(), tag) && sbn.getId() == id) {
+ key = record.getKey();
+ }
+ }
+ if (key != null) {
+ recordsForPkg.remove(key);
+ cancelAlarm(userId, pkg, key);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ protected boolean cancel(int userId, boolean includeCurrentProfiles) {
+ int[] userIds = {userId};
+ if (includeCurrentProfiles) {
+ userIds = mUserProfiles.getCurrentProfileIds();
+ }
+ final int N = userIds.length;
+ for (int i = 0; i < N; i++) {
+ final ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
+ mSnoozedNotifications.remove(userIds[i]);
+ if (snoozedPkgs != null) {
+ final int M = snoozedPkgs.size();
+ for (int j = 0; j < M; j++) {
+ final ArrayMap<String, NotificationRecord> records = snoozedPkgs.valueAt(j);
+ if (records != null) {
+ int P = records.size();
+ for (int k = 0; k < P; k++) {
+ cancelAlarm(userId, snoozedPkgs.keyAt(j), records.keyAt(k));
+ }
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected boolean cancel(int userId, String pkg) {
+ if (mSnoozedNotifications.containsKey(userId)) {
+ if (mSnoozedNotifications.get(userId).containsKey(pkg)) {
+ ArrayMap<String, NotificationRecord> records =
+ mSnoozedNotifications.get(userId).remove(pkg);
+ int N = records.size();
+ for (int i = 0; i < N; i++) {
+ cancelAlarm(userId, pkg, records.keyAt(i));
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void cancelAlarm(int userId, String pkg, String key) {
+ final PendingIntent pi = createPendingIntent(pkg, key, userId);
+ mAm.cancel(pi);
+ }
+
+ /**
+ * Updates the notification record so the most up to date information is shown on re-post.
+ */
+ protected void update(int userId, NotificationRecord record) {
+ ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
+ mSnoozedNotifications.get(userId);
+ if (records == null) {
+ return;
+ }
+ ArrayMap<String, NotificationRecord> pkgRecords = records.get(record.sbn.getPackageName());
+ if (pkgRecords == null) {
+ return;
+ }
+ pkgRecords.put(record.getKey(), record);
+ }
+
+ @VisibleForTesting
+ void repost(String pkg, String key, int userId) {
+ ArrayMap<String, ArrayMap<String, NotificationRecord>> records =
+ mSnoozedNotifications.get(userId);
+ if (records == null) {
+ return;
+ }
+ ArrayMap<String, NotificationRecord> pkgRecords = records.get(pkg);
+ if (pkgRecords == null) {
+ return;
+ }
+ final NotificationRecord record = pkgRecords.remove(key);
+ if (record != null) {
+ mCallback.repost(userId, record);
+ }
+ }
+
+ private PendingIntent createPendingIntent(String pkg, String key, int userId) {
+ return PendingIntent.getBroadcast(mContext,
+ REQUEST_CODE_REPOST,
+ new Intent(REPOST_ACTION)
+ .setData(new Uri.Builder().scheme(REPOST_SCHEME).appendPath(key).build())
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ .putExtra(EXTRA_PKG, pkg)
+ .putExtra(EXTRA_KEY, key)
+ .putExtra(EXTRA_USER_ID, userId),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ private void scheduleRepost(String pkg, String key, int userId, long time) {
+ final PendingIntent pi = createPendingIntent(pkg, key, userId);
+ mAm.cancel(pi);
+ if (DEBUG) Slog.d(TAG, "Scheduling evaluate for " + new Date(time));
+ mAm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pi);
+ }
+
+ public void dump(PrintWriter pw, NotificationManagerService.DumpFilter filter) {
+ pw.println("\n Snoozed notifications:");
+ for (int userId : mSnoozedNotifications.keySet()) {
+ pw.print(INDENT);
+ pw.println("user: " + userId);
+ ArrayMap<String, ArrayMap<String, NotificationRecord>> snoozedPkgs =
+ mSnoozedNotifications.get(userId);
+ for (String pkg : snoozedPkgs.keySet()) {
+ pw.print(INDENT);
+ pw.print(INDENT);
+ pw.println("package: " + pkg);
+ Set<String> snoozedKeys = snoozedPkgs.get(pkg).keySet();
+ for (String key : snoozedKeys) {
+ pw.print(INDENT);
+ pw.print(INDENT);
+ pw.print(INDENT);
+ pw.println(key);
+ }
+ }
+ }
+ }
+
+ protected void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
+
+ }
+
+ public void readXml(XmlPullParser parser, boolean forRestore)
+ throws XmlPullParserException, IOException {
+
+ }
+
+ @VisibleForTesting
+ void setAlarmManager(AlarmManager am) {
+ mAm = am;
+ }
+
+ protected interface Callback {
+ void repost(int userId, NotificationRecord r);
+ }
+
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Slog.d(TAG, "Reposting notification");
+ }
+ if (REPOST_ACTION.equals(intent.getAction())) {
+ repost(intent.getStringExtra(EXTRA_PKG), intent.getStringExtra(EXTRA_KEY),
+ intent.getIntExtra(EXTRA_USER_ID, 0));
+ }
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
index 759030b..5f08257 100644
--- a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
+++ b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Build;
import android.os.IDeviceIdentifiersPolicyService;
@@ -53,9 +54,15 @@
@Override
public @Nullable String getSerial() throws RemoteException {
- if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.READ_PHONE_STATE, "getSerial");
+ if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
+ && mContext.checkCallingOrSelfPermission(
+ Manifest.permission.READ_PHONE_STATE)
+ != PackageManager.PERMISSION_GRANTED
+ && mContext.checkCallingOrSelfPermission(
+ Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("getSerial requires READ_PHONE_STATE"
+ + " or READ_PRIVILEGED_PHONE_STATE permission");
}
return SystemProperties.get("ro.serialno", Build.UNKNOWN);
}
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index ded85f3..00e45fd 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -150,6 +150,8 @@
private static final int MSG_READ_DEFAULT_PERMISSION_EXCEPTIONS = 1;
+ private static final String ACTION_TRACK = "com.android.fitness.TRACK";
+
private final PackageManagerService mService;
private final Handler mHandler;
@@ -603,8 +605,9 @@
grantRuntimePermissionsLPw(musicPackage, STORAGE_PERMISSIONS, userId);
}
- // Android Wear Home
+ // Watches
if (mService.hasSystemFeature(PackageManager.FEATURE_WATCH, 0)) {
+ // Home application on watches
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
homeIntent.addCategory(Intent.CATEGORY_HOME_MAIN);
@@ -621,6 +624,16 @@
grantRuntimePermissionsLPw(wearHomePackage, LOCATION_PERMISSIONS, false,
userId);
}
+
+ // Fitness tracking on watches
+ Intent trackIntent = new Intent(ACTION_TRACK);
+ PackageParser.Package trackPackage = getDefaultSystemHandlerActivityPackageLPr(
+ trackIntent, userId);
+ if (trackPackage != null
+ && doesPackageSupportRuntimePermissions(trackPackage)) {
+ grantRuntimePermissionsLPw(trackPackage, SENSORS_PERMISSIONS, false, userId);
+ grantRuntimePermissionsLPw(trackPackage, LOCATION_PERMISSIONS, false, userId);
+ }
}
// Print Spooler
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 0b8a347..2ece99f 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -439,7 +439,13 @@
if (!FileUtils.isValidExtFilename(name)) {
throw new IllegalArgumentException("Invalid name: " + name);
}
- final File target = new File(resolveStageDir(), name);
+ final File target;
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ target = new File(resolveStageDir(), name);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
// TODO: this should delegate to DCS so the system process avoids
// holding open FDs into containers.
@@ -1084,7 +1090,12 @@
if (stageDir != null) {
prepareStageDir(stageDir);
} else if (stageCid != null) {
- prepareExternalStageCid(stageCid, params.sizeBytes);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ prepareExternalStageCid(stageCid, params.sizeBytes);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
// TODO: deliver more granular progress for ASEC allocation
mInternalProgress = 0.25f;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 13428b2..e48d6fb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -465,6 +465,12 @@
private static final String PACKAGE_SCHEME = "package";
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
+ /**
+ * If VENDOR_OVERLAY_SKU_PROPERTY is set, search for runtime resource overlay APKs also in
+ * VENDOR_OVERLAY_DIR/<value of VENDOR_OVERLAY_SKU_PROPERTY> in addition to
+ * VENDOR_OVERLAY_DIR.
+ */
+ private static final String VENDOR_OVERLAY_SKU_PROPERTY = "ro.boot.vendor.overlay.sku";
private static int DEFAULT_EPHEMERAL_HASH_PREFIX_MASK = 0xFFFFF000;
private static int DEFAULT_EPHEMERAL_HASH_PREFIX_COUNT = 5;
@@ -2279,12 +2285,17 @@
}
}
- // Collect vendor overlay packages.
- // (Do this before scanning any apps.)
+ // Collect vendor overlay packages. (Do this before scanning any apps.)
// For security and version matching reason, only consider
- // overlay packages if they reside in VENDOR_OVERLAY_DIR.
- File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
- scanDirTracedLI(vendorOverlayDir, mDefParseFlags
+ // overlay packages if they reside in the right directory.
+ String overlaySkuDir = SystemProperties.get(VENDOR_OVERLAY_SKU_PROPERTY);
+ if (!overlaySkuDir.isEmpty()) {
+ scanDirTracedLI(new File(VENDOR_OVERLAY_DIR, overlaySkuDir), mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM
+ | PackageParser.PARSE_IS_SYSTEM_DIR
+ | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
+ }
+ scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
@@ -2527,8 +2538,7 @@
// NOTE: We ignore potential failures here during a system scan (like
// the rest of the commands above) because there's precious little we
// can do about it. A settings error is reported, though.
- adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,
- false /* boot complete */);
+ adjustCpuAbisForSharedUserLPw(setting.packages, null /*scannedPackage*/);
}
// Now that we know all the packages we are keeping,
@@ -4001,6 +4011,11 @@
@Override
public void grantRuntimePermission(String packageName, String name, final int userId) {
+ grantRuntimePermission(packageName, name, userId, false /* Only if not fixed by policy */);
+ }
+
+ private void grantRuntimePermission(String packageName, String name, final int userId,
+ boolean overridePolicy) {
if (!sUserManager.exists(userId)) {
Log.e(TAG, "No such user:" + userId);
return;
@@ -4053,6 +4068,10 @@
throw new SecurityException("Cannot grant system fixed permission "
+ name + " for package " + packageName);
}
+ if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
+ throw new SecurityException("Cannot grant policy fixed permission "
+ + name + " for package " + packageName);
+ }
if (bp.isDevelopment()) {
// Development permissions must be handled specially, since they are not
@@ -4113,6 +4132,11 @@
@Override
public void revokeRuntimePermission(String packageName, String name, int userId) {
+ revokeRuntimePermission(packageName, name, userId, false /* Only if not fixed by policy */);
+ }
+
+ private void revokeRuntimePermission(String packageName, String name, int userId,
+ boolean overridePolicy) {
if (!sUserManager.exists(userId)) {
Log.e(TAG, "No such user:" + userId);
return;
@@ -4163,6 +4187,10 @@
throw new SecurityException("Cannot revoke system fixed permission "
+ name + " for package " + packageName);
}
+ if (!overridePolicy && (flags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
+ throw new SecurityException("Cannot revoke policy fixed permission "
+ + name + " for package " + packageName);
+ }
if (bp.isDevelopment()) {
// Development permissions must be handled specially, since they are not
@@ -4698,11 +4726,16 @@
}
// reader
synchronized (mPackages) {
- final SharedUserSetting suid = mSettings.getSharedUserLPw(sharedUserName, 0, 0, false);
- if (suid == null) {
- return -1;
+ SharedUserSetting suid;
+ try {
+ suid = mSettings.getSharedUserLPw(sharedUserName, 0, 0, false);
+ if (suid != null) {
+ return suid.userId;
+ }
+ } catch (PackageManagerException ignore) {
+ // can't happen, but, still need to catch it
}
- return suid.userId;
+ return -1;
}
}
@@ -6865,11 +6898,11 @@
if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
// This package has been renamed to its original name. Let's
// use that.
- ps = mSettings.peekPackageLPr(oldName);
+ ps = mSettings.getPackageLPr(oldName);
}
// If there was no original package, see one for the real package name.
if (ps == null) {
- ps = mSettings.peekPackageLPr(pkg.packageName);
+ ps = mSettings.getPackageLPr(pkg.packageName);
}
// Check to see if this package could be hiding/updating a system
// package. Must look for it either under the original or real
@@ -7109,7 +7142,7 @@
}
private static String fixProcessName(String defProcessName,
- String processName, int uid) {
+ String processName) {
if (processName == null) {
return defProcessName;
}
@@ -7781,7 +7814,7 @@
}
}
- private void addSharedLibraryLPw(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file,
+ private void addSharedLibraryLPr(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file,
PackageParser.Package changingLib) {
if (file.path != null) {
usesLibraryFiles.add(file.path);
@@ -7802,7 +7835,7 @@
}
}
- private void updateSharedLibrariesLPw(PackageParser.Package pkg,
+ private void updateSharedLibrariesLPr(PackageParser.Package pkg,
PackageParser.Package changingLib) throws PackageManagerException {
if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
final ArraySet<String> usesLibraryFiles = new ArraySet<>();
@@ -7814,7 +7847,7 @@
"Package " + pkg.packageName + " requires unavailable shared library "
+ pkg.usesLibraries.get(i) + "; failing!");
}
- addSharedLibraryLPw(usesLibraryFiles, file, changingLib);
+ addSharedLibraryLPr(usesLibraryFiles, file, changingLib);
}
N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0;
for (int i=0; i<N; i++) {
@@ -7824,7 +7857,7 @@
+ " desires unavailable shared library "
+ pkg.usesOptionalLibraries.get(i) + "; ignoring!");
} else {
- addSharedLibraryLPw(usesLibraryFiles, file, changingLib);
+ addSharedLibraryLPr(usesLibraryFiles, file, changingLib);
}
}
N = usesLibraryFiles.size();
@@ -7853,7 +7886,7 @@
private void updateAllSharedLibrariesLPw() {
for (PackageParser.Package pkg : mPackages.values()) {
try {
- updateSharedLibrariesLPw(pkg, null);
+ updateSharedLibrariesLPr(pkg, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
@@ -7871,7 +7904,7 @@
}
res.add(pkg);
try {
- updateSharedLibrariesLPw(pkg, changingPkg);
+ updateSharedLibrariesLPr(pkg, changingPkg);
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
@@ -7982,7 +8015,7 @@
*
* @throws PackageManagerException If bytecode could not be found when it should exist
*/
- private static void enforceCodePolicy(PackageParser.Package pkg)
+ private static void assertCodePolicy(PackageParser.Package pkg)
throws PackageManagerException {
final boolean shouldHaveCode =
(pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
@@ -8005,164 +8038,24 @@
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
- throws PackageManagerException {
- final File scanFile = new File(pkg.codePath);
- if (pkg.applicationInfo.getCodePath() == null ||
- pkg.applicationInfo.getResourcePath() == null) {
- // Bail out. The resource and code paths haven't been set.
- throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
- "Code and resource paths haven't been set correctly");
- }
-
- // Apply policy
- if ((policyFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
- if (pkg.applicationInfo.isDirectBootAware()) {
- // we're direct boot aware; set for all components
- for (PackageParser.Service s : pkg.services) {
- s.info.encryptionAware = s.info.directBootAware = true;
- }
- for (PackageParser.Provider p : pkg.providers) {
- p.info.encryptionAware = p.info.directBootAware = true;
- }
- for (PackageParser.Activity a : pkg.activities) {
- a.info.encryptionAware = a.info.directBootAware = true;
- }
- for (PackageParser.Activity r : pkg.receivers) {
- r.info.encryptionAware = r.info.directBootAware = true;
- }
- }
- } else {
- // Only allow system apps to be flagged as core apps.
- pkg.coreApp = false;
- // clear flags not applicable to regular apps
- pkg.applicationInfo.privateFlags &=
- ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
- pkg.applicationInfo.privateFlags &=
- ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
- }
- pkg.mTrustedOverlay = (policyFlags&PackageParser.PARSE_TRUSTED_OVERLAY) != 0;
-
- if ((policyFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
- pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
- }
-
- if ((policyFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) {
- enforceCodePolicy(pkg);
- }
-
- if (mCustomResolverComponentName != null &&
- mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
- setUpCustomResolverActivity(pkg);
- }
-
- if (pkg.packageName.equals("android")) {
- synchronized (mPackages) {
- if (mAndroidApplication != null) {
- Slog.w(TAG, "*************************************************");
- Slog.w(TAG, "Core android package being redefined. Skipping.");
- Slog.w(TAG, " file=" + scanFile);
- Slog.w(TAG, "*************************************************");
- throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
- "Core android package being redefined. Skipping.");
- }
-
- if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
- // Set up information for our fall-back user intent resolution activity.
- mPlatformPackage = pkg;
- pkg.mVersionCode = mSdkVersion;
- mAndroidApplication = pkg.applicationInfo;
-
- if (!mResolverReplaced) {
- mResolveActivity.applicationInfo = mAndroidApplication;
- mResolveActivity.name = ResolverActivity.class.getName();
- mResolveActivity.packageName = mAndroidApplication.packageName;
- mResolveActivity.processName = "system:ui";
- mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
- mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
- mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
- mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
- mResolveActivity.exported = true;
- mResolveActivity.enabled = true;
- mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
- mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
- | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
- | ActivityInfo.CONFIG_SCREEN_LAYOUT
- | ActivityInfo.CONFIG_ORIENTATION
- | ActivityInfo.CONFIG_KEYBOARD
- | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
- mResolveInfo.activityInfo = mResolveActivity;
- mResolveInfo.priority = 0;
- mResolveInfo.preferredOrder = 0;
- mResolveInfo.match = 0;
- mResolveComponentName = new ComponentName(
- mAndroidApplication.packageName, mResolveActivity.name);
- }
- }
- }
- }
-
+ throws PackageManagerException {
if (DEBUG_PACKAGE_SCANNING) {
if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
Log.d(TAG, "Scanning package " + pkg.packageName);
}
- synchronized (mPackages) {
- if (mPackages.containsKey(pkg.packageName)
- || mSharedLibraries.containsKey(pkg.packageName)) {
- throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
- "Application package " + pkg.packageName
- + " already installed. Skipping duplicate.");
- }
+ applyPolicy(pkg, policyFlags);
- // If we're only installing presumed-existing packages, require that the
- // scanned APK is both already known and at the path previously established
- // for it. Previously unknown packages we pick up normally, but if we have an
- // a priori expectation about this package's install presence, enforce it.
- // With a singular exception for new system packages. When an OTA contains
- // a new system package, we allow the codepath to change from a system location
- // to the user-installed location. If we don't allow this change, any newer,
- // user-installed version of the application will be ignored.
- if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
- if (mExpectingBetter.containsKey(pkg.packageName)) {
- logCriticalInfo(Log.WARN,
- "Relax SCAN_REQUIRE_KNOWN requirement for package " + pkg.packageName);
- } else {
- PackageSetting known = mSettings.peekPackageLPr(pkg.packageName);
- if (known != null) {
- if (DEBUG_PACKAGE_SCANNING) {
- Log.d(TAG, "Examining " + pkg.codePath
- + " and requiring known paths " + known.codePathString
- + " & " + known.resourcePathString);
- }
- if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
- || !pkg.applicationInfo.getResourcePath().equals(
- known.resourcePathString)) {
- throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
- "Application package " + pkg.packageName
- + " found at " + pkg.applicationInfo.getCodePath()
- + " but expected at " + known.codePathString
- + "; ignoring.");
- }
- }
- }
- }
- }
+ assertPackageIsValid(pkg, policyFlags);
// Initialize package source and resource directories
- File destCodeFile = new File(pkg.applicationInfo.getCodePath());
- File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
+ final File scanFile = new File(pkg.codePath);
+ final File destCodeFile = new File(pkg.applicationInfo.getCodePath());
+ final File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
SharedUserSetting suid = null;
PackageSetting pkgSetting = null;
- if (!isSystemApp(pkg)) {
- // Only system apps can use these features.
- pkg.mOriginalPackages = null;
- pkg.mRealPackage = null;
- pkg.mAdoptPermissions = null;
- }
-
// Getting the package setting may have a side-effect, so if we
// are only checking if scan would succeed, stash a copy of the
// old setting to restore at the end.
@@ -8171,12 +8064,9 @@
// writer
synchronized (mPackages) {
if (pkg.mSharedUserId != null) {
- suid = mSettings.getSharedUserLPw(pkg.mSharedUserId, 0, 0, true);
- if (suid == null) {
- throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
- "Creating application package " + pkg.packageName
- + " for shared user failed");
- }
+ // SIDE EFFECTS; may potentially allocate a new shared user
+ suid = mSettings.getSharedUserLPw(
+ pkg.mSharedUserId, 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/);
if (DEBUG_PACKAGE_SCANNING) {
if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
Log.d(TAG, "Shared UserID " + pkg.mSharedUserId + " (uid=" + suid.userId
@@ -8203,10 +8093,9 @@
// it is not already done.
pkg.setPackageName(renamed);
}
-
} else {
for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) {
- if ((origPackage = mSettings.peekPackageLPr(
+ if ((origPackage = mSettings.getPackageLPr(
pkg.mOriginalPackages.get(i))) != null) {
// We do have the package already installed under its
// original name... should we use it?
@@ -8242,7 +8131,7 @@
// See comments in nonMutatedPs declaration
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
- PackageSetting foundPs = mSettings.peekPackageLPr(pkg.packageName);
+ PackageSetting foundPs = mSettings.getPackageLPr(pkg.packageName);
if (foundPs != null) {
nonMutatedPs = new PackageSetting(foundPs);
}
@@ -8252,10 +8141,11 @@
if (pkgSetting != null && pkgSetting.sharedUser != suid) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Package " + pkg.packageName + " shared user changed from "
- + (pkgSetting.sharedUser != null ? pkgSetting.sharedUser.name : "<nothing>")
- + " to "
- + (suid != null ? suid.name : "<nothing>")
- + "; replacing with new");
+ + (pkgSetting.sharedUser != null
+ ? pkgSetting.sharedUser.name : "<nothing>")
+ + " to "
+ + (suid != null ? suid.name : "<nothing>")
+ + "; replacing with new");
pkgSetting = null;
}
final PackageSetting oldPkgSetting =
@@ -8265,6 +8155,7 @@
if (pkgSetting == null) {
final String parentPackageName = (pkg.parentPackage != null)
? pkg.parentPackage.packageName : null;
+ // REMOVE SharedUserSetting from method; update in a separate call
pkgSetting = Settings.createNewSetting(pkg.packageName, origPackage,
disabledPkgSetting, realName, suid, destCodeFile, destResourceFile,
pkg.applicationInfo.nativeLibraryRootDir, pkg.applicationInfo.primaryCpuAbi,
@@ -8272,19 +8163,23 @@
pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, user,
true /*allowInstall*/, parentPackageName, pkg.getChildPackageNames(),
UserManagerService.getInstance());
+ // SIDE EFFECTS; updates system state; move elsewhere
if (origPackage != null) {
mSettings.addRenamedPackageLPw(pkg.packageName, origPackage.name);
}
mSettings.addUserToSettingLPw(pkgSetting);
} else {
+ // REMOVE SharedUserSetting from method; update in a separate call
Settings.updatePackageSetting(pkgSetting, disabledPkgSetting, suid, destCodeFile,
pkg.applicationInfo.nativeLibraryDir, pkg.applicationInfo.primaryCpuAbi,
pkg.applicationInfo.secondaryCpuAbi, pkg.applicationInfo.flags,
pkg.applicationInfo.privateFlags, pkg.getChildPackageNames(),
UserManagerService.getInstance());
}
- mSettings.writeUserRestrictions(pkgSetting, oldPkgSetting);
+ // SIDE EFFECTS; persists system state to files on disk; move elsewhere
+ mSettings.writeUserRestrictionsLPw(pkgSetting, oldPkgSetting);
+ // SIDE EFFECTS; modifies system state; move elsewhere
if (pkgSetting.origPackage != null) {
// If we are first transitioning from an original package,
// fix up the new package's name now. We need to do this after
@@ -8306,6 +8201,7 @@
pkgSetting.origPackage = null;
}
+ // SIDE EFFECTS; modifies system state; move elsewhere
if ((scanFlags & SCAN_CHECK_ONLY) == 0 && realName != null) {
// Make a note of it.
mTransferedPackages.add(pkg.packageName);
@@ -8315,13 +8211,13 @@
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
}
- if ((policyFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
+ if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
// Check all shared libraries and map to their actual file path.
// We only do this here for apps not on a system dir, because those
// are the only ones that can fail an install due to this. We
// will take care of the system apps by updating all of their
// library paths after the scan is done.
- updateSharedLibrariesLPw(pkg, null);
+ updateSharedLibrariesLPr(pkg, null);
}
if (mFoundPolicyFile) {
@@ -8343,12 +8239,13 @@
} else {
pkgSetting.signatures.mSignatures = pkg.mSignatures;
String msg = "System package " + pkg.packageName
- + " signature changed; retaining data.";
+ + " signature changed; retaining data.";
reportSettingsProblem(Log.WARN, msg);
}
}
} else {
try {
+ // SIDE EFFECTS; compareSignaturesCompat() changes KeysetManagerService
verifySignaturesLP(pkgSetting, pkg);
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
@@ -8367,57 +8264,31 @@
// that unreasonable.
if (pkgSetting.sharedUser != null) {
if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
- pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
+ pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
throw new PackageManagerException(
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
- "Signature mismatch for shared user: "
+ "Signature mismatch for shared user: "
+ pkgSetting.sharedUser);
}
}
// File a report about this.
String msg = "System package " + pkg.packageName
- + " signature changed; retaining data.";
+ + " signature changed; retaining data.";
reportSettingsProblem(Log.WARN, msg);
}
}
- // Verify that this new package doesn't have any content providers
- // that conflict with existing packages. Only do this if the
- // package isn't already installed, since we don't want to break
- // things that are installed.
- if ((scanFlags & SCAN_NEW_INSTALL) != 0) {
- final int N = pkg.providers.size();
- int i;
- for (i=0; i<N; i++) {
- PackageParser.Provider p = pkg.providers.get(i);
- if (p.info.authority != null) {
- String names[] = p.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- if (mProvidersByAuthority.containsKey(names[j])) {
- PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
- final String otherPackageName =
- ((other != null && other.getComponentName() != null) ?
- other.getComponentName().getPackageName() : "?");
- throw new PackageManagerException(
- INSTALL_FAILED_CONFLICTING_PROVIDER,
- "Can't install because provider name " + names[j]
- + " (in package " + pkg.applicationInfo.packageName
- + ") is already used by " + otherPackageName);
- }
- }
- }
- }
- }
if ((scanFlags & SCAN_CHECK_ONLY) == 0 && pkg.mAdoptPermissions != null) {
// This package wants to adopt ownership of permissions from
// another package.
for (int i = pkg.mAdoptPermissions.size() - 1; i >= 0; i--) {
final String origName = pkg.mAdoptPermissions.get(i);
- final PackageSetting orig = mSettings.peekPackageLPr(origName);
+ final PackageSetting orig = mSettings.getPackageLPr(origName);
if (orig != null) {
if (verifyPackageUpdateLPr(orig, pkg)) {
Slog.i(TAG, "Adopting permissions from " + origName + " to "
+ pkg.packageName);
+ // SIDE EFFECTS; updates permissions system state; move elsewhere
mSettings.transferPermissionsLPw(origName, pkg.packageName);
}
}
@@ -8425,26 +8296,21 @@
}
}
- final String pkgName = pkg.packageName;
-
- final long scanFileTime = getLastModifiedTime(pkg, scanFile);
- final boolean forceDex = (scanFlags & SCAN_FORCE_DEX) != 0;
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
- pkg.applicationInfo.processName,
- pkg.applicationInfo.uid);
+ pkg.applicationInfo.processName);
if (pkg != mPlatformPackage) {
// Get all of our default paths setup
pkg.applicationInfo.initForUser(UserHandle.USER_SYSTEM);
}
- final String path = scanFile.getPath();
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
- derivePackageAbi(pkg, scanFile, cpuAbiOverride, true /*extractLibs*/);
+ derivePackageAbi(
+ pkg, scanFile, cpuAbiOverride, true /*extractLibs*/, mAppLib32InstallDir);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Some system apps still use directory structure for native libraries
@@ -8453,9 +8319,8 @@
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
pkg.applicationInfo.primaryCpuAbi == null) {
setBundledAppAbisAndRoots(pkg, pkgSetting);
- setNativeLibraryPaths(pkg);
+ setNativeLibraryPaths(pkg, mAppLib32InstallDir);
}
-
} else {
if ((scanFlags & SCAN_MOVE) != 0) {
// We haven't run dex-opt for this move (since we've moved the compiled output too)
@@ -8469,7 +8334,7 @@
// ABIs we've determined above. For non-moves, the path will be updated based on the
// ABIs we determined during compilation, but the path will depend on the final
// package path (after the rename away from the stage path).
- setNativeLibraryPaths(pkg);
+ setNativeLibraryPaths(pkg, mAppLib32InstallDir);
}
// This is a special case for the "system" package, where the ABI is
@@ -8516,6 +8381,7 @@
" secondary=" + pkg.applicationInfo.secondaryCpuAbi);
}
+ // SIDE EFFECTS; removes DEX files from disk; move elsewhere
if ((scanFlags & SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) {
// We don't do this here during boot because we can do it all
// at once after scanning all existing packages.
@@ -8523,8 +8389,7 @@
// We also do this *before* we perform dexopt on this package, so that
// we can avoid redundant dexopts, and also to make sure we've got the
// code and package path correct.
- adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages,
- pkg, true /* boot complete */);
+ adjustCpuAbisForSharedUserLPw(pkgSetting.sharedUser.packages, pkg);
}
if (mFactoryTest && pkg.requestedPermissions.contains(
@@ -8536,7 +8401,25 @@
pkgSetting.isOrphaned = true;
}
- ArrayList<PackageParser.Package> clientLibPkgs = null;
+ // Take care of first install / last update times.
+ final long scanFileTime = getLastModifiedTime(pkg, scanFile);
+ if (currentTime != 0) {
+ if (pkgSetting.firstInstallTime == 0) {
+ pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
+ } else if ((scanFlags & SCAN_UPDATE_TIME) != 0) {
+ pkgSetting.lastUpdateTime = currentTime;
+ }
+ } else if (pkgSetting.firstInstallTime == 0) {
+ // We need *something*. Take time time stamp of the file.
+ pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
+ } else if ((policyFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
+ if (scanFileTime != pkgSetting.timeStamp) {
+ // A package on the system image has changed; consider this
+ // to be an update.
+ pkgSetting.lastUpdateTime = scanFileTime;
+ }
+ }
+ pkgSetting.setTimeStamp(scanFileTime);
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
if (nonMutatedPs != null) {
@@ -8544,27 +8427,239 @@
mSettings.mPackages.put(nonMutatedPs.name, nonMutatedPs);
}
}
- return pkg;
+ } else {
+ // Modify state for the given package setting
+ commitPackageSettings(pkg, pkgSetting, user, scanFlags,
+ (policyFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/);
+ }
+ return pkg;
+ }
+
+ /**
+ * Applies policy to the parsed package based upon the given policy flags.
+ * Ensures the package is in a good state.
+ * <p>
+ * Implementation detail: This method must NOT have any side effect. It would
+ * ideally be static, but, it requires locks to read system state.
+ */
+ private void applyPolicy(PackageParser.Package pkg, int policyFlags) {
+ if ((policyFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
+ pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ if (pkg.applicationInfo.isDirectBootAware()) {
+ // we're direct boot aware; set for all components
+ for (PackageParser.Service s : pkg.services) {
+ s.info.encryptionAware = s.info.directBootAware = true;
+ }
+ for (PackageParser.Provider p : pkg.providers) {
+ p.info.encryptionAware = p.info.directBootAware = true;
+ }
+ for (PackageParser.Activity a : pkg.activities) {
+ a.info.encryptionAware = a.info.directBootAware = true;
+ }
+ for (PackageParser.Activity r : pkg.receivers) {
+ r.info.encryptionAware = r.info.directBootAware = true;
+ }
+ }
+ } else {
+ // Only allow system apps to be flagged as core apps.
+ pkg.coreApp = false;
+ // clear flags not applicable to regular apps
+ pkg.applicationInfo.privateFlags &=
+ ~ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
+ pkg.applicationInfo.privateFlags &=
+ ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+ }
+ pkg.mTrustedOverlay = (policyFlags&PackageParser.PARSE_TRUSTED_OVERLAY) != 0;
+
+ if ((policyFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
- // Only privileged apps and updated privileged apps can add child packages.
- if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) {
- if ((policyFlags & PARSE_IS_PRIVILEGED) == 0) {
- throw new PackageManagerException("Only privileged apps and updated "
- + "privileged apps can add child packages. Ignoring package "
- + pkg.packageName);
+ if (!isSystemApp(pkg)) {
+ // Only system apps can use these features.
+ pkg.mOriginalPackages = null;
+ pkg.mRealPackage = null;
+ pkg.mAdoptPermissions = null;
+ }
+ }
+
+ /**
+ * Asserts the parsed package is valid according to teh given policy. If the
+ * package is invalid, for whatever reason, throws {@link PackgeManagerException}.
+ * <p>
+ * Implementation detail: This method must NOT have any side effects. It would
+ * ideally be static, but, it requires locks to read system state.
+ *
+ * @throws PackageManagerException If the package fails any of the validation checks
+ */
+ private void assertPackageIsValid(PackageParser.Package pkg, int policyFlags)
+ throws PackageManagerException {
+ if ((policyFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) {
+ assertCodePolicy(pkg);
+ }
+
+ if (pkg.applicationInfo.getCodePath() == null ||
+ pkg.applicationInfo.getResourcePath() == null) {
+ // Bail out. The resource and code paths haven't been set.
+ throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
+ "Code and resource paths haven't been set correctly");
+ }
+
+ // Make sure we're not adding any bogus keyset info
+ KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ ksms.assertScannedPackageValid(pkg);
+
+ synchronized (mPackages) {
+ // The special "android" package can only be defined once
+ if (pkg.packageName.equals("android")) {
+ if (mAndroidApplication != null) {
+ Slog.w(TAG, "*************************************************");
+ Slog.w(TAG, "Core android package being redefined. Skipping.");
+ Slog.w(TAG, " codePath=" + pkg.codePath);
+ Slog.w(TAG, "*************************************************");
+ throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
+ "Core android package being redefined. Skipping.");
+ }
}
- final int childCount = pkg.childPackages.size();
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- if (mSettings.hasOtherDisabledSystemPkgWithChildLPr(pkg.packageName,
- childPkg.packageName)) {
- throw new PackageManagerException("Cannot override a child package of "
- + "another disabled system app. Ignoring package " + pkg.packageName);
+
+ // A package name must be unique; don't allow duplicates
+ if (mPackages.containsKey(pkg.packageName)
+ || mSharedLibraries.containsKey(pkg.packageName)) {
+ throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
+ "Application package " + pkg.packageName
+ + " already installed. Skipping duplicate.");
+ }
+
+ // Only privileged apps and updated privileged apps can add child packages.
+ if (pkg.childPackages != null && !pkg.childPackages.isEmpty()) {
+ if ((policyFlags & PARSE_IS_PRIVILEGED) == 0) {
+ throw new PackageManagerException("Only privileged apps can add child "
+ + "packages. Ignoring package " + pkg.packageName);
+ }
+ final int childCount = pkg.childPackages.size();
+ for (int i = 0; i < childCount; i++) {
+ PackageParser.Package childPkg = pkg.childPackages.get(i);
+ if (mSettings.hasOtherDisabledSystemPkgWithChildLPr(pkg.packageName,
+ childPkg.packageName)) {
+ throw new PackageManagerException("Can't override child of "
+ + "another disabled app. Ignoring package " + pkg.packageName);
+ }
+ }
+ }
+
+ // If we're only installing presumed-existing packages, require that the
+ // scanned APK is both already known and at the path previously established
+ // for it. Previously unknown packages we pick up normally, but if we have an
+ // a priori expectation about this package's install presence, enforce it.
+ // With a singular exception for new system packages. When an OTA contains
+ // a new system package, we allow the codepath to change from a system location
+ // to the user-installed location. If we don't allow this change, any newer,
+ // user-installed version of the application will be ignored.
+ if ((policyFlags & SCAN_REQUIRE_KNOWN) != 0) {
+ if (mExpectingBetter.containsKey(pkg.packageName)) {
+ logCriticalInfo(Log.WARN,
+ "Relax SCAN_REQUIRE_KNOWN requirement for package " + pkg.packageName);
+ } else {
+ PackageSetting known = mSettings.getPackageLPr(pkg.packageName);
+ if (known != null) {
+ if (DEBUG_PACKAGE_SCANNING) {
+ Log.d(TAG, "Examining " + pkg.codePath
+ + " and requiring known paths " + known.codePathString
+ + " & " + known.resourcePathString);
+ }
+ if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
+ || !pkg.applicationInfo.getResourcePath().equals(
+ known.resourcePathString)) {
+ throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
+ "Application package " + pkg.packageName
+ + " found at " + pkg.applicationInfo.getCodePath()
+ + " but expected at " + known.codePathString
+ + "; ignoring.");
+ }
+ }
+ }
+ }
+
+ // Verify that this new package doesn't have any content providers
+ // that conflict with existing packages. Only do this if the
+ // package isn't already installed, since we don't want to break
+ // things that are installed.
+ if ((policyFlags & SCAN_NEW_INSTALL) != 0) {
+ final int N = pkg.providers.size();
+ int i;
+ for (i=0; i<N; i++) {
+ PackageParser.Provider p = pkg.providers.get(i);
+ if (p.info.authority != null) {
+ String names[] = p.info.authority.split(";");
+ for (int j = 0; j < names.length; j++) {
+ if (mProvidersByAuthority.containsKey(names[j])) {
+ PackageParser.Provider other = mProvidersByAuthority.get(names[j]);
+ final String otherPackageName =
+ ((other != null && other.getComponentName() != null) ?
+ other.getComponentName().getPackageName() : "?");
+ throw new PackageManagerException(
+ INSTALL_FAILED_CONFLICTING_PROVIDER,
+ "Can't install because provider name " + names[j]
+ + " (in package " + pkg.applicationInfo.packageName
+ + ") is already used by " + otherPackageName);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds a scanned package to the system. When this method is finished, the package will
+ * be available for query, resolution, etc...
+ */
+ private void commitPackageSettings(PackageParser.Package pkg, PackageSetting pkgSetting,
+ UserHandle user, int scanFlags, boolean chatty) throws PackageManagerException {
+ final String pkgName = pkg.packageName;
+ if (mCustomResolverComponentName != null &&
+ mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
+ setUpCustomResolverActivity(pkg);
+ }
+
+ if (pkg.packageName.equals("android")) {
+ synchronized (mPackages) {
+ if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
+ // Set up information for our fall-back user intent resolution activity.
+ mPlatformPackage = pkg;
+ pkg.mVersionCode = mSdkVersion;
+ mAndroidApplication = pkg.applicationInfo;
+
+ if (!mResolverReplaced) {
+ mResolveActivity.applicationInfo = mAndroidApplication;
+ mResolveActivity.name = ResolverActivity.class.getName();
+ mResolveActivity.packageName = mAndroidApplication.packageName;
+ mResolveActivity.processName = "system:ui";
+ mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
+ mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
+ mResolveActivity.theme = R.style.Theme_Material_Dialog_Alert;
+ mResolveActivity.exported = true;
+ mResolveActivity.enabled = true;
+ mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
+ mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
+ | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
+ | ActivityInfo.CONFIG_SCREEN_LAYOUT
+ | ActivityInfo.CONFIG_ORIENTATION
+ | ActivityInfo.CONFIG_KEYBOARD
+ | ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
+ mResolveInfo.activityInfo = mResolveActivity;
+ mResolveInfo.priority = 0;
+ mResolveInfo.preferredOrder = 0;
+ mResolveInfo.match = 0;
+ mResolveComponentName = new ComponentName(
+ mAndroidApplication.packageName, mResolveActivity.name);
+ }
}
}
}
+ ArrayList<PackageParser.Package> clientLibPkgs = null;
// writer
synchronized (mPackages) {
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
@@ -8641,10 +8736,6 @@
}
}
- // Make sure we're not adding any bogus keyset info
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- ksms.assertScannedPackageValid(pkg);
-
// writer
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
@@ -8656,8 +8747,9 @@
// Note that |user| might be null during the initial boot scan. If a codePath
// for an app has changed during a boot scan, it's due to an app update that's
// part of the system partition and marker changes must be applied to all users.
- maybeRenameForeignDexMarkers(pkgSetting.pkg, pkg,
- (user != null) ? user : UserHandle.ALL);
+ final int userId = ((user != null) ? user : UserHandle.ALL).getIdentifier();
+ final int[] userIds = resolveUserIds(userId);
+ maybeRenameForeignDexMarkers(pkgSetting.pkg, pkg, userIds);
}
// Add the new setting to mSettings
@@ -8673,25 +8765,8 @@
}
}
- // Take care of first install / last update times.
- if (currentTime != 0) {
- if (pkgSetting.firstInstallTime == 0) {
- pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = currentTime;
- } else if ((scanFlags&SCAN_UPDATE_TIME) != 0) {
- pkgSetting.lastUpdateTime = currentTime;
- }
- } else if (pkgSetting.firstInstallTime == 0) {
- // We need *something*. Take time time stamp of the file.
- pkgSetting.firstInstallTime = pkgSetting.lastUpdateTime = scanFileTime;
- } else if ((policyFlags&PackageParser.PARSE_IS_SYSTEM_DIR) != 0) {
- if (scanFileTime != pkgSetting.timeStamp) {
- // A package on the system image has changed; consider this
- // to be an update.
- pkgSetting.lastUpdateTime = scanFileTime;
- }
- }
-
// Add the package's KeySets to the global KeySetManagerService
+ KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.addScannedPackageLPw(pkg);
int N = pkg.providers.size();
@@ -8700,7 +8775,7 @@
for (i=0; i<N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
- p.info.processName, pkg.applicationInfo.uid);
+ p.info.processName);
mProviders.addProvider(p);
p.syncable = p.info.isSyncable;
if (p.info.authority != null) {
@@ -8726,7 +8801,7 @@
p.info.authority = p.info.authority + ";" + names[j];
}
if (DEBUG_PACKAGE_SCANNING) {
- if ((policyFlags & PackageParser.PARSE_CHATTY) != 0)
+ if (chatty)
Log.d(TAG, "Registered content provider: " + names[j]
+ ", className = " + p.info.name + ", isSyncable = "
+ p.info.isSyncable);
@@ -8741,7 +8816,7 @@
}
}
}
- if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8759,9 +8834,9 @@
for (i=0; i<N; i++) {
PackageParser.Service s = pkg.services.get(i);
s.info.processName = fixProcessName(pkg.applicationInfo.processName,
- s.info.processName, pkg.applicationInfo.uid);
+ s.info.processName);
mServices.addService(s);
- if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8779,9 +8854,9 @@
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.receivers.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
- a.info.processName, pkg.applicationInfo.uid);
+ a.info.processName);
mReceivers.addActivity(a, "receiver");
- if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8799,9 +8874,9 @@
for (i=0; i<N; i++) {
PackageParser.Activity a = pkg.activities.get(i);
a.info.processName = fixProcessName(pkg.applicationInfo.processName,
- a.info.processName, pkg.applicationInfo.uid);
+ a.info.processName);
mActivities.addActivity(a, "activity");
- if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8823,7 +8898,7 @@
final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName);
if (cur == null || isPackageUpdate) {
mPermissionGroups.put(pg.info.name, pg);
- if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8838,7 +8913,7 @@
Slog.w(TAG, "Permission group " + pg.info.name + " from package "
+ pg.info.packageName + " ignored: original from "
+ cur.info.packageName);
- if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8917,7 +8992,7 @@
bp.uid = pkg.applicationInfo.uid;
bp.sourcePackage = p.info.packageName;
p.info.flags |= PermissionInfo.FLAG_INSTALLED;
- if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8936,7 +9011,7 @@
+ p.info.packageName + " ignored: original from "
+ bp.sourcePackage);
}
- } else if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
+ } else if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8966,11 +9041,10 @@
a.info.dataDir = pkg.applicationInfo.dataDir;
a.info.deviceProtectedDataDir = pkg.applicationInfo.deviceProtectedDataDir;
a.info.credentialProtectedDataDir = pkg.applicationInfo.credentialProtectedDataDir;
-
a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
a.info.secondaryNativeLibraryDir = pkg.applicationInfo.secondaryNativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
- if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {
+ if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
@@ -8990,8 +9064,6 @@
}
}
- pkgSetting.setTimeStamp(scanFileTime);
-
// Create idmap files for pairs of (packages, overlay packages).
// Note: "android", ie framework-res.apk, is handled by native layers.
if (pkg.mOverlayTarget != null) {
@@ -9021,11 +9093,10 @@
throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"scanPackageLI failed to createIdmap");
}
- return pkg;
}
- private void maybeRenameForeignDexMarkers(PackageParser.Package existing,
- PackageParser.Package update, UserHandle user) {
+ private static void maybeRenameForeignDexMarkers(PackageParser.Package existing,
+ PackageParser.Package update, int[] userIds) {
if (existing.applicationInfo == null || update.applicationInfo == null) {
// This isn't due to an app installation.
return;
@@ -9073,7 +9144,7 @@
markerSuffixes.add(updatedPathName.replace('/', '@'));
}
- for (int userId : resolveUserIds(user.getIdentifier())) {
+ for (int userId : userIds) {
File profileDir = Environment.getDataProfilesDeForeignDexDirectory(userId);
for (String markerSuffix : markerSuffixes) {
@@ -9099,8 +9170,9 @@
*
* If {@code extractLibs} is true, native libraries are extracted from the app if required.
*/
- private void derivePackageAbi(PackageParser.Package pkg, File scanFile,
- String cpuAbiOverride, boolean extractLibs)
+ private static void derivePackageAbi(PackageParser.Package pkg, File scanFile,
+ String cpuAbiOverride, boolean extractLibs,
+ File appLib32InstallDir)
throws PackageManagerException {
// TODO: We can probably be smarter about this stuff. For installed apps,
// we can calculate this information at install time once and for all. For
@@ -9109,7 +9181,7 @@
// Give ourselves some initial paths; we'll come back for another
// pass once we've determined ABI below.
- setNativeLibraryPaths(pkg);
+ setNativeLibraryPaths(pkg, appLib32InstallDir);
// We would never need to extract libs for forward-locked and external packages,
// since the container service will do it for us. We shouldn't attempt to
@@ -9244,7 +9316,7 @@
// Now that we've calculated the ABIs and determined if it's an internal app,
// we will go ahead and populate the nativeLibraryPath.
- setNativeLibraryPaths(pkg);
+ setNativeLibraryPaths(pkg, appLib32InstallDir);
}
/**
@@ -9261,7 +9333,7 @@
* adds unnecessary complexity.
*/
private void adjustCpuAbisForSharedUserLPw(Set<PackageSetting> packagesForUser,
- PackageParser.Package scannedPackage, boolean bootComplete) {
+ PackageParser.Package scannedPackage) {
String requiredInstructionSet = null;
if (scannedPackage != null && scannedPackage.applicationInfo.primaryCpuAbi != null) {
requiredInstructionSet = VMRuntime.getInstructionSet(
@@ -9426,7 +9498,7 @@
* Derive and set the location of native libraries for the given package,
* which varies depending on where and how the package was installed.
*/
- private void setNativeLibraryPaths(PackageParser.Package pkg) {
+ private static void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir) {
final ApplicationInfo info = pkg.applicationInfo;
final String codePath = pkg.codePath;
final File codeFile = new File(codePath);
@@ -9465,7 +9537,7 @@
.getAbsolutePath();
} else {
final String apkName = deriveCodePathName(codePath);
- info.nativeLibraryRootDir = new File(mAppLib32InstallDir, apkName)
+ info.nativeLibraryRootDir = new File(appLib32InstallDir, apkName)
.getAbsolutePath();
}
@@ -9493,7 +9565,7 @@
* of this information, and instead assume that the system was built
* sensibly.
*/
- private void setBundledAppAbisAndRoots(PackageParser.Package pkg,
+ private static void setBundledAppAbisAndRoots(PackageParser.Package pkg,
PackageSetting pkgSetting) {
final String apkName = deriveCodePathName(pkg.applicationInfo.getCodePath());
@@ -14429,7 +14501,7 @@
childRemovedRes.isUpdate = false;
childRemovedRes.dataRemoved = true;
synchronized (mPackages) {
- PackageSetting childPs = mSettings.peekPackageLPr(childPkg.packageName);
+ PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
if (childPs != null) {
childRemovedRes.origUsers = childPs.queryInstalledUsers(allUsers, true);
}
@@ -14584,7 +14656,7 @@
}
} else {
synchronized (mPackages) {
- PackageSetting ps = mSettings.peekPackageLPr(pkg.packageName);
+ PackageSetting ps = mSettings.getPackageLPr(pkg.packageName);
if (ps != null) {
res.removedInfo.removedForAllUsers = mPackages.get(ps.name) == null;
if (res.removedInfo.removedChildPackages != null) {
@@ -14762,7 +14834,7 @@
for (int i = 0; i < childCount; i++) {
PackageSetting childPs = null;
synchronized (mPackages) {
- childPs = mSettings.peekPackageLPr(ps.childPackageNames.get(i));
+ childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i));
}
if (childPs != null) {
NativeLibraryHelper.removeNativeBinariesLI(childPs
@@ -15035,7 +15107,7 @@
childRes.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
childRes.pkg = childPkg;
childRes.name = childPkg.packageName;
- PackageSetting childPs = mSettings.peekPackageLPr(childPkg.packageName);
+ PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
if (childPs != null) {
childRes.origUsers = childPs.queryInstalledUsers(
sUserManager.getUserIds(), true);
@@ -15257,7 +15329,7 @@
String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
args.abiOverride : pkg.cpuAbiOverride);
derivePackageAbi(pkg, new File(pkg.codePath), abiOverride,
- true /* extract libs */);
+ true /*extractLibs*/, mAppLib32InstallDir);
} catch (PackageManagerException pme) {
Slog.e(TAG, "Error deriving application ABI", pme);
res.setError(INSTALL_FAILED_INTERNAL_ERROR, "Error deriving application ABI");
@@ -15267,7 +15339,7 @@
// Shared libraries for the package need to be updated.
synchronized (mPackages) {
try {
- updateSharedLibrariesLPw(pkg, null);
+ updateSharedLibrariesLPr(pkg, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "updateSharedLibrariesLPw failed: " + e.getMessage());
}
@@ -15316,7 +15388,7 @@
for (int i = 0; i < childCount; i++) {
PackageParser.Package childPkg = pkg.childPackages.get(i);
PackageInstalledInfo childRes = res.addedChildPackages.get(childPkg.packageName);
- PackageSetting childPs = mSettings.peekPackageLPr(childPkg.packageName);
+ PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
if (childPs != null) {
childRes.newUsers = childPs.queryInstalledUsers(
sUserManager.getUserIds(), true);
@@ -16115,7 +16187,7 @@
}
try {
// update shared libraries for the newly re-installed system package
- updateSharedLibrariesLPw(newPkg, null);
+ updateSharedLibrariesLPr(newPkg, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
}
@@ -16193,7 +16265,7 @@
for (int i = 0; i < childCount; i++) {
PackageSetting childPs;
synchronized (mPackages) {
- childPs = mSettings.peekPackageLPr(ps.childPackageNames.get(i));
+ childPs = mSettings.getPackageLPr(ps.childPackageNames.get(i));
}
if (childPs != null) {
PackageRemovedInfo childOutInfo = (outInfo != null
@@ -16370,7 +16442,7 @@
PackageRemovedInfo childInfo = new PackageRemovedInfo();
childInfo.removedPackage = childPackageName;
outInfo.removedChildPackages.put(childPackageName, childInfo);
- PackageSetting childPs = mSettings.peekPackageLPr(childPackageName);
+ PackageSetting childPs = mSettings.getPackageLPr(childPackageName);
if (childPs != null) {
childInfo.origUsers = childPs.queryInstalledUsers(allUserHandles, true);
}
@@ -16410,14 +16482,14 @@
// app but were not declared in the update.
if (isSystemApp(ps)) {
synchronized (mPackages) {
- PackageSetting updatedPs = mSettings.peekPackageLPr(ps.name);
+ PackageSetting updatedPs = mSettings.getPackageLPr(ps.name);
final int childCount = (updatedPs.childPackageNames != null)
? updatedPs.childPackageNames.size() : 0;
for (int i = 0; i < childCount; i++) {
String childPackageName = updatedPs.childPackageNames.get(i);
if (outInfo.removedChildPackages == null
|| outInfo.removedChildPackages.indexOfKey(childPackageName) < 0) {
- PackageSetting childPs = mSettings.peekPackageLPr(childPackageName);
+ PackageSetting childPs = mSettings.getPackageLPr(childPackageName);
if (childPs == null) {
continue;
}
@@ -20606,9 +20678,9 @@
}
/** Called by UserManagerService */
- void createNewUser(int userId) {
+ void createNewUser(int userId, String[] disallowedPackages) {
synchronized (mInstallLock) {
- mSettings.createNewUserLI(this, mInstaller, userId);
+ mSettings.createNewUserLI(this, mInstaller, userId, disallowedPackages);
}
synchronized (mPackages) {
scheduleWritePackageRestrictionsLocked(userId);
@@ -21129,6 +21201,20 @@
return mSettings.wasPackageEverLaunchedLPr(packageName, userId);
}
}
+
+ @Override
+ public void grantRuntimePermission(String packageName, String name, int userId,
+ boolean overridePolicy) {
+ PackageManagerService.this.grantRuntimePermission(packageName, name, userId,
+ overridePolicy);
+ }
+
+ @Override
+ public void revokeRuntimePermission(String packageName, String name, int userId,
+ boolean overridePolicy) {
+ PackageManagerService.this.revokeRuntimePermission(packageName, name, userId,
+ overridePolicy);
+ }
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 1d3471a..a24217e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -30,6 +30,10 @@
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.ApkLite;
+import android.content.pm.PackageParser.PackageLite;
+import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
@@ -48,6 +52,7 @@
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.PrintWriterPrinter;
+import com.android.internal.content.PackageHelper;
import com.android.internal.util.SizedInputStream;
import dalvik.system.DexFile;
@@ -137,11 +142,26 @@
private int runInstall() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
final InstallParams params = makeInstallParams();
+ final String inPath = getNextArg();
+ if (params.sessionParams.sizeBytes < 0 && inPath != null) {
+ File file = new File(inPath);
+ if (file.isFile()) {
+ try {
+ ApkLite baseApk = PackageParser.parseApkLite(file, 0);
+ PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null);
+ params.sessionParams.setSize(
+ PackageHelper.calculateInstalledSize(pkgLite,false, params.sessionParams.abiOverride));
+ } catch (PackageParserException | IOException e) {
+ pw.println("Error: Failed to parse APK file : " + e);
+ return 1;
+ }
+ }
+ }
+
final int sessionId = doCreateSession(params.sessionParams,
params.installerPackageName, params.userId);
boolean abandonSession = true;
try {
- final String inPath = getNextArg();
if (inPath == null && params.sessionParams.sizeBytes == 0) {
pw.println("Error: must either specify a package size or an APK file");
return 1;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 8cab355..6d514e4 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -430,10 +430,6 @@
}
PackageSetting getPackageLPr(String pkgName) {
- return peekPackageLPr(pkgName);
- }
-
- PackageSetting peekPackageLPr(String pkgName) {
return mPackages.get(pkgName);
}
@@ -502,23 +498,20 @@
}
/** Gets and optionally creates a new shared user id. */
- SharedUserSetting getSharedUserLPw(String name,
- int pkgFlags, int pkgPrivateFlags, boolean create) {
+ SharedUserSetting getSharedUserLPw(String name, int pkgFlags, int pkgPrivateFlags,
+ boolean create) throws PackageManagerException {
SharedUserSetting s = mSharedUsers.get(name);
- if (s == null) {
- if (!create) {
- return null;
- }
+ if (s == null && create) {
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.userId = newUserIdLPw(s);
- Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
- // < 0 means we couldn't assign a userid; fall out and return
- // s, which is currently null
- if (s.userId >= 0) {
- mSharedUsers.put(name, s);
+ if (s.userId < 0) {
+ // < 0 means we couldn't assign a userid; throw exception
+ throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
+ "Creating shared user " + name + " failed");
}
+ Log.i(PackageManagerService.TAG, "New shared user " + name + ": id=" + s.userId);
+ mSharedUsers.put(name, s);
}
-
return s;
}
@@ -875,9 +868,9 @@
* Writes per-user package restrictions if the user state has changed. If the user
* state has not changed, this does nothing.
*/
- void writeUserRestrictions(PackageSetting newPackage, PackageSetting oldPackage) {
+ void writeUserRestrictionsLPw(PackageSetting newPackage, PackageSetting oldPackage) {
// package doesn't exist; do nothing
- if (peekPackageLPr(newPackage.name) == null) {
+ if (getPackageLPr(newPackage.name) == null) {
return;
}
// no users defined; do nothing
@@ -3956,7 +3949,7 @@
}
void createNewUserLI(@NonNull PackageManagerService service, @NonNull Installer installer,
- int userHandle) {
+ int userHandle, String[] disallowedPackages) {
String[] volumeUuids;
String[] names;
int[] appIds;
@@ -3977,8 +3970,10 @@
if (ps.pkg == null || ps.pkg.applicationInfo == null) {
continue;
}
+ final boolean shouldInstall = ps.isSystem() &&
+ !ArrayUtils.contains(disallowedPackages, ps.name);
// Only system apps are initially installed.
- ps.setInstalled(ps.isSystem(), userHandle);
+ ps.setInstalled(shouldInstall, userHandle);
// Need to create a data directory for all apps under this user. Accumulate all
// required args and call the installer after mPackages lock has been released
volumeUuids[i] = ps.volumeUuid;
@@ -4088,7 +4083,7 @@
return mVerifierDeviceIdentity;
}
- public boolean hasOtherDisabledSystemPkgWithChildLPr(String parentPackageName,
+ boolean hasOtherDisabledSystemPkgWithChildLPr(String parentPackageName,
String childPackageName) {
final int packageCount = mDisabledSysPackages.size();
for (int i = 0; i < packageCount; i++) {
@@ -4260,7 +4255,7 @@
ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
};
- static final Object[] PRIVATE_FLAG_DUMP_SPEC = new Object[] {
+ private static final Object[] PRIVATE_FLAG_DUMP_SPEC = new Object[] {
ApplicationInfo.PRIVATE_FLAG_HIDDEN, "HIDDEN",
ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
@@ -4272,7 +4267,8 @@
ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE, "PARTIALLY_DIRECT_BOOT_AWARE",
ApplicationInfo.PRIVATE_FLAG_EPHEMERAL, "EPHEMERAL",
ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER",
- ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES, "RESIZEABLE_ACTIVITIES",
+ ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_EXPLICITLY_SET, "RESIZEABLE_ACTIVITIES_EXPLICITLY_SET",
+ ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION, "RESIZEABLE_ACTIVITIES_VIA_SDK_VERSION",
ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND, "BACKUP_IN_FOREGROUND",
};
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index c6b09d1..efd6f46 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -97,6 +97,7 @@
import com.android.server.SystemService;
import com.android.server.am.UserState;
import com.android.server.storage.DeviceStorageMonitorInternal;
+
import libcore.io.IoUtils;
import libcore.util.Objects;
@@ -591,7 +592,7 @@
@Override
public int[] getProfileIds(int userId, boolean enabledOnly) {
if (userId != UserHandle.getCallingUserId()) {
- checkManageUsersPermission("getting profiles related to user " + userId);
+ checkManageOrCreateUsersPermission("getting profiles related to user " + userId);
}
final long ident = Binder.clearCallingIdentity();
try {
@@ -672,12 +673,10 @@
public boolean isSameProfileGroup(int userId, int otherUserId) {
if (userId == otherUserId) return true;
checkManageUsersPermission("check if in the same profile group");
- synchronized (mPackagesLock) {
- return isSameProfileGroupLP(userId, otherUserId);
- }
+ return isSameProfileGroupNoChecks(userId, otherUserId);
}
- private boolean isSameProfileGroupLP(int userId, int otherUserId) {
+ private boolean isSameProfileGroupNoChecks(int userId, int otherUserId) {
synchronized (mUsersLock) {
UserInfo userInfo = getUserInfoLU(userId);
if (userInfo == null || userInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
@@ -879,12 +878,10 @@
public boolean isManagedProfile(int userId) {
int callingUserId = UserHandle.getCallingUserId();
if (callingUserId != userId && !hasManageUsersPermission()) {
- synchronized (mPackagesLock) {
- if (!isSameProfileGroupLP(callingUserId, userId)) {
- throw new SecurityException(
- "You need MANAGE_USERS permission to: check if specified user a " +
- "managed profile outside your profile group");
- }
+ if (!isSameProfileGroupNoChecks(callingUserId, userId)) {
+ throw new SecurityException(
+ "You need MANAGE_USERS permission to: check if specified user a " +
+ "managed profile outside your profile group");
}
}
synchronized (mUsersLock) {
@@ -894,6 +891,18 @@
}
@Override
+ public boolean isUserUnlockingOrUnlocked(int userId) {
+ int callingUserId = UserHandle.getCallingUserId();
+ if (callingUserId != userId && !hasManageUsersPermission()) {
+ if (!isSameProfileGroupNoChecks(callingUserId, userId)) {
+ throw new SecurityException(
+ "You need MANAGE_USERS permission to: check isUserUnlockingOrUnlocked");
+ }
+ }
+ return mLocalService.isUserUnlockingOrUnlocked(userId);
+ }
+
+ @Override
public boolean isDemoUser(int userId) {
int callingUserId = UserHandle.getCallingUserId();
if (callingUserId != userId && !hasManageUsersPermission()) {
@@ -1706,14 +1715,13 @@
UserRestrictionsUtils
.readRestrictions(parser, mGuestRestrictions);
}
- } else if (parser.getName().equals(TAG_DEVICE_POLICY_RESTRICTIONS)
- ) {
- UserRestrictionsUtils.readRestrictions(parser,
- newDevicePolicyGlobalUserRestrictions);
}
break;
}
}
+ } else if (name.equals(TAG_DEVICE_POLICY_RESTRICTIONS)) {
+ UserRestrictionsUtils.readRestrictions(parser,
+ newDevicePolicyGlobalUserRestrictions);
} else if (name.equals(TAG_GLOBAL_RESTRICTION_OWNER_ID)) {
String ownerUserId = parser.getAttributeValue(null, ATTR_ID);
if (ownerUserId != null) {
@@ -2183,9 +2191,17 @@
}
@Override
- public UserInfo createProfileForUser(String name, int flags, int userId) {
+ public UserInfo createProfileForUser(String name, int flags, int userId,
+ String[] disallowedPackages) {
checkManageOrCreateUsersPermission(flags);
- return createUserInternal(name, flags, userId);
+ return createUserInternal(name, flags, userId, disallowedPackages);
+ }
+
+ @Override
+ public UserInfo createProfileForUserEvenWhenDisallowed(String name, int flags, int userId,
+ String[] disallowedPackages) {
+ checkManageOrCreateUsersPermission(flags);
+ return createUserInternalUnchecked(name, flags, userId, disallowedPackages);
}
@Override
@@ -2195,20 +2211,26 @@
}
private UserInfo createUserInternal(String name, int flags, int parentId) {
+ return createUserInternal(name, flags, parentId, null);
+ }
+
+ private UserInfo createUserInternal(String name, int flags, int parentId,
+ String[] disallowedPackages) {
if (hasUserRestriction(UserManager.DISALLOW_ADD_USER, UserHandle.getCallingUserId())) {
Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");
return null;
}
+ return createUserInternalUnchecked(name, flags, parentId, disallowedPackages);
+ }
+
+ private UserInfo createUserInternalUnchecked(String name, int flags, int parentId,
+ String[] disallowedPackages) {
DeviceStorageMonitorInternal dsm = LocalServices
.getService(DeviceStorageMonitorInternal.class);
if (dsm.isMemoryLow()) {
Log.w(LOG_TAG, "Cannot add user. Not enough space on disk.");
return null;
}
- return createUserInternalUnchecked(name, flags, parentId);
- }
-
- private UserInfo createUserInternalUnchecked(String name, int flags, int parentId) {
if (ActivityManager.isLowRamDeviceStatic()) {
return null;
}
@@ -2322,7 +2344,7 @@
storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral());
mPm.prepareUserData(userId, userInfo.serialNumber,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
- mPm.createNewUser(userId);
+ mPm.createNewUser(userId, disallowedPackages);
userInfo.partial = false;
synchronized (mPackagesLock) {
writeUserLP(userData);
@@ -2372,7 +2394,8 @@
@Override
public UserInfo createRestrictedProfile(String name, int parentUserId) {
checkManageOrCreateUsersPermission("setupRestrictedProfile");
- final UserInfo user = createProfileForUser(name, UserInfo.FLAG_RESTRICTED, parentUserId);
+ final UserInfo user = createProfileForUser(
+ name, UserInfo.FLAG_RESTRICTED, parentUserId, null);
if (user == null) {
return null;
}
@@ -3534,7 +3557,7 @@
@Override
public UserInfo createUserEvenWhenDisallowed(String name, int flags) {
- UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL);
+ UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL, null);
// Keep this in sync with UserManager.createUser
if (user != null && !user.isAdmin()) {
setUserRestriction(UserManager.DISALLOW_SMS, true, user.id);
diff --git a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
index e6ec6a6..92729dc 100644
--- a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -43,7 +43,10 @@
// Default value when max burnin radius is not set.
public static final int BURN_IN_MAX_RADIUS_DEFAULT = -1;
- private static final long BURNIN_PROTECTION_WAKEUP_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1);
+ private static final long BURNIN_PROTECTION_FIRST_WAKEUP_INTERVAL_MS =
+ TimeUnit.MINUTES.toMillis(1);
+ private static final long BURNIN_PROTECTION_SUBSEQUENT_WAKEUP_INTERVAL_MS =
+ TimeUnit.MINUTES.toMillis(2);
private static final long BURNIN_PROTECTION_MINIMAL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(10);
private static final boolean DEBUG = false;
@@ -138,6 +141,9 @@
// We don't want to adjust offsets immediately after the device goes into ambient mode.
// Instead, we want to wait until it's more likely that the user is not observing the
// screen anymore.
+ final long interval = mFirstUpdate
+ ? BURNIN_PROTECTION_FIRST_WAKEUP_INTERVAL_MS
+ : BURNIN_PROTECTION_SUBSEQUENT_WAKEUP_INTERVAL_MS;
if (mFirstUpdate) {
mFirstUpdate = false;
} else {
@@ -156,8 +162,7 @@
// Next adjustment at least ten seconds in the future.
long nextWall = nowWall + BURNIN_PROTECTION_MINIMAL_INTERVAL_MS;
// And aligned to the minute.
- nextWall = nextWall - nextWall % BURNIN_PROTECTION_WAKEUP_INTERVAL_MS
- + BURNIN_PROTECTION_WAKEUP_INTERVAL_MS;
+ nextWall = (nextWall - (nextWall % interval)) + interval;
// Use elapsed real time that is adjusted to full minute on wall clock.
final long nextElapsed = nowElapsed + (nextWall - nowWall);
if (DEBUG) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2f25971..b8b16d5 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -28,6 +28,7 @@
import static android.view.WindowManager.DOCKED_TOP;
import static android.view.WindowManager.DOCKED_LEFT;
import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
import static android.view.WindowManager.TAKE_SCREENSHOT_SELECTED_REGION;
import static android.view.WindowManager.LayoutParams.*;
@@ -72,6 +73,7 @@
import android.hardware.hdmi.HdmiPlaybackClient;
import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
import android.hardware.input.InputManagerInternal;
+import android.hardware.power.V1_0.PowerHint;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
@@ -140,6 +142,7 @@
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.policy.PhoneWindow;
import com.android.internal.policy.IShortcutService;
@@ -176,12 +179,13 @@
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_WAKEUP = false;
static final boolean SHOW_STARTING_ANIMATIONS = true;
- static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
// Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
// No longer recommended for desk docks;
static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false;
+ static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
+
static final int SHORT_PRESS_POWER_NOTHING = 0;
static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1;
static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2;
@@ -595,6 +599,13 @@
private static final int DISMISS_KEYGUARD_CONTINUE = 2; // Keyguard has been dismissed.
int mDismissKeyguard = DISMISS_KEYGUARD_NONE;
+ /**
+ * Indicates that we asked the Keyguard to be dismissed and we just wait for the Keyguard to
+ * dismiss itself.
+ */
+ @GuardedBy("Lw")
+ private boolean mCurrentlyDismissingKeyguard;
+
/** The window that is currently dismissing the keyguard. Dismissing the keyguard must only
* be done once per window. */
private WindowState mWinDismissingKeyguard;
@@ -898,7 +909,7 @@
@Override
public void run() {
// send interaction hint to improve redraw performance
- mPowerManagerInternal.powerHint(PowerManagerInternal.POWER_HINT_INTERACTION, 0);
+ mPowerManagerInternal.powerHint(PowerHint.INTERACTION, 0);
updateRotation(false);
}
};
@@ -1829,7 +1840,7 @@
public void onFling(int duration) {
if (mPowerManagerInternal != null) {
mPowerManagerInternal.powerHint(
- PowerManagerInternal.POWER_HINT_INTERACTION, duration);
+ PowerHint.INTERACTION, duration);
}
}
@Override
@@ -2456,22 +2467,24 @@
mNavigationBarWidthForRotationDefault[mSeascapeRotation] =
res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
- // Height of the navigation bar when presented horizontally at bottom
- mNavigationBarHeightForRotationInCarMode[mPortraitRotation] =
- mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] =
- res.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_height_car_mode);
- mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] =
- mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] = res.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);
+ if (ALTERNATE_CAR_MODE_NAV_SIZE) {
+ // Height of the navigation bar when presented horizontally at bottom
+ mNavigationBarHeightForRotationInCarMode[mPortraitRotation] =
+ mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] =
+ res.getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_height_car_mode);
+ mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] =
+ mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);
- // Width of the navigation bar when presented vertically along one side
- mNavigationBarWidthForRotationInCarMode[mPortraitRotation] =
- mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] =
- mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] =
- mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] =
- res.getDimensionPixelSize(
- com.android.internal.R.dimen.navigation_bar_width_car_mode);
+ // Width of the navigation bar when presented vertically along one side
+ mNavigationBarWidthForRotationInCarMode[mPortraitRotation] =
+ mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] =
+ mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] =
+ mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] =
+ res.getDimensionPixelSize(
+ com.android.internal.R.dimen.navigation_bar_width_car_mode);
+ }
}
/** {@inheritDoc} */
@@ -2603,7 +2616,7 @@
}
private int getNavigationBarWidth(int rotation, int uiMode) {
- if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
+ if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
return mNavigationBarWidthForRotationInCarMode[rotation];
} else {
return mNavigationBarWidthForRotationDefault[rotation];
@@ -2624,7 +2637,7 @@
}
private int getNavigationBarHeight(int rotation, int uiMode) {
- if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
+ if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
return mNavigationBarHeightForRotationInCarMode[rotation];
} else {
return mNavigationBarHeightForRotationDefault[rotation];
@@ -2722,7 +2735,7 @@
}
}
- if (overrideConfig != null && overrideConfig != EMPTY) {
+ if (overrideConfig != null && !overrideConfig.equals(EMPTY)) {
if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow: creating context based"
+ " on overrideConfig" + overrideConfig + " for starting window");
final Context overrideContext = context.createConfigurationContext(overrideConfig);
@@ -3265,21 +3278,6 @@
mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
null, null, null, 0, null, null);
return -1;
- } else if (SHOW_PROCESSES_ON_ALT_MENU &&
- (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
- Intent service = new Intent();
- service.setClassName(mContext, "com.android.server.LoadAverageService");
- ContentResolver res = mContext.getContentResolver();
- boolean shown = Settings.Global.getInt(
- res, Settings.Global.SHOW_PROCESSES, 0) != 0;
- if (!shown) {
- mContext.startService(service);
- } else {
- mContext.stopService(service);
- }
- Settings.Global.putInt(
- res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1);
- return -1;
}
}
} else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
@@ -3706,10 +3704,11 @@
@Override
public boolean canShowDismissingWindowWhileLockedLw() {
- // If the keyguard is trusted, it will unlock without a challange. Therefore, windows with
- // FLAG_DISMISS_KEYGUARD don't need to be force hidden, as they will unlock the phone right
- // away anyways.
- return mKeyguardDelegate != null && mKeyguardDelegate.isTrusted();
+ // If the keyguard is trusted, it will unlock without a challenge. Therefore, if we are in
+ // the process of dismissing Keyguard, we don't need to hide them as the phone will be
+ // unlocked right away in any case.
+ return mKeyguardDelegate != null && mKeyguardDelegate.isTrusted()
+ && mCurrentlyDismissingKeyguard;
}
private void launchAssistLongPressAction() {
@@ -3962,14 +3961,6 @@
}
}
}
- final InputEventReceiver.Factory mHideNavInputEventReceiverFactory =
- new InputEventReceiver.Factory() {
- @Override
- public InputEventReceiver createInputEventReceiver(
- InputChannel inputChannel, Looper looper) {
- return new HideNavInputEventReceiver(inputChannel, looper);
- }
- };
@Override
public void setRecentsVisibilityLw(boolean visible) {
@@ -4194,8 +4185,9 @@
mInputConsumer = null;
}
} else if (mInputConsumer == null) {
- mInputConsumer = mWindowManagerFuncs.addInputConsumer(mHandler.getLooper(),
- mHideNavInputEventReceiverFactory);
+ mInputConsumer = mWindowManagerFuncs.createInputConsumer(mHandler.getLooper(),
+ INPUT_CONSUMER_NAVIGATION,
+ (channel, looper) -> new HideNavInputEventReceiver(channel, looper));
}
// For purposes of positioning and showing the nav bar, if we have
@@ -5416,22 +5408,27 @@
}
} else if (mDismissKeyguard != DISMISS_KEYGUARD_NONE) {
mKeyguardHidden = false;
- final boolean trusted = mKeyguardDelegate.isTrusted();
- if (trusted) {
- // No need to un-occlude keyguard - we'll dimiss it right away anyways.
- } else if (setKeyguardOccludedLw(false)) {
- changes |= FINISH_LAYOUT_REDO_LAYOUT
- | FINISH_LAYOUT_REDO_CONFIG
- | FINISH_LAYOUT_REDO_WALLPAPER;
- }
+ boolean willDismiss = false;
if (mDismissKeyguard == DISMISS_KEYGUARD_START) {
+ final boolean trusted = mKeyguardDelegate.isTrusted();
+ willDismiss = trusted && mKeyguardOccluded && mKeyguardDelegate != null
+ && mKeyguardDelegate.isShowing();
+ if (willDismiss) {
+ mCurrentlyDismissingKeyguard = true;
+ }
+
// Only launch the next keyguard unlock window once per window.
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mKeyguardDelegate.dismiss(trusted /* allowWhileOccluded */);
- }
- });
+ mHandler.post(() -> mKeyguardDelegate.dismiss(
+ trusted /* allowWhileOccluded */));
+ }
+
+ // If we are currently dismissing Keyguard, there is no need to unocclude it.
+ if (!mCurrentlyDismissingKeyguard) {
+ if (setKeyguardOccludedLw(false)) {
+ changes |= FINISH_LAYOUT_REDO_LAYOUT
+ | FINISH_LAYOUT_REDO_CONFIG
+ | FINISH_LAYOUT_REDO_WALLPAPER;
+ }
}
} else {
mWinDismissingKeyguard = null;
@@ -5481,11 +5478,23 @@
mStatusBar.getAttrs().privateFlags &= ~PRIVATE_FLAG_KEYGUARD;
mStatusBar.getAttrs().flags &= ~FLAG_SHOW_WALLPAPER;
return true;
+ } else if (wasOccluded != isOccluded) {
+ mKeyguardOccluded = isOccluded;
+ mKeyguardDelegate.setOccluded(isOccluded, false /* animate */);
+ return false;
} else {
return false;
}
}
+ private void onKeyguardShowingStateChanged(boolean showing) {
+ if (!showing) {
+ synchronized (mWindowManagerFuncs.getWindowManagerLock()) {
+ mCurrentlyDismissingKeyguard = false;
+ }
+ }
+ }
+
private boolean isStatusBarKeyguard() {
return mStatusBar != null
&& (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
@@ -7016,7 +7025,8 @@
/** {@inheritDoc} */
@Override
public void systemReady() {
- mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
+ mKeyguardDelegate = new KeyguardServiceDelegate(mContext,
+ this::onKeyguardShowingStateChanged);
mKeyguardDelegate.onSystemReady();
readCameraLensCoverState();
@@ -8102,6 +8112,7 @@
pw.print(" mForceStatusBarFromKeyguard=");
pw.println(mForceStatusBarFromKeyguard);
pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard);
+ pw.print(" mCurrentlyDismissingKeyguard="); pw.println(mCurrentlyDismissingKeyguard);
pw.print(" mWinDismissingKeyguard="); pw.print(mWinDismissingKeyguard);
pw.print(" mHomePressed="); pw.println(mHomePressed);
pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn);
diff --git a/services/core/java/com/android/server/policy/RecentApplicationsBackground.java b/services/core/java/com/android/server/policy/RecentApplicationsBackground.java
deleted file mode 100644
index 694a110..0000000
--- a/services/core/java/com/android/server/policy/RecentApplicationsBackground.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2010 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.server.policy;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.LinearLayout;
-
-/**
- * A vertical linear layout. However, instead of drawing the background
- * behnd the items, it draws the background outside the items based on the
- * padding. If there isn't enough room to draw both, it clips the background
- * instead of the contents.
- */
-public class RecentApplicationsBackground extends LinearLayout {
- private static final String TAG = "RecentApplicationsBackground";
-
- private boolean mBackgroundSizeChanged;
- private Drawable mBackground;
- private Rect mTmp0 = new Rect();
- private Rect mTmp1 = new Rect();
-
- public RecentApplicationsBackground(Context context) {
- this(context, null);
- init();
- }
-
- public RecentApplicationsBackground(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
-
- private void init() {
- mBackground = getBackground();
- setBackgroundDrawable(null);
- setPadding(0, 0, 0, 0);
- setGravity(Gravity.CENTER);
- }
-
- @Override
- protected boolean setFrame(int left, int top, int right, int bottom) {
- setWillNotDraw(false);
- if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
- mBackgroundSizeChanged = true;
- }
- return super.setFrame(left, top, right, bottom);
- }
-
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return who == mBackground || super.verifyDrawable(who);
- }
-
- @Override
- public void jumpDrawablesToCurrentState() {
- super.jumpDrawablesToCurrentState();
- if (mBackground != null) mBackground.jumpToCurrentState();
- }
-
- @Override
- protected void drawableStateChanged() {
- Drawable d = mBackground;
- if (d != null && d.isStateful()) {
- d.setState(getDrawableState());
- }
- super.drawableStateChanged();
- }
-
- @Override
- public void draw(Canvas canvas) {
- final Drawable background = mBackground;
- if (background != null) {
- if (mBackgroundSizeChanged) {
- mBackgroundSizeChanged = false;
- Rect chld = mTmp0;
- Rect bkg = mTmp1;
- mBackground.getPadding(bkg);
- getChildBounds(chld);
- // This doesn't clamp to this view's bounds, which is what we want,
- // so that the drawing is clipped.
- final int top = chld.top - bkg.top;
- final int bottom = chld.bottom + bkg.bottom;
- // The background here is a gradient that wants to
- // extend the full width of the screen (whatever that
- // may be).
- int left, right;
- if (false) {
- // This limits the width of the drawable.
- left = chld.left - bkg.left;
- right = chld.right + bkg.right;
- } else {
- // This expands it to full width.
- left = 0;
- right = getRight();
- }
- background.setBounds(left, top, right, bottom);
- }
- }
- mBackground.draw(canvas);
-
- if (false) {
- android.graphics.Paint p = new android.graphics.Paint();
- p.setColor(0x88ffff00);
- canvas.drawRect(background.getBounds(), p);
- }
- canvas.drawARGB((int)(0.75*0xff), 0, 0, 0);
-
- super.draw(canvas);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mBackground.setCallback(this);
- setWillNotDraw(false);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mBackground.setCallback(null);
- }
-
- private void getChildBounds(Rect r) {
- r.left = r.top = Integer.MAX_VALUE;
- r.bottom = r.right = Integer.MIN_VALUE;
- final int N = getChildCount();
- for (int i=0; i<N; i++) {
- View v = getChildAt(i);
- if (v.getVisibility() == View.VISIBLE) {
- r.left = Math.min(r.left, v.getLeft());
- r.top = Math.min(r.top, v.getTop());
- r.right = Math.max(r.right, v.getRight());
- r.bottom = Math.max(r.bottom, v.getBottom());
- }
- }
- }
-}
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 2069f24..10c237f 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -23,6 +23,7 @@
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
import com.android.server.UiThread;
+import com.android.server.policy.keyguard.KeyguardStateMonitor.OnShowingStateChangedCallback;
import java.io.PrintWriter;
@@ -49,6 +50,7 @@
private final Handler mScrimHandler;
private final KeyguardState mKeyguardState = new KeyguardState();
private DrawnListener mDrawnListenerWhenConnect;
+ private final OnShowingStateChangedCallback mShowingStateChangedCallback;
private static final class KeyguardState {
KeyguardState() {
@@ -117,9 +119,11 @@
}
};
- public KeyguardServiceDelegate(Context context) {
+ public KeyguardServiceDelegate(Context context,
+ OnShowingStateChangedCallback showingStateChangedCallback) {
mContext = context;
mScrimHandler = UiThread.getHandler();
+ mShowingStateChangedCallback = showingStateChangedCallback;
mScrim = createScrim(context, mScrimHandler);
}
@@ -155,7 +159,7 @@
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
mKeyguardService = new KeyguardServiceWrapper(mContext,
- IKeyguardService.Stub.asInterface(service));
+ IKeyguardService.Stub.asInterface(service), mShowingStateChangedCallback);
if (mKeyguardState.systemIsReady) {
// If the system is ready, it means keyguard crashed and restarted.
mKeyguardService.onSystemReady();
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
index 1d85f34..acc67db 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceWrapper.java
@@ -26,6 +26,7 @@
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardService;
import com.android.internal.policy.IKeyguardStateCallback;
+import com.android.server.policy.keyguard.KeyguardStateMonitor.OnShowingStateChangedCallback;
import java.io.PrintWriter;
@@ -39,9 +40,11 @@
private IKeyguardService mService;
private String TAG = "KeyguardServiceWrapper";
- public KeyguardServiceWrapper(Context context, IKeyguardService service) {
+ public KeyguardServiceWrapper(Context context, IKeyguardService service,
+ OnShowingStateChangedCallback showingStateChangedCallback) {
mService = service;
- mKeyguardStateMonitor = new KeyguardStateMonitor(context, service);
+ mKeyguardStateMonitor = new KeyguardStateMonitor(context, service,
+ showingStateChangedCallback);
}
@Override // Binder interface
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 08eaaa9..712b625 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -49,10 +49,13 @@
private int mCurrentUserId;
private final LockPatternUtils mLockPatternUtils;
+ private final OnShowingStateChangedCallback mOnShowingStateChangedCallback;
- public KeyguardStateMonitor(Context context, IKeyguardService service) {
+ public KeyguardStateMonitor(Context context, IKeyguardService service,
+ OnShowingStateChangedCallback showingStateChangedCallback) {
mLockPatternUtils = new LockPatternUtils(context);
mCurrentUserId = ActivityManager.getCurrentUser();
+ mOnShowingStateChangedCallback = showingStateChangedCallback;
try {
service.addStateMonitorCallback(this);
} catch (RemoteException e) {
@@ -83,6 +86,7 @@
@Override // Binder interface
public void onShowingStateChanged(boolean showing) {
mIsShowing = showing;
+ mOnShowingStateChangedCallback.onShowingStateChanged(showing);
}
@Override // Binder interface
@@ -122,4 +126,8 @@
pw.println(prefix + "mTrusted=" + mTrusted);
pw.println(prefix + "mCurrentUserId=" + mCurrentUserId);
}
+
+ public interface OnShowingStateChangedCallback {
+ void onShowingStateChanged(boolean showing);
+ }
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 7576cddad..706828b 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -31,6 +31,7 @@
import android.hardware.SystemSensorManager;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.hardware.power.V1_0.PowerHint;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryManagerInternal;
@@ -84,7 +85,6 @@
import java.util.ArrayList;
import java.util.Arrays;
-import static android.os.PowerManagerInternal.POWER_HINT_INTERACTION;
import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP;
import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE;
import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING;
@@ -163,10 +163,6 @@
// How long a partial wake lock must be held until we consider it a long wake lock.
static final long MIN_LONG_WAKE_CHECK_INTERVAL = 60*1000;
- // Power hints defined in hardware/libhardware/include/hardware/power.h.
- private static final int POWER_HINT_LOW_POWER = 5;
- private static final int POWER_HINT_VR_MODE = 7;
-
// Power features defined in hardware/libhardware/include/hardware/power.h.
private static final int POWER_FEATURE_DOUBLE_TAP_TO_WAKE = 1;
@@ -826,7 +822,7 @@
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
- powerHintInternal(POWER_HINT_LOW_POWER, lowPowerModeEnabled ? 1 : 0);
+ powerHintInternal(PowerHint.LOW_POWER, lowPowerModeEnabled ? 1 : 0);
postAfterBootCompleted(new Runnable() {
@Override
public void run() {
@@ -1152,7 +1148,7 @@
Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
try {
if (eventTime > mLastInteractivePowerHintTime) {
- powerHintInternal(POWER_HINT_INTERACTION, 0);
+ powerHintInternal(PowerHint.INTERACTION, 0);
mLastInteractivePowerHintTime = eventTime;
}
@@ -3083,7 +3079,7 @@
private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
@Override
public void onVrStateChanged(boolean enabled) {
- powerHintInternal(POWER_HINT_VR_MODE, enabled ? 1 : 0);
+ powerHintInternal(PowerHint.VR_MODE, enabled ? 1 : 0);
}
};
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index d219aed..353d663 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -872,6 +872,11 @@
} catch (RemoteException e) {
}
}
+ final Intent lockIntent = new Intent(Intent.ACTION_DEVICE_LOCKED_CHANGED);
+ lockIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ lockIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ mContext.sendBroadcastAsUser(lockIntent, UserHandle.SYSTEM,
+ Manifest.permission.TRUST_LISTENER, /* options */ null);
}
} finally {
Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index b488297..47414a0 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -915,7 +915,11 @@
public void updateTvInputInfo(TvInputInfo inputInfo, int userId) {
String inputInfoPackageName = inputInfo.getServiceInfo().packageName;
String callingPackageName = getCallingPackageName();
- if (!TextUtils.equals(inputInfoPackageName, callingPackageName)) {
+ if (!TextUtils.equals(inputInfoPackageName, callingPackageName)
+ && mContext.checkCallingPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ // Only the app owning the input and system settings are allowed to update info.
throw new IllegalArgumentException("calling package " + callingPackageName
+ " is not allowed to change TvInputInfo for " + inputInfoPackageName);
}
diff --git a/services/core/java/com/android/server/utils/PriorityDump.java b/services/core/java/com/android/server/utils/PriorityDump.java
new file mode 100644
index 0000000..c05cc3f
--- /dev/null
+++ b/services/core/java/com/android/server/utils/PriorityDump.java
@@ -0,0 +1,179 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Helper for {@link android.os.Binder#dump(java.io.FileDescriptor, String[])} that supports the
+ * {@link #PRIORITY_ARG} argument.
+ * <p>
+ * Typical usage:
+ *
+ * <pre><code>
+public class SpringfieldNuclearPowerPlant extends Binder {
+
+ private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() {
+
+ @Override
+ public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Donuts in the box: 1");
+ }
+
+ @Override
+ public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Nuclear reactor status: DANGER - MELTDOWN IMMINENT");
+ }
+ };
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ PriorityDump.dump(mPriorityDumper, fd, pw, args);
+ }
+}
+
+ * </code></pre>
+ *
+ * <strong>Disclaimer</strong>: a real-life service should prioritize core status over donuts :-)
+ *
+ * <p>Then to invoke it:
+ *
+ * <pre><code>
+ *
+ $ adb shell dumpsys snpp
+ Donuts in the box: 1
+ Nuclear reactor status: DANGER - MELTDOWN IMMINENT
+
+ $ adb shell dumpsys snpp --dump_priority CRITICAL
+ Donuts in the box: 1
+
+ $ adb shell dumpsys snpp --dump_priority NORMAL
+ Nuclear reactor status: DANGER - MELTDOWN IMMINENT
+
+ * </code></pre>
+ *
+ *
+ *
+ * <p>To run the unit tests:
+ * <pre><code>
+ *
+ mmm -j32 frameworks/base/services/tests/servicestests/ && \
+ adb install -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && \
+ adb shell am instrument -e class "com.android.server.utils.PriorityDumpTest" \
+ -w "com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner"
+
+ * </code></pre>
+ *
+ *
+ * @hide
+ */
+public final class PriorityDump {
+
+ public static final String PRIORITY_ARG = "--dump_priority";
+
+ private PriorityDump() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Parses {@code} and call the proper {@link PriorityDumper} method when the first argument is
+ * {@code --dump_priority}, stripping the priority and its type.
+ * <p>
+ * For example, if called as {@code --dump_priority HIGH arg1 arg2 arg3}, it will call
+ * <code>dumper.dumpHigh(fd, pw, {"arg1", "arg2", "arg3"}) </code>
+ * <p>
+ * If the {@code --dump_priority} is not set, it calls
+ * {@link PriorityDumper#dump(FileDescriptor, PrintWriter, String[])} passing the whole
+ * {@code args} instead.
+ */
+ public static void dump(PriorityDumper dumper, FileDescriptor fd, PrintWriter pw,
+ String[] args) {
+ if (args != null && args.length >= 2 && args[0].equals(PRIORITY_ARG)) {
+ final String priority = args[1];
+ switch (priority) {
+ case "CRITICAL": {
+ dumper.dumpCritical(fd, pw, getStrippedArgs(args));
+ return;
+ }
+ case "HIGH": {
+ dumper.dumpHigh(fd, pw, getStrippedArgs(args));
+ return;
+ }
+ case "NORMAL": {
+ dumper.dumpNormal(fd, pw, getStrippedArgs(args));
+ return;
+ }
+ }
+ }
+ dumper.dump(fd, pw, args);
+ }
+
+ /**
+ * Gets an array without the {@code --dump_priority PRIORITY} prefix.
+ */
+ private static String[] getStrippedArgs(String[] args) {
+ final String[] stripped = new String[args.length - 2];
+ System.arraycopy(args, 2, stripped, 0, stripped.length);
+ return stripped;
+ }
+
+ /**
+ * Helper for {@link android.os.Binder#dump(java.io.FileDescriptor, String[])} that supports the
+ * {@link #PRIORITY_ARG} argument.
+ *
+ * @hide
+ */
+ public static interface PriorityDumper {
+
+ /**
+ * Dumps only the critical section.
+ */
+ @SuppressWarnings("unused")
+ default void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
+ }
+
+ /**
+ * Dumps only the high-priority section.
+ */
+ @SuppressWarnings("unused")
+ default void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args) {
+ }
+
+ /**
+ * Dumps only the normal section.
+ */
+ @SuppressWarnings("unused")
+ default void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
+ }
+
+ /**
+ * Dumps all sections.
+ * <p>
+ * This method is called when
+ * {@link PriorityDump#dump(PriorityDumper, FileDescriptor, PrintWriter, String[])} is
+ * called without priority arguments. By default, it calls the 3 {@code dumpTYPE} methods,
+ * so sub-classes just need to implement the priority types they support.
+ */
+ @SuppressWarnings("unused")
+ default void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ dumpCritical(fd, pw, args);
+ dumpHigh(fd, pw, args);
+ dumpNormal(fd, pw, args);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 5514551..7439f535 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -480,6 +480,7 @@
WallpaperData mLastWallpaper;
IWallpaperManagerCallback mKeyguardListener;
boolean mWaitingForUnlock;
+ boolean mShuttingDown;
/**
* ID of the current wallpaper, changed every time anything sets a wallpaper.
@@ -607,6 +608,14 @@
private Runnable mResetRunnable = () -> {
synchronized (mLock) {
+ if (mShuttingDown) {
+ // Don't expect wallpaper services to relaunch during shutdown
+ if (DEBUG) {
+ Slog.i(TAG, "Ignoring relaunch timeout during shutdown");
+ }
+ return;
+ }
+
if (!mWallpaper.wallpaperUpdating
&& mWallpaper.userId == mCurrentUserId) {
Slog.w(TAG, "Wallpaper reconnect timed out, "
@@ -867,6 +876,7 @@
public WallpaperManagerService(Context context) {
if (DEBUG) Slog.v(TAG, "WallpaperService startup");
mContext = context;
+ mShuttingDown = false;
mImageWallpaper = ComponentName.unflattenFromString(
context.getResources().getString(R.string.image_wallpaper_component));
mIWindowManager = IWindowManager.Stub.asInterface(
@@ -931,6 +941,21 @@
}
}, userFilter);
+ final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
+ if (DEBUG) {
+ Slog.i(TAG, "Shutting down");
+ }
+ synchronized (mLock) {
+ mShuttingDown = true;
+ }
+ }
+ }
+ }, shutdownFilter);
+
try {
ActivityManagerNative.getDefault().registerUserSwitchObserver(
new UserSwitchObserver() {
@@ -1012,6 +1037,7 @@
for (String filename : sPerUserFiles) {
new File(wallpaperDir, filename).delete();
}
+ mUserRestorecon.remove(userId);
}
}
@@ -1453,7 +1479,7 @@
lockWP.cropHint.set(sysWP.cropHint);
lockWP.width = sysWP.width;
lockWP.height = sysWP.height;
- lockWP.allowBackup = false;
+ lockWP.allowBackup = sysWP.allowBackup;
// Migrate the bitmap files outright; no need to copy
try {
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 43cdf59..6d97796 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.PatternMatcher;
@@ -224,7 +225,13 @@
@Override // Binder call
public String getCurrentWebViewPackageName() {
- return WebViewUpdateService.this.mImpl.getCurrentWebViewPackageName();
+ PackageInfo pi = WebViewUpdateService.this.mImpl.getCurrentWebViewPackage();
+ return pi == null ? null : pi.packageName;
+ }
+
+ @Override // Binder call
+ public PackageInfo getCurrentWebViewPackage() {
+ return WebViewUpdateService.this.mImpl.getCurrentWebViewPackage();
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index 3a93b46..b69a8c1 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -145,8 +145,8 @@
return mSystemInterface.getWebViewPackages();
}
- String getCurrentWebViewPackageName() {
- return mWebViewUpdater.getCurrentWebViewPackageName();
+ PackageInfo getCurrentWebViewPackage() {
+ return mWebViewUpdater.getCurrentWebViewPackage();
}
void enableFallbackLogic(boolean enable) {
@@ -316,6 +316,7 @@
onWebViewProviderChanged(newPackage);
}
} catch (WebViewPackageMissingException e) {
+ mCurrentWebViewPackage = null;
Slog.e(TAG, "Could not find valid WebView package to create " +
"relro with " + e);
}
@@ -371,6 +372,7 @@
providerChanged = (oldPackage == null)
|| !newPackage.packageName.equals(oldPackage.packageName);
} catch (WebViewPackageMissingException e) {
+ mCurrentWebViewPackage = null;
Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView " +
"package " + e);
// If we don't perform the user change but don't have an installed WebView
@@ -548,11 +550,9 @@
return new WebViewProviderResponse(webViewPackage, webViewStatus);
}
- public String getCurrentWebViewPackageName() {
+ public PackageInfo getCurrentWebViewPackage() {
synchronized(mLock) {
- if (mCurrentWebViewPackage == null)
- return null;
- return mCurrentWebViewPackage.packageName;
+ return mCurrentWebViewPackage;
}
}
@@ -579,6 +579,7 @@
PackageInfo newPackage = findPreferredWebViewPackage();
onWebViewProviderChanged(newPackage);
} catch (WebViewPackageMissingException e) {
+ mCurrentWebViewPackage = null;
// If we can't find any valid WebView package we are now in a state where
// mAnyWebViewInstalled is false, so loading WebView will be blocked and we
// should simply wait until we receive an intent declaring a new package was
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 0605d80..893749e 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -654,7 +654,7 @@
final int windowCount = windowList.size();
for (int i = 0; i < windowCount; i++) {
WindowState windowState = windowList.get(i);
- if (windowState.isOnScreen() &&
+ if (windowState.isOnScreen() && windowState.isVisibleLw() &&
!windowState.mWinAnimator.mEnterAnimationPending) {
outWindows.put(windowState.mLayer, windowState);
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index e4ec295..cd46165 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -374,6 +374,7 @@
void goodToGo(AppWindowAnimator topOpeningAppAnimator, AppWindowAnimator topClosingAppAnimator,
ArraySet<AppWindowToken> openingApps, ArraySet<AppWindowToken> closingApps) {
+ int appTransition = mNextAppTransition;
mNextAppTransition = TRANSIT_UNSET;
mAppTransitionState = APP_STATE_RUNNING;
notifyAppTransitionStartingLocked(
@@ -382,7 +383,7 @@
topOpeningAppAnimator != null ? topOpeningAppAnimator.animation : null,
topClosingAppAnimator != null ? topClosingAppAnimator.animation : null);
mService.getDefaultDisplayContentLocked().getDockedDividerController()
- .notifyAppTransitionStarting(openingApps);
+ .notifyAppTransitionStarting(openingApps, appTransition);
// Prolong the start for the transition when docking a task from recents, unless recents
// ended it already then we don't need to wait.
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index a265f26..f1df94f 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -35,6 +35,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.NOTIFY_ACTIVITY_DRAWN;
+import static com.android.server.wm.WindowManagerService.H.NOTIFY_STARTING_WINDOW_DRAWN;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.logWithStack;
@@ -91,19 +92,22 @@
// an activity have been drawn, so they can be made visible together
// at the same time.
// initialize so that it doesn't match mTransactionSequence which is an int.
- long lastTransactionSequence = Long.MIN_VALUE;
- int numInterestingWindows;
- int numDrawnWindows;
+ private long mLastTransactionSequence = Long.MIN_VALUE;
+ private int mNumInterestingWindows;
+ private int mNumDrawnWindows;
boolean inPendingTransaction;
boolean allDrawn;
// Set to true when this app creates a surface while in the middle of an animation. In that
// case do not clear allDrawn until the animation completes.
boolean deferClearAllDrawn;
- // These are to track the app's real drawing status if there were no saved surfaces.
+ /**
+ * These are to track the app's real drawing status if there were no saved surfaces.
+ * @see #updateDrawnWindowStates
+ */
boolean allDrawnExcludingSaved;
- int numInterestingWindowsExcludingSaved;
- int numDrawnWindowsExcludingSaved;
+ private int mNumInterestingWindowsExcludingSaved;
+ private int mNumDrawnWindowsExcludingSaved;
// Is this window's surface needed? This is almost like hidden, except
// it will sometimes be true a little earlier: when the token has
@@ -118,7 +122,7 @@
boolean reportedVisible;
// Last drawn state we reported to the app token.
- boolean reportedDrawn;
+ private boolean reportedDrawn;
// Set to true when the token has been removed from the window mgr.
boolean removed;
@@ -146,7 +150,7 @@
boolean mAppStopped;
int mRotationAnimationHint;
- int mPendingRelaunchCount;
+ private int mPendingRelaunchCount;
private ArrayList<WindowSurfaceController.SurfaceControlWithBackground> mSurfaceViewBackgrounds =
new ArrayList<>();
@@ -154,8 +158,10 @@
ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
- AppWindowToken(WindowManagerService service, IApplicationToken token, boolean _voiceInteraction) {
- super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true);
+ AppWindowToken(WindowManagerService service, IApplicationToken token, boolean _voiceInteraction,
+ DisplayContent displayContent) {
+ super(service, token != null ? token.asBinder() : null, TYPE_APPLICATION, true,
+ displayContent);
appToken = token;
voiceInteraction = _voiceInteraction;
mInputApplicationHandle = new InputApplicationHandle(this);
@@ -364,11 +370,9 @@
@Override
boolean isVisible() {
- if (hidden) {
- // TODO: Should this be checking hiddenRequested instead of hidden?
- return false;
- }
- return super.isVisible();
+ // If the app token isn't hidden then it is considered visible and there is no need to check
+ // its children windows to see if they are visible.
+ return !hidden;
}
@Override
@@ -414,7 +418,7 @@
* surfaces that's eligible, if the app is already stopped.
*/
private void destroySurfaces(boolean cleanupOnResume) {
- final DisplayContentList displayList = new DisplayContentList();
+ final ArrayList<DisplayContent> displayList = new ArrayList();
for (int i = mChildren.size() - 1; i >= 0; i--) {
final WindowState win = mChildren.get(i);
final boolean destroyed = win.destroySurface(cleanupOnResume, mAppStopped);
@@ -729,9 +733,7 @@
if (mTask.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
// We didn't call prepareFreezingBounds on the task, so use the current value.
- final Configuration config = new Configuration(mService.mGlobalConfiguration);
- config.updateFrom(mTask.mOverrideConfig);
- mFrozenMergedConfig.offer(config);
+ mFrozenMergedConfig.offer(new Configuration(mTask.getConfiguration()));
} else {
mFrozenMergedConfig.offer(new Configuration(mTask.mPreparedFrozenMergedConfig));
}
@@ -792,6 +794,9 @@
void overridePlayingAppAnimations(Animation a) {
if (mAppAnimator.isAnimating()) {
final WindowState win = findMainWindow();
+ if (win == null) {
+ return;
+ }
final int width = win.mContainingFrame.width();
final int height = win.mContainingFrame.height();
mAppAnimator.setAnimation(a, width, height, false, STACK_CLIP_NONE);
@@ -894,7 +899,7 @@
}
boolean transferStartingWindow(IBinder transferFrom) {
- final AppWindowToken fromToken = mService.findAppWindowToken(transferFrom);
+ final AppWindowToken fromToken = getDisplayContent().getAppWindowToken(transferFrom);
if (fromToken == null) {
return false;
}
@@ -1039,7 +1044,7 @@
stopFreezingScreen(false, true);
if (DEBUG_ORIENTATION) Slog.i(TAG,
"Setting mOrientationChangeComplete=true because wtoken " + this
- + " numInteresting=" + numInterestingWindows + " numDrawn=" + numDrawnWindows);
+ + " numInteresting=" + mNumInterestingWindows + " numDrawn=" + mNumDrawnWindows);
// This will set mOrientationChangeComplete and cause a pass through layout.
setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER,
"checkAppWindowsReadyToShow: freezingScreen", displayId);
@@ -1053,30 +1058,28 @@
}
}
- @Override
- void updateAllDrawn(int displayId) {
- final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(displayId);
-
+ void updateAllDrawn(DisplayContent dc) {
if (!allDrawn) {
- final int numInteresting = numInterestingWindows;
- if (numInteresting > 0 && numDrawnWindows >= numInteresting) {
+ final int numInteresting = mNumInterestingWindows;
+ if (numInteresting > 0 && mNumDrawnWindows >= numInteresting) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this
- + " interesting=" + numInteresting + " drawn=" + numDrawnWindows);
+ + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows);
allDrawn = true;
// Force an additional layout pass where
// WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked().
- displayContent.setLayoutNeeded();
+ dc.setLayoutNeeded();
mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
}
}
+
if (!allDrawnExcludingSaved) {
- int numInteresting = numInterestingWindowsExcludingSaved;
- if (numInteresting > 0 && numDrawnWindowsExcludingSaved >= numInteresting) {
+ int numInteresting = mNumInterestingWindowsExcludingSaved;
+ if (numInteresting > 0 && mNumDrawnWindowsExcludingSaved >= numInteresting) {
if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawnExcludingSaved: " + this
+ " interesting=" + numInteresting
- + " drawn=" + numDrawnWindowsExcludingSaved);
+ + " drawn=" + mNumDrawnWindowsExcludingSaved);
allDrawnExcludingSaved = true;
- displayContent.setLayoutNeeded();
+ dc.setLayoutNeeded();
if (isAnimatingInvisibleWithSavedSurface()
&& !mService.mFinishedEarlyAnim.contains(this)) {
mService.mFinishedEarlyAnim.add(this);
@@ -1085,6 +1088,87 @@
}
}
+ /**
+ * Updated this app token tracking states for interesting and drawn windows based on the window.
+ *
+ * @return Returns true if the input window is considered interesting and drawn while all the
+ * windows in this app token where not considered drawn as of the last pass.
+ */
+ boolean updateDrawnWindowStates(WindowState w) {
+ if (DEBUG_STARTING_WINDOW && w == startingWindow) {
+ Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
+ + " allDrawn=" + allDrawn + " freezingScreen=" + mAppAnimator.freezingScreen);
+ }
+
+ if (allDrawn && allDrawnExcludingSaved && !mAppAnimator.freezingScreen) {
+ return false;
+ }
+
+ if (mLastTransactionSequence != mService.mTransactionSequence) {
+ mLastTransactionSequence = mService.mTransactionSequence;
+ mNumInterestingWindows = mNumDrawnWindows = 0;
+ mNumInterestingWindowsExcludingSaved = 0;
+ mNumDrawnWindowsExcludingSaved = 0;
+ startingDisplayed = false;
+ }
+
+ final WindowStateAnimator winAnimator = w.mWinAnimator;
+
+ boolean isInterestingAndDrawn = false;
+
+ if (!allDrawn && w.mightAffectAllDrawn(false /* visibleOnly */)) {
+ if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
+ Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
+ + ", isAnimationSet=" + winAnimator.isAnimationSet());
+ if (!w.isDrawnLw()) {
+ Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController
+ + " pv=" + w.mPolicyVisibility
+ + " mDrawState=" + winAnimator.drawStateToString()
+ + " ph=" + w.isParentWindowHidden() + " th=" + hiddenRequested
+ + " a=" + winAnimator.mAnimating);
+ }
+ }
+
+ if (w != startingWindow) {
+ if (w.isInteresting()) {
+ mNumInterestingWindows++;
+ if (w.isDrawnLw()) {
+ mNumDrawnWindows++;
+
+ if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, "tokenMayBeDrawn: "
+ + this + " w=" + w + " numInteresting=" + mNumInterestingWindows
+ + " freezingScreen=" + mAppAnimator.freezingScreen
+ + " mAppFreezing=" + w.mAppFreezing);
+
+ isInterestingAndDrawn = true;
+ }
+ }
+ } else if (w.isDrawnLw()) {
+ mService.mH.sendEmptyMessage(NOTIFY_STARTING_WINDOW_DRAWN);
+ startingDisplayed = true;
+ }
+ }
+
+ if (!allDrawnExcludingSaved && w.mightAffectAllDrawn(true /* visibleOnly */)) {
+ if (w != startingWindow && w.isInteresting()) {
+ mNumInterestingWindowsExcludingSaved++;
+ if (w.isDrawnLw() && !w.isAnimatingWithSavedSurface()) {
+ mNumDrawnWindowsExcludingSaved++;
+
+ if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
+ "tokenMayBeDrawnExcludingSaved: " + this + " w=" + w
+ + " numInteresting=" + mNumInterestingWindowsExcludingSaved
+ + " freezingScreen=" + mAppAnimator.freezingScreen
+ + " mAppFreezing=" + w.mAppFreezing);
+
+ isInterestingAndDrawn = true;
+ }
+ }
+ }
+
+ return isInterestingAndDrawn;
+ }
+
@Override
void stepAppWindowsAnimation(long currentTime, int displayId) {
mAppAnimator.wasAnimating = mAppAnimator.animating;
@@ -1100,16 +1184,16 @@
}
}
- int rebuildWindowListUnchecked(DisplayContent dc, int addIndex) {
- return super.rebuildWindowList(dc, addIndex);
+ int rebuildWindowListUnchecked(int addIndex) {
+ return super.rebuildWindowList(addIndex);
}
@Override
- int rebuildWindowList(DisplayContent dc, int addIndex) {
+ int rebuildWindowList(int addIndex) {
if (mIsExiting && !waitingForReplacement()) {
return addIndex;
}
- return rebuildWindowListUnchecked(dc, addIndex);
+ return rebuildWindowListUnchecked(addIndex);
}
@Override
@@ -1146,11 +1230,11 @@
if (mAppStopped) {
pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped);
}
- if (numInterestingWindows != 0 || numDrawnWindows != 0
+ if (mNumInterestingWindows != 0 || mNumDrawnWindows != 0
|| allDrawn || mAppAnimator.allDrawn) {
- pw.print(prefix); pw.print("numInterestingWindows=");
- pw.print(numInterestingWindows);
- pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
+ pw.print(prefix); pw.print("mNumInterestingWindows=");
+ pw.print(mNumInterestingWindows);
+ pw.print(" mNumDrawnWindows="); pw.print(mNumDrawnWindows);
pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
pw.print(" allDrawn="); pw.print(allDrawn);
pw.print(" (animator="); pw.print(mAppAnimator.allDrawn);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1ef5778..65f2906 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -23,6 +23,12 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.FLAG_PRIVATE;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
import static android.view.WindowManager.DOCKED_BOTTOM;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.DOCKED_TOP;
@@ -43,21 +49,27 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.dipToPixel;
+import static com.android.server.wm.WindowManagerService.localLOGV;
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
import android.annotation.NonNull;
import android.app.ActivityManager.StackId;
+import android.content.res.Configuration;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Region.Op;
import android.hardware.display.DisplayManagerInternal;
import android.os.Debug;
+import android.os.IBinder;
import android.util.DisplayMetrics;
import android.util.Slog;
import android.view.Display;
import android.view.DisplayInfo;
import android.view.IWindow;
-import android.view.Surface;
+
import com.android.internal.util.FastPrintWriter;
import java.io.FileDescriptor;
@@ -65,11 +77,11 @@
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
-class DisplayContentList extends ArrayList<DisplayContent> {
-}
-
/**
* Utility class for keeping track of the WindowStates and other pertinent contents of a
* particular Display.
@@ -77,15 +89,24 @@
* IMPORTANT: No method from this class should ever be used without holding
* WindowManagerService.mWindowMap.
*/
-class DisplayContent extends WindowContainer<TaskStack> {
+class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer> {
/** Unique identifier of this stack. */
private final int mDisplayId;
+ // The display only has 2 child window containers. mTaskStackContainers which contains all
+ // window containers that are related to apps (Activities) and mNonAppWindowContainers which
+ // contains all window containers not related to apps (e.g. Status bar).
+ private final TaskStackContainers mTaskStackContainers = new TaskStackContainers();
+ private final NonAppWindowContainers mNonAppWindowContainers = new NonAppWindowContainers();
+
/** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
* from mDisplayWindows; */
private final WindowList mWindows = new WindowList();
+ // Mapping from a token IBinder to a WindowToken object on this display.
+ private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap();
+
int mInitialDisplayWidth = 0;
int mInitialDisplayHeight = 0;
int mInitialDisplayDensity = 0;
@@ -121,12 +142,14 @@
/** Save allocating when calculating rects */
private final Rect mTmpRect = new Rect();
private final Rect mTmpRect2 = new Rect();
+ private final RectF mTmpRectF = new RectF();
+ private final Matrix mTmpMatrix = new Matrix();
private final Region mTmpRegion = new Region();
final WindowManagerService mService;
/** Remove this display when animation on it has completed. */
- boolean mDeferredRemoval;
+ private boolean mDeferredRemoval;
final DockedStackDividerController mDividerControllerLocked;
@@ -142,6 +165,10 @@
private final GetWindowOnDisplaySearchResult mTmpGetWindowOnDisplaySearchResult =
new GetWindowOnDisplaySearchResult();
+ // True if this display is in the process of being removed. Used to determine if the removal of
+ // the display's direct children should be allowed.
+ private boolean mRemovingDisplay = false;
+
/**
* @param display May not be null.
* @param service You know.
@@ -151,11 +178,15 @@
mDisplayId = display.getDisplayId();
display.getDisplayInfo(mDisplayInfo);
display.getMetrics(mDisplayMetrics);
- isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
+ isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
mService = service;
initializeDisplayBaseInfo();
mDividerControllerLocked = new DockedStackDividerController(service, this);
mDimLayerController = new DimLayerController(this);
+
+ // These are the only direct children we should ever have and they are permanent.
+ super.addChild(mTaskStackContainers, null);
+ super.addChild(mNonAppWindowContainers, null);
}
int getDisplayId() {
@@ -166,6 +197,45 @@
return mWindows;
}
+ WindowToken getWindowToken(IBinder binder) {
+ return mTokenMap.get(binder);
+ }
+
+ AppWindowToken getAppWindowToken(IBinder binder) {
+ final WindowToken token = getWindowToken(binder);
+ if (token == null) {
+ return null;
+ }
+ return token.asAppWindowToken();
+ }
+
+ void setWindowToken(IBinder binder, WindowToken token) {
+ final DisplayContent dc = mService.mRoot.getWindowTokenDisplay(token);
+ if (dc != null) {
+ // We currently don't support adding a window token to the display if the display
+ // already has the binder mapped to another token. If there is a use case for supporting
+ // this moving forward we will either need to merge the WindowTokens some how or have
+ // the binder map to a list of window tokens.
+ throw new IllegalArgumentException("Can't map token=" + token + " to display=" + this
+ + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
+ }
+ mTokenMap.put(binder, token);
+
+ if (token.asAppWindowToken() == null) {
+ // Add non-app token to container hierarchy on the display. App tokens are added through
+ // the parent container managing them (e.g. Tasks).
+ mNonAppWindowContainers.addChild(token, null);
+ }
+ }
+
+ WindowToken removeWindowToken(IBinder binder) {
+ final WindowToken token = mTokenMap.remove(binder);
+ if (token != null && token.asAppWindowToken() == null) {
+ mNonAppWindowContainers.removeChild(token);
+ }
+ return token;
+ }
+
Display getDisplay() {
return mDisplay;
}
@@ -190,19 +260,19 @@
}
boolean isPrivate() {
- return (mDisplay.getFlags() & Display.FLAG_PRIVATE) != 0;
+ return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
}
TaskStack getHomeStack() {
- if (mHomeStack == null && mDisplayId == Display.DEFAULT_DISPLAY) {
+ if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) {
Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this);
}
return mHomeStack;
}
TaskStack getStackById(int stackId) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final TaskStack stack = mChildren.get(i);
+ for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
+ final TaskStack stack = mTaskStackContainers.get(i);
if (stack.mStackId == stackId) {
return stack;
}
@@ -210,18 +280,26 @@
return null;
}
- /** Callback used to notify about configuration changes. */
- void onConfigurationChanged(@NonNull List<Integer> changedStackList) {
+ @Override
+ void onConfigurationChanged(Configuration newParentConfig) {
+ super.onConfigurationChanged(newParentConfig);
+
// The display size information is heavily dependent on the resources in the current
// configuration, so we need to reconfigure it every time the configuration changes.
// See {@link PhoneWindowManager#setInitialDisplaySize}...sigh...
mService.reconfigureDisplayLocked(this);
getDockedDividerController().onConfigurationChanged();
+ }
- for (int i = 0; i < mChildren.size(); i++) {
- final TaskStack stack = mChildren.get(i);
- if (stack.onConfigurationChanged()) {
+ /**
+ * Callback used to trigger bounds update after configuration change and get ids of stacks whose
+ * bounds were updated.
+ */
+ void updateStackBoundsAfterConfigChange(@NonNull List<Integer> changedStackList) {
+ for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
+ final TaskStack stack = mTaskStackContainers.get(i);
+ if (stack.updateBoundsAfterConfigChange()) {
changedStackList.add(stack.mStackId);
}
}
@@ -231,10 +309,6 @@
super.checkAppWindowsReadyToShow(mDisplayId);
}
- void updateAllDrawn() {
- super.updateAllDrawn(mDisplayId);
- }
-
void stepAppWindowsAnimation(long currentTime) {
super.stepAppWindowsAnimation(currentTime, mDisplayId);
}
@@ -289,8 +363,8 @@
void updateDisplayInfo() {
mDisplay.getDisplayInfo(mDisplayInfo);
mDisplay.getMetrics(mDisplayMetrics);
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- mChildren.get(i).updateDisplayInfo(null);
+ for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
+ mTaskStackContainers.get(i).updateDisplayInfo(null);
}
}
@@ -313,8 +387,7 @@
void getLogicalDisplayRect(Rect out) {
// Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
final int orientation = mDisplayInfo.rotation;
- boolean rotated = (orientation == Surface.ROTATION_90
- || orientation == Surface.ROTATION_270);
+ boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
int width = mDisplayInfo.logicalWidth;
@@ -324,51 +397,53 @@
out.set(left, top, left + width, top + height);
}
+ private void getLogicalDisplayRect(Rect out, int orientation) {
+ getLogicalDisplayRect(out);
+
+ // Rotate the Rect if needed.
+ final int currentRotation = mDisplayInfo.rotation;
+ final int rotationDelta = deltaRotation(currentRotation, orientation);
+ if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) {
+ createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix);
+ mTmpRectF.set(out);
+ mTmpMatrix.mapRect(mTmpRectF);
+ mTmpRectF.round(out);
+ }
+ }
+
void getContentRect(Rect out) {
out.set(mContentRect);
}
/** Refer to {@link WindowManagerService#attachStack(int, int, boolean)} */
void attachStack(TaskStack stack, boolean onTop) {
- if (stack.mStackId == HOME_STACK_ID) {
- if (mHomeStack != null) {
- throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
- }
- mHomeStack = stack;
- }
- addChild(stack, onTop);
+ mTaskStackContainers.attachStack(stack, onTop);
}
void moveStack(TaskStack stack, boolean toTop) {
- if (StackId.isAlwaysOnTop(stack.mStackId) && !toTop) {
- // This stack is always-on-top silly...
- Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + stack + " to bottom");
- return;
- }
-
- if (!mChildren.contains(stack)) {
- Slog.wtf(TAG_WM, "moving stack that was not added: " + stack, new Throwable());
- }
- removeChild(stack);
- addChild(stack, toTop);
+ mTaskStackContainers.moveStack(stack, toTop);
}
- private void addChild(TaskStack stack, boolean toTop) {
- int addIndex = toTop ? mChildren.size() : 0;
+ @Override
+ protected void addChild(DisplayChildWindowContainer child,
+ Comparator<DisplayChildWindowContainer> comparator) {
+ throw new UnsupportedOperationException("See DisplayChildWindowContainer");
+ }
- if (toTop
- && mService.isStackVisibleLocked(PINNED_STACK_ID)
- && stack.mStackId != PINNED_STACK_ID) {
- // The pinned stack is always the top most stack (always-on-top) when it is visible.
- // So, stack is moved just below the pinned stack.
- addIndex--;
- TaskStack topStack = mChildren.get(addIndex);
- if (topStack.mStackId != PINNED_STACK_ID) {
- throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren);
- }
+ @Override
+ protected void addChild(DisplayChildWindowContainer child, int index) {
+ throw new UnsupportedOperationException("See DisplayChildWindowContainer");
+ }
+
+ @Override
+ protected void removeChild(DisplayChildWindowContainer child) {
+ // Only allow removal of direct children from this display if the display is in the process
+ // of been removed.
+ if (mRemovingDisplay) {
+ super.removeChild(child);
+ return;
}
- addChild(stack, addIndex);
- setLayoutNeeded();
+ throw new UnsupportedOperationException("See DisplayChildWindowContainer");
}
/**
@@ -380,8 +455,8 @@
}
int taskIdFromPoint(int x, int y) {
- for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
- final TaskStack stack = mChildren.get(stackNdx);
+ for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
+ final TaskStack stack = mTaskStackContainers.get(stackNdx);
final int taskId = stack.taskIdFromPoint(x, y);
if (taskId != -1) {
return taskId;
@@ -395,10 +470,10 @@
* Returns null if the touch doesn't fall into a resizing area.
*/
Task findTaskForResizePoint(int x, int y) {
- final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
+ final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
mTmpTaskForResizePointSearchResult.reset();
- for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
- TaskStack stack = mChildren.get(stackNdx);
+ for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
+ final TaskStack stack = mTaskStackContainers.get(stackNdx);
if (!StackId.isTaskResizeAllowed(stack.mStackId)) {
return null;
}
@@ -413,10 +488,10 @@
void setTouchExcludeRegion(Task focusedTask) {
mTouchExcludeRegion.set(mBaseDisplayRect);
- final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
+ final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
mTmpRect2.setEmpty();
- for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
- final TaskStack stack = mChildren.get(stackNdx);
+ for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
+ final TaskStack stack = mTaskStackContainers.get(stackNdx);
stack.setTouchExcludeRegion(
focusedTask, delta, mTouchExcludeRegion, mContentRect, mTmpRect2);
}
@@ -460,16 +535,16 @@
}
}
- for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
- mChildren.get(stackNdx).switchUser();
+ for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
+ mTaskStackContainers.get(stackNdx).switchUser();
}
rebuildAppWindowList();
}
void resetAnimationBackgroundAnimator() {
- for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
- mChildren.get(stackNdx).resetAnimationBackgroundAnimator();
+ for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
+ mTaskStackContainers.get(stackNdx).resetAnimationBackgroundAnimator();
}
}
@@ -500,12 +575,17 @@
@Override
void removeImmediately() {
- super.removeImmediately();
- if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this);
- mDimLayerController.close();
- if (mDisplayId == Display.DEFAULT_DISPLAY) {
- mService.unregisterPointerEventListener(mTapDetector);
- mService.unregisterPointerEventListener(mService.mMousePositionTracker);
+ mRemovingDisplay = true;
+ try {
+ super.removeImmediately();
+ if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this);
+ mDimLayerController.close();
+ if (mDisplayId == DEFAULT_DISPLAY) {
+ mService.unregisterPointerEventListener(mTapDetector);
+ mService.unregisterPointerEventListener(mService.mMousePositionTracker);
+ }
+ } finally {
+ mRemovingDisplay = false;
}
}
@@ -526,8 +606,8 @@
float dividerAnimationTarget) {
boolean updated = false;
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final TaskStack stack = mChildren.get(i);
+ for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
+ final TaskStack stack = mTaskStackContainers.get(i);
if (stack == null || !stack.isAdjustedForIme()) {
continue;
}
@@ -555,8 +635,8 @@
boolean clearImeAdjustAnimation() {
boolean changed = false;
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final TaskStack stack = mChildren.get(i);
+ for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
+ final TaskStack stack = mTaskStackContainers.get(i);
if (stack != null && stack.isAdjustedForIme()) {
stack.resetAdjustedForIme(true /* adjustBoundsNow */);
changed = true;
@@ -566,8 +646,8 @@
}
void beginImeAdjustAnimation() {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final TaskStack stack = mChildren.get(i);
+ for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
+ final TaskStack stack = mTaskStackContainers.get(i);
if (stack.isVisible() && stack.isAdjustedForIme()) {
stack.beginImeAdjustAnimation();
}
@@ -596,8 +676,8 @@
// - If IME is not visible, divider is not moved and is normal width.
if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final TaskStack stack = mChildren.get(i);
+ for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
+ final TaskStack stack = mTaskStackContainers.get(i);
final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
if (stack.isVisible() && (imeOnBottom || isDockedOnBottom)) {
stack.setAdjustedForIme(imeWin, imeOnBottom && imeHeightChanged);
@@ -608,8 +688,8 @@
mDividerControllerLocked.setAdjustedForIme(
imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight);
} else {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final TaskStack stack = mChildren.get(i);
+ for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
+ final TaskStack stack = mTaskStackContainers.get(i);
stack.resetAdjustedForIme(!dockVisible);
}
mDividerControllerLocked.setAdjustedForIme(
@@ -618,39 +698,23 @@
}
void prepareFreezingTaskBounds() {
- for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
- final TaskStack stack = mChildren.get(stackNdx);
+ for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
+ final TaskStack stack = mTaskStackContainers.get(stackNdx);
stack.prepareFreezingTaskBounds();
}
}
void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
- final int rotationDelta = DisplayContent.deltaRotation(oldRotation, newRotation);
- getLogicalDisplayRect(mTmpRect);
- switch (rotationDelta) {
- case Surface.ROTATION_0:
- mTmpRect2.set(bounds);
- break;
- case Surface.ROTATION_90:
- mTmpRect2.top = mTmpRect.bottom - bounds.right;
- mTmpRect2.left = bounds.top;
- mTmpRect2.right = mTmpRect2.left + bounds.height();
- mTmpRect2.bottom = mTmpRect2.top + bounds.width();
- break;
- case Surface.ROTATION_180:
- mTmpRect2.top = mTmpRect.bottom - bounds.bottom;
- mTmpRect2.left = mTmpRect.right - bounds.right;
- mTmpRect2.right = mTmpRect2.left + bounds.width();
- mTmpRect2.bottom = mTmpRect2.top + bounds.height();
- break;
- case Surface.ROTATION_270:
- mTmpRect2.top = bounds.left;
- mTmpRect2.left = mTmpRect.right - bounds.bottom;
- mTmpRect2.right = mTmpRect2.left + bounds.height();
- mTmpRect2.bottom = mTmpRect2.top + bounds.width();
- break;
- }
- bounds.set(mTmpRect2);
+ getLogicalDisplayRect(mTmpRect, newRotation);
+
+ // Compute a transform matrix to undo the coordinate space transformation,
+ // and present the window at the same physical position it previously occupied.
+ final int deltaRotation = deltaRotation(newRotation, oldRotation);
+ createRotationMatrix(deltaRotation, mTmpRect.width(), mTmpRect.height(), mTmpMatrix);
+
+ mTmpRectF.set(bounds);
+ mTmpMatrix.mapRect(mTmpRectF);
+ mTmpRectF.round(bounds);
}
static int deltaRotation(int oldRotation, int newRotation) {
@@ -659,6 +723,35 @@
return delta;
}
+ private static void createRotationMatrix(int rotation, float displayWidth, float displayHeight,
+ Matrix outMatrix) {
+ // For rotations without Z-ordering we don't need the target rectangle's position.
+ createRotationMatrix(rotation, 0 /* rectLeft */, 0 /* rectTop */, displayWidth,
+ displayHeight, outMatrix);
+ }
+
+ static void createRotationMatrix(int rotation, float rectLeft, float rectTop,
+ float displayWidth, float displayHeight, Matrix outMatrix) {
+ switch (rotation) {
+ case ROTATION_0:
+ outMatrix.reset();
+ break;
+ case ROTATION_270:
+ outMatrix.setRotate(270, 0, 0);
+ outMatrix.postTranslate(0, displayHeight);
+ outMatrix.postTranslate(rectTop, 0);
+ break;
+ case ROTATION_180:
+ outMatrix.reset();
+ break;
+ case ROTATION_90:
+ outMatrix.setRotate(90, 0, 0);
+ outMatrix.postTranslate(displayWidth, 0);
+ outMatrix.postTranslate(-rectTop, rectLeft);
+ break;
+ }
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
final String subPrefix = " " + prefix;
@@ -690,8 +783,8 @@
pw.println();
pw.println(" Application tokens in top down Z order:");
- for (int stackNdx = mChildren.size() - 1; stackNdx >= 0; --stackNdx) {
- final TaskStack stack = mChildren.get(stackNdx);
+ for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
+ final TaskStack stack = mTaskStackContainers.get(stackNdx);
stack.dump(prefix + " ", pw);
}
@@ -700,7 +793,7 @@
pw.println();
pw.println(" Exiting tokens:");
for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
- WindowToken token = mExitingTokens.get(i);
+ final WindowToken token = mExitingTokens.get(i);
pw.print(" Exiting #"); pw.print(i);
pw.print(' '); pw.print(token);
pw.println(':');
@@ -715,11 +808,11 @@
@Override
public String toString() {
- return getName() + " stacks=" + mChildren;
+ return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mChildren;
}
String getName() {
- return "Display " + mDisplayId + " info=" + mDisplayInfo;
+ return "Display " + mDisplayId + " name=\"" + mDisplayInfo.name + "\"";
}
/**
@@ -787,8 +880,7 @@
return true;
}
- void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus,
- WindowState newFocus) {
+ void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus, WindowState newFocus) {
if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) {
return;
}
@@ -872,15 +964,15 @@
}
// No windows from this token on this display
- if (mService.localLOGV) Slog.v(TAG_WM, "Figuring out where to add app window "
+ if (localLOGV) Slog.v(TAG_WM, "Figuring out where to add app window "
+ client.asBinder() + " (token=" + this + ")");
final WindowToken wToken = win.mToken;
// Figure out where the window should go, based on the order of applications.
mTmpGetWindowOnDisplaySearchResult.reset();
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final TaskStack stack = mChildren.get(i);
+ for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
+ final TaskStack stack = mTaskStackContainers.get(i);
stack.getWindowOnDisplayBeforeToken(this, wToken, mTmpGetWindowOnDisplaySearchResult);
if (mTmpGetWindowOnDisplaySearchResult.reachedToken) {
// We have reach the token we are interested in. End search.
@@ -894,7 +986,7 @@
// position; else we need to look some more.
if (pos != null) {
// Move behind any windows attached to this one.
- final WindowToken atoken = mService.mTokenMap.get(pos.mClient.asBinder());
+ final WindowToken atoken = getWindowToken(pos.mClient.asBinder());
if (atoken != null) {
tokenWindowList = getTokenWindowsOnDisplay(atoken);
final int NC = tokenWindowList.size();
@@ -911,8 +1003,8 @@
// Continue looking down until we find the first token that has windows on this display.
mTmpGetWindowOnDisplaySearchResult.reset();
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final TaskStack stack = mChildren.get(i);
+ for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
+ final TaskStack stack = mTaskStackContainers.get(i);
stack.getWindowOnDisplayAfterToken(this, wToken, mTmpGetWindowOnDisplaySearchResult);
if (mTmpGetWindowOnDisplaySearchResult.foundWindow != null) {
// We have found a window after the token. End search.
@@ -924,7 +1016,7 @@
if (pos != null) {
// Move in front of any windows attached to this one.
- final WindowToken atoken = mService.mTokenMap.get(pos.mClient.asBinder());
+ final WindowToken atoken = getWindowToken(pos.mClient.asBinder());
if (atoken != null) {
final WindowState top = atoken.getTopWindow();
if (top != null && top.mSubLayer >= 0) {
@@ -982,6 +1074,10 @@
mService.mWindowsChanged = true;
}
+ void addToWindowList(WindowState win, int index) {
+ mWindows.add(index, win);
+ }
+
void addChildWindowToWindowList(WindowState win) {
final WindowState parentWindow = win.getParentWindow();
@@ -1076,18 +1172,18 @@
// First add all of the exiting app tokens... these are no longer in the main app list,
// but still have windows shown. We put them in the back because now that the animation is
// over we no longer will care about them.
- final int numStacks = mChildren.size();
+ final int numStacks = mTaskStackContainers.size();
for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
- AppTokenList exitingAppTokens = mChildren.get(stackNdx).mExitingAppTokens;
+ AppTokenList exitingAppTokens = mTaskStackContainers.get(stackNdx).mExitingAppTokens;
int NT = exitingAppTokens.size();
for (int j = 0; j < NT; j++) {
- i = exitingAppTokens.get(j).rebuildWindowListUnchecked(this, i);
+ i = exitingAppTokens.get(j).rebuildWindowListUnchecked(i);
}
}
// And add in the still active app tokens in Z order.
for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
- i = mChildren.get(stackNdx).rebuildWindowList(this, i);
+ i = mTaskStackContainers.get(stackNdx).rebuildWindowList(i);
}
i -= lastBelow;
@@ -1233,6 +1329,39 @@
}
}
+ void dumpTokens(PrintWriter pw, boolean dumpAll) {
+ if (mTokenMap.isEmpty()) {
+ return;
+ }
+ pw.println(" Display #" + mDisplayId);
+ final Iterator<WindowToken> it = mTokenMap.values().iterator();
+ while (it.hasNext()) {
+ final WindowToken token = it.next();
+ pw.print(" ");
+ pw.print(token);
+ if (dumpAll) {
+ pw.println(':');
+ token.dump(pw, " ");
+ } else {
+ pw.println();
+ }
+ }
+ }
+
+ void enableSurfaceTrace(FileDescriptor fd) {
+ for (int i = mWindows.size() - 1; i >= 0; i--) {
+ final WindowState win = mWindows.get(i);
+ win.mWinAnimator.enableSurfaceTrace(fd);
+ }
+ }
+
+ void disableSurfaceTrace() {
+ for (int i = mWindows.size() - 1; i >= 0; i--) {
+ final WindowState win = mWindows.get(i);
+ win.mWinAnimator.disableSurfaceTrace();
+ }
+ }
+
static final class GetWindowOnDisplaySearchResult {
boolean reachedToken;
WindowState foundWindow;
@@ -1253,17 +1382,89 @@
}
}
- void enableSurfaceTrace(FileDescriptor fd) {
- for (int i = mWindows.size() - 1; i >= 0; i--) {
- final WindowState win = mWindows.get(i);
- win.mWinAnimator.enableSurfaceTrace(fd);
+ /**
+ * Base class for any direct child window container of {@link #DisplayContent} need to inherit
+ * from. This is mainly a pass through class that allows {@link #DisplayContent} to have
+ * homogeneous children type which is currently required by sub-classes of
+ * {@link WindowContainer} class.
+ */
+ static class DisplayChildWindowContainer<E extends WindowContainer> extends WindowContainer<E> {
+
+ int size() {
+ return mChildren.size();
+ }
+
+ E get(int index) {
+ return mChildren.get(index);
+ }
+
+ @Override
+ boolean fillsParent() {
+ return true;
+ }
+
+ @Override
+ boolean isVisible() {
+ return true;
}
}
- void disableSurfaceTrace() {
- for (int i = mWindows.size() - 1; i >= 0; i--) {
- final WindowState win = mWindows.get(i);
- win.mWinAnimator.disableSurfaceTrace();
+ /**
+ * Window container class that contains all containers on this display relating to Apps.
+ * I.e Activities.
+ */
+ private class TaskStackContainers extends DisplayChildWindowContainer<TaskStack> {
+
+ void attachStack(TaskStack stack, boolean onTop) {
+ if (stack.mStackId == HOME_STACK_ID) {
+ if (mHomeStack != null) {
+ throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
+ }
+ mHomeStack = stack;
+ }
+ addChild(stack, onTop);
+ stack.onDisplayChanged(DisplayContent.this);
}
+
+ void moveStack(TaskStack stack, boolean toTop) {
+ if (StackId.isAlwaysOnTop(stack.mStackId) && !toTop) {
+ // This stack is always-on-top silly...
+ Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + stack + " to bottom");
+ return;
+ }
+
+ if (!mChildren.contains(stack)) {
+ Slog.wtf(TAG_WM, "moving stack that was not added: " + stack, new Throwable());
+ }
+ removeChild(stack);
+ addChild(stack, toTop);
+ }
+
+ private void addChild(TaskStack stack, boolean toTop) {
+ int addIndex = toTop ? mChildren.size() : 0;
+
+ if (toTop
+ && mService.isStackVisibleLocked(PINNED_STACK_ID)
+ && stack.mStackId != PINNED_STACK_ID) {
+ // The pinned stack is always the top most stack (always-on-top) when it is visible.
+ // So, stack is moved just below the pinned stack.
+ addIndex--;
+ TaskStack topStack = mChildren.get(addIndex);
+ if (topStack.mStackId != PINNED_STACK_ID) {
+ throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren);
+ }
+ }
+ addChild(stack, addIndex);
+ setLayoutNeeded();
+ }
+
+ }
+
+ /**
+ * Window container class that contains all containers on this display that are not related to
+ * Apps. E.g. status bar.
+ */
+ private static class NonAppWindowContainers extends DisplayChildWindowContainer<WindowToken> {
+
}
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ef8f492..5854197 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -29,6 +29,7 @@
import static android.view.WindowManager.DOCKED_TOP;
import static com.android.server.wm.AppTransition.DEFAULT_APP_TRANSITION_DURATION;
import static com.android.server.wm.AppTransition.TOUCH_RESPONSE_INTERPOLATOR;
+import static com.android.server.wm.AppTransition.TRANSIT_NONE;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.H.NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED;
@@ -153,7 +154,7 @@
// If the bounds are fullscreen, return the value of the fullscreen configuration
if (bounds == null || (bounds.left == 0 && bounds.top == 0
&& bounds.right == di.logicalWidth && bounds.bottom == di.logicalHeight)) {
- return mService.mGlobalConfiguration.smallestScreenWidthDp;
+ return mDisplayContent.getConfiguration().smallestScreenWidthDp;
}
final int baseDisplayWidth = mDisplayContent.mBaseDisplayWidth;
final int baseDisplayHeight = mDisplayContent.mBaseDisplayHeight;
@@ -190,7 +191,7 @@
}
private void initSnapAlgorithmForRotations() {
- final Configuration baseConfig = mService.mGlobalConfiguration;
+ final Configuration baseConfig = mDisplayContent.getConfiguration();
// Initialize the snap algorithms for all 4 screen orientations.
final Configuration config = new Configuration();
@@ -493,7 +494,7 @@
checkMinimizeChanged(false /* animate */);
}
- void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps) {
+ void notifyAppTransitionStarting(ArraySet<AppWindowToken> openingApps, int appTransition) {
final boolean wasMinimized = mMinimizedDock;
checkMinimizeChanged(true /* animate */);
@@ -502,7 +503,8 @@
// any case that was missed in ActivityStarter.postStartActivityUncheckedProcessing because
// we couldn't retrace the launch of the app in the docked stack to the launch from
// homescreen.
- if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)) {
+ if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps)
+ && appTransition != TRANSIT_NONE) {
mService.showRecentApps(true /* fromHome */);
}
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index a5387bd..065a3dc 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
@@ -25,14 +27,17 @@
import android.app.ActivityManagerNative;
import android.graphics.Rect;
import android.os.Debug;
+import android.os.Looper;
import android.os.RemoteException;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
-import android.view.Display;
import android.view.InputChannel;
+import android.view.InputEventReceiver;
import android.view.KeyEvent;
import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
import com.android.server.input.InputApplicationHandle;
import com.android.server.input.InputManagerService;
import com.android.server.input.InputWindowHandle;
@@ -69,10 +74,103 @@
private final Object mInputDevicesReadyMonitor = new Object();
private boolean mInputDevicesReady;
+ /**
+ * The set of input consumer added to the window manager by name, which consumes input events
+ * for the windows below it.
+ */
+ private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap();
+
+ private static final class EventReceiverInputConsumer extends InputConsumerImpl
+ implements WindowManagerPolicy.InputConsumer {
+ private InputMonitor mInputMonitor;
+ private final InputEventReceiver mInputEventReceiver;
+
+ EventReceiverInputConsumer(WindowManagerService service, InputMonitor monitor,
+ Looper looper, String name,
+ InputEventReceiver.Factory inputEventReceiverFactory) {
+ super(service, name, null);
+ mInputMonitor = monitor;
+ mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
+ mClientChannel, looper);
+ }
+
+ @Override
+ public void dismiss() {
+ synchronized (mService.mWindowMap) {
+ if (mInputMonitor.destroyInputConsumer(mWindowHandle.name)) {
+ mInputEventReceiver.dispose();
+ }
+ }
+ }
+ }
+
public InputMonitor(WindowManagerService service) {
mService = service;
}
+ void addInputConsumer(String name, InputConsumerImpl consumer) {
+ mInputConsumers.put(name, consumer);
+ updateInputWindowsLw(true /* force */);
+ }
+
+ boolean destroyInputConsumer(String name) {
+ if (disposeInputConsumer(mInputConsumers.remove(name))) {
+ updateInputWindowsLw(true /* force */);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean disposeInputConsumer(InputConsumerImpl consumer) {
+ if (consumer != null) {
+ consumer.disposeChannelsLw();
+ return true;
+ }
+ return false;
+ }
+
+ InputConsumerImpl getInputConsumer(String name) {
+ return mInputConsumers.get(name);
+ }
+
+ void layoutInputConsumers(int dw, int dh) {
+ for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
+ mInputConsumers.valueAt(i).layout(dw, dh);
+ }
+ }
+
+ WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name,
+ InputEventReceiver.Factory inputEventReceiverFactory) {
+ if (mInputConsumers.containsKey(name)) {
+ throw new IllegalStateException("Existing input consumer found with name: " + name);
+ }
+
+ final EventReceiverInputConsumer consumer = new EventReceiverInputConsumer(mService,
+ this, looper, name, inputEventReceiverFactory);
+ addInputConsumer(name, consumer);
+ return consumer;
+ }
+
+ void createInputConsumer(String name, InputChannel inputChannel) {
+ if (mInputConsumers.containsKey(name)) {
+ throw new IllegalStateException("Existing input consumer found with name: " + name);
+ }
+
+ final InputConsumerImpl consumer = new InputConsumerImpl(mService, name, inputChannel);
+ switch (name) {
+ case INPUT_CONSUMER_WALLPAPER:
+ consumer.mWindowHandle.hasWallpaper = true;
+ break;
+ case INPUT_CONSUMER_PIP:
+ // The touchable region of the Pip input window is cropped to the bounds of the
+ // stack, and we need FLAG_NOT_TOUCH_MODAL to ensure other events fall through
+ consumer.mWindowHandle.layoutParamsFlags |=
+ WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ break;
+ }
+ addInputConsumer(name, consumer);
+ }
+
/* Notifies the window manager about a broken input channel.
*
* Called by the InputManager.
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 5b0c471..4622329 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -19,8 +19,10 @@
import android.app.AppOpsManager;
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.hardware.power.V1_0.PowerHint;
import android.os.Binder;
import android.os.Debug;
+import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
import android.os.RemoteException;
@@ -41,12 +43,18 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
+import static android.view.WindowManager.INPUT_CONSUMER_PIP;
+import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
@@ -57,15 +65,17 @@
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
@@ -76,10 +86,10 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.H.NOTIFY_STARTING_WINDOW_DRAWN;
import static com.android.server.wm.WindowManagerService.H.REPORT_LOSING_FOCUS;
import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
@@ -108,7 +118,7 @@
private long mUserActivityTimeout = -1;
private boolean mUpdateRotation = false;
private boolean mObscured = false;
- boolean mSyswin = false;
+ private boolean mSyswin = false;
// Set to true when the display contains content to show the user.
// When false, the display manager may choose to mirror or blank the display.
private boolean mDisplayHasContent = false;
@@ -118,7 +128,7 @@
// Last window that requires screen wakelock
WindowState mHoldScreenWindow = null;
// Last window that obscures all windows below
- WindowState mObsuringWindow = null;
+ WindowState mObscuringWindow = null;
// Only set while traversing the default display based on its content.
// Affects the behavior of mirroring on secondary displays.
private boolean mObscureApplicationContentOnSecondaryDisplays = false;
@@ -136,6 +146,17 @@
private final ArrayList<Integer> mChangedStackList = new ArrayList();
+ private final LinkedList<AppWindowToken> mTmpUpdateAllDrawn = new LinkedList();
+
+ private final ArrayList<WindowToken> mTmpTokensList = new ArrayList();
+
+ // Collection of binder tokens mapped to their window type we are allowed to create window
+ // tokens for but that are not current attached to any display. We need to track this here
+ // because a binder token can be added through {@link WindowManagerService#addWindowToken},
+ // but we don't know what display windows for the token will be added to until
+ // {@link WindowManagerService#addWindow} is called.
+ private final HashMap<IBinder, Integer> mUnattachedBinderTokens = new HashMap();
+
// State for the RemoteSurfaceTrace system used in testing. If this is enabled SurfaceControl
// instances will be replaced with an instance that writes a binary representation of all
// commands to mSurfaceTraceFd.
@@ -178,7 +199,7 @@
return dc;
}
- private DisplayContent getDisplayContent(int displayId) {
+ DisplayContent getDisplayContent(int displayId) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final DisplayContent current = mChildren.get(i);
if (current.getDisplayId() == displayId) {
@@ -252,7 +273,6 @@
}
if (!attachedToDisplay) {
- stack.attachDisplayContent(dc);
dc.attachStack(stack, onTop);
}
@@ -337,6 +357,202 @@
return null;
}
+ /** Return the window token associated with the input binder token on the input display */
+ WindowToken getWindowToken(IBinder binder, DisplayContent dc) {
+ final WindowToken token = dc.getWindowToken(binder);
+ if (token != null) {
+ return token;
+ }
+
+ // There is no window token mapped to the binder on the display. Create and map a window
+ // token if it is currently allowed.
+ if (!mUnattachedBinderTokens.containsKey(binder)) {
+ return null;
+ }
+
+ final int type = mUnattachedBinderTokens.get(binder);
+ return new WindowToken(mService, binder, type, true, dc);
+ }
+
+ /** Returns all window tokens mapped to the input binder. */
+ ArrayList<WindowToken> getWindowTokens(IBinder binder) {
+ mTmpTokensList.clear();
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final DisplayContent dc = mChildren.get(i);
+ final WindowToken token = dc.getWindowToken(binder);
+ if (token != null) {
+ mTmpTokensList.add(token);
+ }
+ }
+ return mTmpTokensList;
+ }
+
+ /**
+ * Returns the app window token for the input binder if it exist in the system.
+ * NOTE: Only one AppWindowToken is allowed to exist in the system for a binder token, since
+ * AppWindowToken represents an activity which can only exist on one display.
+ */
+ AppWindowToken getAppWindowToken(IBinder binder) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final DisplayContent dc = mChildren.get(i);
+ final AppWindowToken atoken = dc.getAppWindowToken(binder);
+ if (atoken != null) {
+ return atoken;
+ }
+ }
+ return null;
+ }
+
+ /** Returns the display object the input window token is currently mapped on. */
+ DisplayContent getWindowTokenDisplay(WindowToken token) {
+ if (token == null) {
+ return null;
+ }
+
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final DisplayContent dc = mChildren.get(i);
+ final WindowToken current = dc.getWindowToken(token.token);
+ if (current == token) {
+ return dc;
+ }
+ }
+
+ return null;
+ }
+
+ void addWindowToken(IBinder binder, int type) {
+ if (mUnattachedBinderTokens.containsKey(binder)) {
+ Slog.w(TAG_WM, "addWindowToken: Attempted to add existing binder token: " + binder);
+ return;
+ }
+
+ final ArrayList<WindowToken> tokens = getWindowTokens(binder);
+
+ if (!tokens.isEmpty()) {
+ Slog.w(TAG_WM, "addWindowToken: Attempted to add binder token: " + binder
+ + " for already created window tokens: " + tokens);
+ return;
+ }
+
+ mUnattachedBinderTokens.put(binder, type);
+
+ // TODO(multi-display): By default we add this to the default display, but maybe we
+ // should provide an API for a token to be added to any display?
+ final WindowToken token = new WindowToken(mService, binder, type, true,
+ getDisplayContent(DEFAULT_DISPLAY));
+ if (type == TYPE_WALLPAPER) {
+ mService.mWallpaperControllerLocked.addWallpaperToken(token);
+ }
+ }
+
+ ArrayList<WindowToken> removeWindowToken(IBinder binder) {
+ mUnattachedBinderTokens.remove(binder);
+
+ mTmpTokensList.clear();
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final DisplayContent dc = mChildren.get(i);
+ final WindowToken token = dc.removeWindowToken(binder);
+ if (token != null) {
+ mTmpTokensList.add(token);
+ }
+ }
+ return mTmpTokensList;
+ }
+
+ /**
+ * Removed the mapping to the input binder for the system if it no longer as a window token
+ * associated with it on any display.
+ */
+ void removeWindowTokenIfPossible(IBinder binder) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final DisplayContent dc = mChildren.get(i);
+ final WindowToken token = dc.getWindowToken(binder);
+ if (token != null) {
+ return;
+ }
+ }
+
+ mUnattachedBinderTokens.remove(binder);
+ }
+
+ void removeAppToken(IBinder binder) {
+ final ArrayList<WindowToken> removedTokens = removeWindowToken(binder);
+ if (removedTokens == null || removedTokens.isEmpty()) {
+ Slog.w(TAG_WM, "removeAppToken: Attempted to remove non-existing token: " + binder);
+ return;
+ }
+
+ for (int i = removedTokens.size() - 1; i >= 0; --i) {
+ WindowToken wtoken = removedTokens.get(i);
+ AppWindowToken appToken = wtoken.asAppWindowToken();
+
+ if (appToken == null) {
+ Slog.w(TAG_WM,
+ "Attempted to remove non-App token: " + binder + " wtoken=" + wtoken);
+ continue;
+ }
+
+ AppWindowToken startingToken = null;
+
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + appToken);
+
+ boolean delayed = appToken.setVisibility(null, false, TRANSIT_UNSET, true,
+ appToken.voiceInteraction);
+
+ mService.mOpeningApps.remove(appToken);
+ appToken.waitingToShow = false;
+ if (mService.mClosingApps.contains(appToken)) {
+ delayed = true;
+ } else if (mService.mAppTransition.isTransitionSet()) {
+ mService.mClosingApps.add(appToken);
+ delayed = true;
+ }
+
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app " + appToken
+ + " delayed=" + delayed
+ + " animation=" + appToken.mAppAnimator.animation
+ + " animating=" + appToken.mAppAnimator.animating);
+
+ if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
+ + appToken + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
+
+ final TaskStack stack = appToken.mTask.mStack;
+ if (delayed && !appToken.isEmpty()) {
+ // set the token aside because it has an active animation to be finished
+ if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM,
+ "removeAppToken make exiting: " + appToken);
+ stack.mExitingAppTokens.add(appToken);
+ appToken.mIsExiting = true;
+ } else {
+ // Make sure there is no animation running on this token, so any windows associated
+ // with it will be removed as soon as their animations are complete
+ appToken.mAppAnimator.clearAnimation();
+ appToken.mAppAnimator.animating = false;
+ appToken.removeIfPossible();
+ }
+
+ appToken.removed = true;
+ if (appToken.startingData != null) {
+ startingToken = appToken;
+ }
+ appToken.stopFreezingScreen(true, true);
+ if (mService.mFocusedApp == appToken) {
+ if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + appToken);
+ mService.mFocusedApp = null;
+ mService.updateFocusedWindowLocked(
+ UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
+ mService.mInputMonitor.setFocusedAppLw(null);
+ }
+
+ if (!delayed) {
+ appToken.updateReportedVisibilityLocked();
+ }
+
+ // Will only remove if startingToken non null.
+ mService.scheduleRemoveStartingWindowLocked(startingToken);
+ }
+ }
+
// TODO: Users would have their own window containers under the display container?
void switchUser() {
final int count = mChildren.size();
@@ -346,18 +562,35 @@
}
}
- int[] onConfigurationChanged(Configuration config) {
+ /** Set new config and return array of ids of stacks that were changed during update. */
+ int[] setGlobalConfigurationIfNeeded(Configuration newConfiguration) {
+ final boolean configChanged = getConfiguration().diff(newConfiguration) != 0;
+ if (!configChanged) {
+ return null;
+ }
+ onConfigurationChanged(newConfiguration);
+ return updateStackBoundsAfterConfigChange();
+ }
+
+ @Override
+ void onConfigurationChanged(Configuration newParentConfig) {
prepareFreezingTaskBounds();
- mService.mGlobalConfiguration = new Configuration(config);
+ super.onConfigurationChanged(newParentConfig);
mService.mPolicy.onConfigurationChanged();
+ }
+ /**
+ * Callback used to trigger bounds update after configuration change and get ids of stacks whose
+ * bounds were updated.
+ */
+ private int[] updateStackBoundsAfterConfigChange() {
mChangedStackList.clear();
final int numDisplays = mChildren.size();
for (int i = 0; i < numDisplays; ++i) {
final DisplayContent dc = mChildren.get(i);
- dc.onConfigurationChanged(mChangedStackList);
+ dc.updateStackBoundsAfterConfigChange(mChangedStackList);
}
return mChangedStackList.isEmpty() ? null : ArrayUtils.convertToIntArray(mChangedStackList);
@@ -471,8 +704,16 @@
}
void updateInputWindows(InputMonitor inputMonitor, WindowState inputFocus, boolean inDrag) {
- boolean addInputConsumerHandle = mService.mInputConsumer != null;
- boolean addWallpaperInputConsumerHandle = mService.mWallpaperInputConsumer != null;
+ final InputConsumerImpl navInputConsumer =
+ mService.mInputMonitor.getInputConsumer(INPUT_CONSUMER_NAVIGATION);
+ final InputConsumerImpl pipInputConsumer =
+ mService.mInputMonitor.getInputConsumer(INPUT_CONSUMER_PIP);
+ final InputConsumerImpl wallpaperInputConsumer =
+ mService.mInputMonitor.getInputConsumer(INPUT_CONSUMER_WALLPAPER);
+ boolean addInputConsumerHandle = navInputConsumer != null;
+ boolean addPipInputConsumerHandle = pipInputConsumer != null;
+ boolean addWallpaperInputConsumerHandle = wallpaperInputConsumer != null;
+ final Rect pipTouchableBounds = addPipInputConsumerHandle ? new Rect() : null;
final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
boolean disableWallpaperTouchEvents = false;
@@ -489,9 +730,20 @@
// Skip this window because it cannot possibly receive input.
continue;
}
+
+ if (addPipInputConsumerHandle
+ && child.getStackId() == PINNED_STACK_ID
+ && inputWindowHandle.layer <= pipInputConsumer.mWindowHandle.layer) {
+ // Update the bounds of the Pip input consumer to match the Pinned stack
+ child.getStack().getBounds(pipTouchableBounds);
+ pipInputConsumer.mWindowHandle.touchableRegion.set(pipTouchableBounds);
+ inputMonitor.addInputWindowHandle(pipInputConsumer.mWindowHandle);
+ addPipInputConsumerHandle = false;
+ }
+
if (addInputConsumerHandle
- && inputWindowHandle.layer <= mService.mInputConsumer.mWindowHandle.layer) {
- inputMonitor.addInputWindowHandle(mService.mInputConsumer.mWindowHandle);
+ && inputWindowHandle.layer <= navInputConsumer.mWindowHandle.layer) {
+ inputMonitor.addInputWindowHandle(navInputConsumer.mWindowHandle);
addInputConsumerHandle = false;
}
@@ -499,8 +751,7 @@
if (child.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER &&
child.isVisibleLw()) {
// Add the wallpaper input consumer above the first visible wallpaper.
- inputMonitor.addInputWindowHandle(
- mService.mWallpaperInputConsumer.mWindowHandle);
+ inputMonitor.addInputWindowHandle(wallpaperInputConsumer.mWindowHandle);
addWallpaperInputConsumerHandle = false;
}
}
@@ -534,7 +785,7 @@
if (addWallpaperInputConsumerHandle) {
// No visible wallpaper found, add the wallpaper input consumer at the end.
- inputMonitor.addInputWindowHandle(mService.mWallpaperInputConsumer.mWindowHandle);
+ inputMonitor.addInputWindowHandle(wallpaperInputConsumer.mWindowHandle);
}
}
@@ -690,7 +941,7 @@
">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
mService.openSurfaceTransaction();
try {
- mService.mRoot.applySurfaceChangesTransaction(recoveringMemory, defaultDw, defaultDh);
+ applySurfaceChangesTransaction(recoveringMemory, defaultDw, defaultDh);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
@@ -873,7 +1124,7 @@
if (mSustainedPerformanceModeCurrent != mSustainedPerformanceModeEnabled) {
mSustainedPerformanceModeEnabled = mSustainedPerformanceModeCurrent;
mService.mPowerManagerInternal.powerHint(
- mService.mPowerManagerInternal.POWER_HINT_SUSTAINED_PERFORMANCE_MODE,
+ PowerHint.SUSTAINED_PERFORMANCE,
(mSustainedPerformanceModeEnabled ? 1 : 0));
}
@@ -912,7 +1163,7 @@
}
mService.mPendingRemove.toArray(mService.mPendingRemoveTmp);
mService.mPendingRemove.clear();
- DisplayContentList displayList = new DisplayContentList();
+ ArrayList<DisplayContent> displayList = new ArrayList();
for (i = 0; i < N; i++) {
final WindowState w = mService.mPendingRemoveTmp[i];
w.removeImmediately();
@@ -952,7 +1203,7 @@
// TODO: Super crazy long method that should be broken down...
private void applySurfaceChangesTransaction(boolean recoveringMemory, int defaultDw, int defaultDh) {
mHoldScreenWindow = null;
- mObsuringWindow = null;
+ mObscuringWindow = null;
if (mService.mWatermark != null) {
mService.mWatermark.positionSurface(defaultDw, defaultDh);
@@ -973,7 +1224,6 @@
final int count = mChildren.size();
for (int j = 0; j < count; ++j) {
final DisplayContent dc = mChildren.get(j);
- boolean updateAllDrawn = false;
WindowList windows = dc.getWindowList();
DisplayInfo displayInfo = dc.getDisplayInfo();
final int displayId = dc.getDisplayId();
@@ -986,6 +1236,7 @@
mDisplayHasContent = false;
mPreferredRefreshRate = 0;
mPreferredModeId = 0;
+ mTmpUpdateAllDrawn.clear();
int repeats = 0;
do {
@@ -1069,45 +1320,14 @@
if (isDefaultDisplay && obscuredChanged && w.isVisibleLw()
&& mService.mWallpaperControllerLocked.isWallpaperTarget(w)) {
// This is the wallpaper target and its obscured state changed... make sure the
- // current wallaper's visibility has been updated accordingly.
+ // current wallpaper's visibility has been updated accordingly.
mService.mWallpaperControllerLocked.updateWallpaperVisibility();
}
+ w.handleWindowMovedIfNeeded();
+
final WindowStateAnimator winAnimator = w.mWinAnimator;
- // If the window has moved due to its containing content frame changing, then
- // notify the listeners and optionally animate it. Simply checking a change of
- // position is not enough, because being move due to dock divider is not a trigger
- // for animation.
- if (w.hasMoved()) {
- // Frame has moved, containing content frame has also moved, and we're not
- // currently animating... let's do something.
- final int left = w.mFrame.left;
- final int top = w.mFrame.top;
- final boolean adjustedForMinimizedDockOrIme = task != null
- && (task.mStack.isAdjustedForMinimizedDockedStack()
- || task.mStack.isAdjustedForIme());
- if (mService.okToDisplay()
- && (w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
- && !w.isDragResizing() && !adjustedForMinimizedDockOrIme
- && (task == null || w.getTask().mStack.hasMovementAnimations())
- && !w.mWinAnimator.mLastHidden) {
- winAnimator.setMoveAnimation(left, top);
- }
-
- //TODO (multidisplay): Accessibility supported only for the default display.
- if (mService.mAccessibilityController != null
- && displayId == Display.DEFAULT_DISPLAY) {
- mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
- }
-
- try {
- w.mClient.moved(left, top);
- } catch (RemoteException e) {
- }
- w.mMovedByResize = false;
- }
-
//Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
w.mContentChanged = false;
@@ -1154,71 +1374,10 @@
}
final AppWindowToken atoken = w.mAppToken;
- if (DEBUG_STARTING_WINDOW && atoken != null && w == atoken.startingWindow) {
- Slog.d(TAG, "updateWindows: starting " + w
- + " isOnScreen=" + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
- + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
- }
- if (atoken != null && (!atoken.allDrawn || !atoken.allDrawnExcludingSaved
- || atoken.mAppAnimator.freezingScreen)) {
- if (atoken.lastTransactionSequence != mService.mTransactionSequence) {
- atoken.lastTransactionSequence = mService.mTransactionSequence;
- atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
- atoken.numInterestingWindowsExcludingSaved = 0;
- atoken.numDrawnWindowsExcludingSaved = 0;
- atoken.startingDisplayed = false;
- }
- if (!atoken.allDrawn && w.mightAffectAllDrawn(false /* visibleOnly */)) {
- if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
- Slog.v(TAG, "Eval win " + w + ": isDrawn="
- + w.isDrawnLw()
- + ", isAnimationSet=" + winAnimator.isAnimationSet());
- if (!w.isDrawnLw()) {
- Slog.v(TAG, "Not displayed: s="
- + winAnimator.mSurfaceController
- + " pv=" + w.mPolicyVisibility
- + " mDrawState=" + winAnimator.drawStateToString()
- + " ph=" + w.isParentWindowHidden()
- + " th=" + atoken.hiddenRequested
- + " a=" + winAnimator.mAnimating);
- }
- }
- if (w != atoken.startingWindow) {
- if (w.isInteresting()) {
- atoken.numInterestingWindows++;
- if (w.isDrawnLw()) {
- atoken.numDrawnWindows++;
- if (DEBUG_VISIBILITY || DEBUG_ORIENTATION)
- Slog.v(TAG, "tokenMayBeDrawn: " + atoken
- + " w=" + w + " numInteresting="
- + atoken.numInterestingWindows
- + " freezingScreen="
- + atoken.mAppAnimator.freezingScreen
- + " mAppFreezing=" + w.mAppFreezing);
- updateAllDrawn = true;
- }
- }
- } else if (w.isDrawnLw()) {
- mService.mH.sendEmptyMessage(NOTIFY_STARTING_WINDOW_DRAWN);
- atoken.startingDisplayed = true;
- }
- }
- if (!atoken.allDrawnExcludingSaved
- && w.mightAffectAllDrawn(true /* visibleOnly */)) {
- if (w != atoken.startingWindow && w.isInteresting()) {
- atoken.numInterestingWindowsExcludingSaved++;
- if (w.isDrawnLw() && !w.isAnimatingWithSavedSurface()) {
- atoken.numDrawnWindowsExcludingSaved++;
- if (DEBUG_VISIBILITY || DEBUG_ORIENTATION)
- Slog.v(TAG, "tokenMayBeDrawnExcludingSaved: " + atoken
- + " w=" + w + " numInteresting="
- + atoken.numInterestingWindowsExcludingSaved
- + " freezingScreen="
- + atoken.mAppAnimator.freezingScreen
- + " mAppFreezing=" + w.mAppFreezing);
- updateAllDrawn = true;
- }
- }
+ if (atoken != null) {
+ final boolean updateAllDrawn = atoken.updateDrawnWindowStates(w);
+ if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(atoken)) {
+ mTmpUpdateAllDrawn.add(atoken);
}
}
@@ -1227,7 +1386,7 @@
focusDisplayed = true;
}
- mService.updateResizingWindows(w);
+ w.updateResizingWindowIfNeeded();
}
mService.mDisplayManagerInternal.setDisplayProperties(displayId,
@@ -1238,10 +1397,11 @@
dc.stopDimmingIfNeeded();
- if (updateAllDrawn) {
+ while (!mTmpUpdateAllDrawn.isEmpty()) {
+ final AppWindowToken atoken = mTmpUpdateAllDrawn.removeLast();
// See if any windows have been drawn, so they (and others associated with them)
// can now be shown.
- dc.updateAllDrawn();
+ atoken.updateAllDrawn(dc);
}
}
@@ -1269,7 +1429,7 @@
// so we want to leave all of them as undimmed (for
// performance reasons).
if (!mObscured) {
- mObsuringWindow = w;
+ mObscuringWindow = w;
}
mObscured = true;
@@ -1434,6 +1594,13 @@
}
}
+ void dumpTokens(PrintWriter pw, boolean dumpAll) {
+ pw.println(" All tokens:");
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ mChildren.get(i).dumpTokens(pw, dumpAll);
+ }
+ }
+
@Override
String getName() {
return "ROOT";
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 9e8c609..19c9b7d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -20,7 +20,6 @@
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -35,7 +34,6 @@
import android.view.DisplayInfo;
import android.view.Surface;
-import android.view.SurfaceControl;
import com.android.server.EventLogTags;
import java.io.PrintWriter;
@@ -43,17 +41,17 @@
class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerUser {
static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
// Return value from {@link setBounds} indicating no change was made to the Task bounds.
- static final int BOUNDS_CHANGE_NONE = 0;
+ private static final int BOUNDS_CHANGE_NONE = 0;
// Return value from {@link setBounds} indicating the position of the Task bounds changed.
- static final int BOUNDS_CHANGE_POSITION = 1;
+ private static final int BOUNDS_CHANGE_POSITION = 1;
// Return value from {@link setBounds} indicating the size of the Task bounds changed.
- static final int BOUNDS_CHANGE_SIZE = 1 << 1;
+ private static final int BOUNDS_CHANGE_SIZE = 1 << 1;
// TODO: Track parent marks like this in WindowContainer.
TaskStack mStack;
final int mTaskId;
final int mUserId;
- boolean mDeferRemoval = false;
+ private boolean mDeferRemoval = false;
final WindowManagerService mService;
// Content limits relative to the DisplayContent this sits in.
@@ -65,17 +63,11 @@
private final Rect mTempInsetBounds = new Rect();
// Device rotation as of the last time {@link #mBounds} was set.
- int mRotation;
+ private int mRotation;
// Whether mBounds is fullscreen
private boolean mFillsParent = true;
- /**
- * Contains configurations settings that are different from the parent configuration due to
- * stack specific operations. E.g. {@link #setBounds}.
- */
- Configuration mOverrideConfig = Configuration.EMPTY;
-
// For comparison with DisplayContent bounds.
private Rect mTmpRect = new Rect();
// For handling display rotations.
@@ -120,8 +112,9 @@
}
}
- if (wtoken.mParent != null) {
- wtoken.mParent.removeChild(wtoken);
+ final WindowContainer parent = wtoken.getParent();
+ if (parent != null) {
+ parent.removeChild(wtoken);
}
addChild(wtoken, addPos);
wtoken.mTask = this;
@@ -153,7 +146,7 @@
if (content != null) {
content.mDimLayerController.removeDimLayerUser(this);
}
- mParent.removeChild(this);
+ getParent().removeChild(this);
mService.mTaskIdToTask.delete(mTaskId);
}
@@ -165,11 +158,12 @@
if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
+ " from stack=" + mStack);
EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
- mParent.removeChild(this);
+ getParent().removeChild(this);
stack.addTask(this, toTop);
}
- void positionTaskInStack(TaskStack stack, int position, Rect bounds, Configuration config) {
+ void positionTaskInStack(TaskStack stack, int position, Rect bounds,
+ Configuration overrideConfig) {
if (mStack != null && stack != mStack) {
if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
+ " from stack=" + mStack);
@@ -177,7 +171,7 @@
mStack.removeChild(this);
}
stack.positionTask(this, position, showForAllUsers());
- resizeLocked(bounds, config, false /* force */);
+ resizeLocked(bounds, overrideConfig, false /* force */);
for (int activityNdx = mChildren.size() - 1; activityNdx >= 0; --activityNdx) {
mChildren.get(activityNdx).notifyMovedInStack();
@@ -254,7 +248,7 @@
if (displayContent != null) {
displayContent.mDimLayerController.updateDimLayer(this);
}
- mOverrideConfig = mFillsParent ? Configuration.EMPTY : overrideConfig;
+ onOverrideConfigurationChanged(mFillsParent ? Configuration.EMPTY : overrideConfig);
return boundsChange;
}
@@ -283,8 +277,7 @@
}
boolean isResizeable() {
- return !mHomeTask
- && (ActivityInfo.isResizeableMode(mResizeMode) || mService.mForceResizableTasks);
+ return ActivityInfo.isResizeableMode(mResizeMode) || mService.mForceResizableTasks;
}
boolean isOnTopLauncher() {
@@ -292,7 +285,7 @@
}
boolean cropWindowsToStackBounds() {
- return !mHomeTask && (isResizeable() || mResizeMode == RESIZE_MODE_CROP_WINDOWS);
+ return isResizeable();
}
boolean isHomeTask() {
@@ -321,8 +314,7 @@
*/
void prepareFreezingBounds() {
mPreparedFrozenBounds.set(mBounds);
- mPreparedFrozenMergedConfig.setTo(mService.mGlobalConfiguration);
- mPreparedFrozenMergedConfig.updateFrom(mOverrideConfig);
+ mPreparedFrozenMergedConfig.setTo(getConfiguration());
}
/**
@@ -334,9 +326,9 @@
* bounds's bottom; false if the task's top should be aligned
* the adjusted bounds's top.
*/
- void alignToAdjustedBounds(
- Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
- if (!isResizeable() || mOverrideConfig == Configuration.EMPTY) {
+ void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
+ final Configuration overrideConfig = getOverrideConfiguration();
+ if (!isResizeable() || Configuration.EMPTY.equals(overrideConfig)) {
return;
}
@@ -348,7 +340,7 @@
mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
}
setTempInsetBounds(tempInsetBounds);
- resizeLocked(mTmpRect2, mOverrideConfig, false /* forced */);
+ resizeLocked(mTmpRect2, overrideConfig, false /* forced */);
}
/** Return true if the current bound can get outputted to the rest of the system as-is. */
@@ -500,12 +492,12 @@
mTmpRect2.set(mBounds);
if (!StackId.isTaskResizeAllowed(mStack.mStackId)) {
- setBounds(mTmpRect2, mOverrideConfig);
+ setBounds(mTmpRect2, getOverrideConfiguration());
return;
}
displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
- if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) {
+ if (setBounds(mTmpRect2, getOverrideConfiguration()) != BOUNDS_CHANGE_NONE) {
// Post message to inform activity manager of the bounds change simulating a one-way
// call. We do this to prevent a deadlock between window manager lock and activity
// manager lock been held.
@@ -567,7 +559,7 @@
@Override
public boolean dimFullscreen() {
- return isHomeTask() || isFullscreen();
+ return isFullscreen();
}
boolean isFullscreen() {
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 21db840..6887312 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -478,7 +478,7 @@
private int getDimSide(int x) {
if (mTask.mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID
|| !mTask.mStack.fillsParent()
- || mService.mGlobalConfiguration.orientation != ORIENTATION_LANDSCAPE) {
+ || mTask.mStack.getConfiguration().orientation != ORIENTATION_LANDSCAPE) {
return CTRL_NONE;
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 329afad..56fdc33 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -94,16 +94,16 @@
private boolean mFillsParent = true;
// Device rotation as of the last time {@link #mBounds} was set.
- int mRotation;
+ private int mRotation;
/** Density as of last time {@link #mBounds} was set. */
- int mDensity;
+ private int mDensity;
/** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
- DimLayer mAnimationBackgroundSurface;
+ private DimLayer mAnimationBackgroundSurface;
/** The particular window with an Animation with non-zero background color. */
- WindowStateAnimator mAnimationBackgroundAnimator;
+ private WindowStateAnimator mAnimationBackgroundAnimator;
/** Application tokens that are exiting, but still on screen for animations. */
final AppTokenList mExitingAppTokens = new AppTokenList();
@@ -354,11 +354,8 @@
// If the rotation or density didn't match, we'll update it in onConfigurationChanged.
}
- boolean onConfigurationChanged() {
- return updateBoundsAfterConfigChange();
- }
-
- private boolean updateBoundsAfterConfigChange() {
+ /** @return true if bounds were updated to some non-empty value. */
+ boolean updateBoundsAfterConfigChange() {
if (mDisplayContent == null) {
// If the stack is already detached we're not updating anything,
// as it's going away soon anyway.
@@ -459,7 +456,7 @@
// Snap the position to a target.
final int rotation = displayInfo.rotation;
- final int orientation = mService.mGlobalConfiguration.orientation;
+ final int orientation = mDisplayContent.getConfiguration().orientation;
mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
mService.mContext.getResources(), displayWidth, displayHeight,
@@ -609,12 +606,12 @@
}
}
- void attachDisplayContent(DisplayContent displayContent) {
+ void onDisplayChanged(DisplayContent dc) {
if (mDisplayContent != null) {
- throw new IllegalStateException("attachDisplayContent: Already attached");
+ throw new IllegalStateException("onDisplayChanged: Already attached");
}
- mDisplayContent = displayContent;
+ mDisplayContent = dc;
mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(),
"animation background stackId=" + mStackId);
@@ -628,7 +625,7 @@
// not fullscreen. If it's fullscreen, it means that we are in the transition of
// dismissing it, so we must not resize this stack.
bounds = new Rect();
- displayContent.getLogicalDisplayRect(mTmpRect);
+ dc.getLogicalDisplayRect(mTmpRect);
mTmpRect2.setEmpty();
if (dockedStack != null) {
dockedStack.getRawBounds(mTmpRect2);
@@ -641,6 +638,8 @@
}
updateDisplayInfo(bounds);
+
+ super.onDisplayChanged(dc);
}
void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) {
@@ -713,7 +712,7 @@
di.logicalWidth,
di.logicalHeight,
dockDividerWidth,
- mService.mGlobalConfiguration.orientation == ORIENTATION_PORTRAIT,
+ mDisplayContent.getConfiguration().orientation == ORIENTATION_PORTRAIT,
mTmpRect2).getMiddleTarget().position;
if (dockOnTopOrLeft) {
@@ -1182,7 +1181,7 @@
return DOCKED_INVALID;
}
mDisplayContent.getLogicalDisplayRect(mTmpRect);
- final int orientation = mService.mGlobalConfiguration.orientation;
+ final int orientation = mDisplayContent.getConfiguration().orientation;
return getDockSideUnchecked(bounds, mTmpRect, orientation);
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 58439eb..962325f 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -18,14 +18,10 @@
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -39,6 +35,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.ArraySet;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.WindowManager;
@@ -384,18 +381,6 @@
return mWallpaperAnimLayerAdjustment;
}
- void setAnimLayerAdjustment(WindowState win, int adj) {
- if (win != mWallpaperTarget || mLowerWallpaperTarget != null) {
- return;
- }
-
- if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Setting wallpaper layer adj to " + adj);
- mWallpaperAnimLayerAdjustment = adj;
- for (int i = mWallpaperTokens.size() - 1; i >= 0; i--) {
- mWallpaperTokens.get(i).adjustAnimLayer(adj);
- }
- }
-
private void findWallpaperTarget(WindowList windows, FindWallpaperTargetResult result) {
final WindowAnimator winAnimator = mService.mAnimator;
result.reset();
@@ -477,101 +462,111 @@
}
}
+ /** Updates the target wallpaper if needed and returns true if an update happened. */
private boolean updateWallpaperWindowsTarget(
WindowList windows, FindWallpaperTargetResult result) {
- boolean targetChanged = false;
WindowState wallpaperTarget = result.wallpaperTarget;
int wallpaperTargetIndex = result.wallpaperTargetIndex;
- if (mWallpaperTarget != wallpaperTarget
- && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != wallpaperTarget)) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget);
+ if (mWallpaperTarget == wallpaperTarget
+ || (mLowerWallpaperTarget != null && mLowerWallpaperTarget == wallpaperTarget)) {
- mLowerWallpaperTarget = null;
- mUpperWallpaperTarget = null;
-
- WindowState oldW = mWallpaperTarget;
- mWallpaperTarget = wallpaperTarget;
- targetChanged = true;
-
- // Now what is happening... if the current and new targets are animating,
- // then we are in our super special mode!
- if (wallpaperTarget != null && oldW != null) {
- boolean oldAnim = oldW.isAnimatingLw();
- boolean foundAnim = wallpaperTarget.isAnimatingLw();
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "New animation: " + foundAnim + " old animation: " + oldAnim);
- if (foundAnim && oldAnim) {
- int oldI = windows.indexOf(oldW);
+ if (mLowerWallpaperTarget != null) {
+ // Is it time to stop animating?
+ if (!mLowerWallpaperTarget.isAnimatingLw()
+ || !mUpperWallpaperTarget.isAnimatingLw()) {
if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "New i: " + wallpaperTargetIndex + " old i: " + oldI);
- if (oldI >= 0) {
- final boolean newTargetHidden =
- wallpaperTarget.mAppToken != null && wallpaperTarget.mAppToken.hiddenRequested;
- final boolean oldTargetHidden =
- oldW.mAppToken != null && oldW.mAppToken.hiddenRequested;
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:"
- + " old#" + oldI + "=" + oldW + " hidden=" + oldTargetHidden
- + " new#" + wallpaperTargetIndex + "=" + wallpaperTarget
- + " hidden=" + newTargetHidden);
-
- // Set the upper and lower wallpaper targets correctly,
- // and make sure that we are positioning the wallpaper below the lower.
- if (wallpaperTargetIndex > oldI) {
- // The new target is on top of the old one.
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "Found target above old target.");
- mUpperWallpaperTarget = wallpaperTarget;
- mLowerWallpaperTarget = oldW;
-
- wallpaperTarget = oldW;
- wallpaperTargetIndex = oldI;
- } else {
- // The new target is below the old one.
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "Found target below old target.");
- mUpperWallpaperTarget = oldW;
- mLowerWallpaperTarget = wallpaperTarget;
- }
- if (newTargetHidden && !oldTargetHidden) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
- "Old wallpaper still the target.");
- // Use the old target if new target is hidden but old target
- // is not. If they're both hidden, still use the new target.
- mWallpaperTarget = oldW;
- } else if (newTargetHidden == oldTargetHidden
- && !mService.mOpeningApps.contains(wallpaperTarget.mAppToken)
- && (mService.mOpeningApps.contains(oldW.mAppToken)
- || mService.mClosingApps.contains(oldW.mAppToken))) {
- // If they're both hidden (or both not hidden), prefer the one that's
- // currently in opening or closing app list, this allows transition
- // selection logic to better determine the wallpaper status of
- // opening/closing apps.
- mWallpaperTarget = oldW;
- }
- }
+ "No longer animating wallpaper targets!");
+ mLowerWallpaperTarget = null;
+ mUpperWallpaperTarget = null;
+ mWallpaperTarget = wallpaperTarget;
+ return true;
}
}
- } else if (mLowerWallpaperTarget != null) {
- // Is it time to stop animating?
- if (!mLowerWallpaperTarget.isAnimatingLw() || !mUpperWallpaperTarget.isAnimatingLw()) {
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!");
- mLowerWallpaperTarget = null;
- mUpperWallpaperTarget = null;
- mWallpaperTarget = wallpaperTarget;
- targetChanged = true;
- }
+ return false;
+ }
+
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget);
+
+ mLowerWallpaperTarget = null;
+ mUpperWallpaperTarget = null;
+
+ WindowState oldW = mWallpaperTarget;
+ mWallpaperTarget = wallpaperTarget;
+
+ if (wallpaperTarget == null || oldW == null) {
+ return true;
+ }
+
+ // Now what is happening... if the current and new targets are animating,
+ // then we are in our super special mode!
+ boolean oldAnim = oldW.isAnimatingLw();
+ boolean foundAnim = wallpaperTarget.isAnimatingLw();
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "New animation: " + foundAnim + " old animation: " + oldAnim);
+
+ if (!foundAnim || !oldAnim) {
+ return true;
+ }
+
+ int oldI = windows.indexOf(oldW);
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+ "New i: " + wallpaperTargetIndex + " old i: " + oldI);
+
+ if (oldI < 0) {
+ return true;
+ }
+
+ final boolean newTargetHidden = wallpaperTarget.mAppToken != null
+ && wallpaperTarget.mAppToken.hiddenRequested;
+ final boolean oldTargetHidden = oldW.mAppToken != null
+ && oldW.mAppToken.hiddenRequested;
+
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Animating wallpapers:" + " old#" + oldI + "="
+ + oldW + " hidden=" + oldTargetHidden + " new#" + wallpaperTargetIndex + "="
+ + wallpaperTarget + " hidden=" + newTargetHidden);
+
+ // Set the upper and lower wallpaper targets correctly,
+ // and make sure that we are positioning the wallpaper below the lower.
+ if (wallpaperTargetIndex > oldI) {
+ // The new target is on top of the old one.
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target above old target.");
+ mUpperWallpaperTarget = wallpaperTarget;
+ mLowerWallpaperTarget = oldW;
+
+ wallpaperTarget = oldW;
+ wallpaperTargetIndex = oldI;
+ } else {
+ // The new target is below the old one.
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Found target below old target.");
+ mUpperWallpaperTarget = oldW;
+ mLowerWallpaperTarget = wallpaperTarget;
+ }
+
+ if (newTargetHidden && !oldTargetHidden) {
+ if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Old wallpaper still the target.");
+ // Use the old target if new target is hidden but old target
+ // is not. If they're both hidden, still use the new target.
+ mWallpaperTarget = oldW;
+ } else if (newTargetHidden == oldTargetHidden
+ && !mService.mOpeningApps.contains(wallpaperTarget.mAppToken)
+ && (mService.mOpeningApps.contains(oldW.mAppToken)
+ || mService.mClosingApps.contains(oldW.mAppToken))) {
+ // If they're both hidden (or both not hidden), prefer the one that's currently in
+ // opening or closing app list, this allows transition selection logic to better
+ // determine the wallpaper status of opening/closing apps.
+ mWallpaperTarget = oldW;
}
result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
- return targetChanged;
+ return true;
}
- boolean updateWallpaperWindowsTargetByLayer(
- WindowList windows, FindWallpaperTargetResult result) {
+ private boolean updateWallpaperWindowsTargetByLayer(WindowList windows,
+ FindWallpaperTargetResult result) {
WindowState wallpaperTarget = result.wallpaperTarget;
int wallpaperTargetIndex = result.wallpaperTargetIndex;
@@ -621,7 +616,7 @@
return visible;
}
- boolean updateWallpaperWindowsPlacement(WindowList windows,
+ private boolean updateWallpaperWindowsPlacement(WindowList windows,
WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) {
// TODO(multidisplay): Wallpapers on main screen only.
@@ -734,6 +729,31 @@
return transitionReady;
}
+ /**
+ * Adjusts the wallpaper windows if the input display has a pending wallpaper layout or one of
+ * the opening apps should be a wallpaper target.
+ */
+ void adjustWallpaperWindowsForAppTransitionIfNeeded(
+ DisplayContent dc, ArraySet<AppWindowToken> openingApps, WindowList windows) {
+ boolean adjust = false;
+ if ((dc.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+ adjust = true;
+ } else {
+ for (int i = openingApps.size() - 1; i >= 0; --i) {
+ final AppWindowToken token = openingApps.valueAt(i);
+ if (token.windowsCanBeWallpaperTarget()) {
+ adjust = true;
+ break;
+ }
+ }
+ }
+
+ if (adjust && adjustWallpaperWindows()) {
+ mService.mLayersController.assignLayersLocked(windows);
+ dc.setLayoutNeeded();
+ }
+ }
+
void addWallpaperToken(WindowToken token) {
mWallpaperTokens.add(token);
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index af0fbd3..981b813 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import android.annotation.CallSuper;
+import android.content.res.Configuration;
import android.view.animation.Animation;
import java.util.Comparator;
@@ -34,13 +35,33 @@
*/
class WindowContainer<E extends WindowContainer> implements Comparable<WindowContainer> {
- // The parent of this window container.
- protected WindowContainer mParent = null;
+ /**
+ * The parent of this window container.
+ * For removing or setting new parent {@link #setParent} should be used, because it also
+ * performs configuration updates based on new parent's settings.
+ */
+ private WindowContainer mParent = null;
// List of children for this window container. List is in z-order as the children appear on
// screen with the top-most window container at the tail of the list.
protected final LinkedList<E> mChildren = new LinkedList();
+ /** Contains override configuration settings applied to this window container. */
+ private Configuration mOverrideConfiguration = new Configuration();
+
+ /**
+ * Contains full configuration applied to this window container. Corresponds to full parent's
+ * config with applied {@link #mOverrideConfiguration}.
+ */
+ private Configuration mFullConfiguration = new Configuration();
+
+ /**
+ * Contains merged override configuration settings from the top of the hierarchy down to this
+ * particular instance. It is different from {@link #mFullConfiguration} because it starts from
+ * topmost container's override config instead of global config.
+ */
+ private Configuration mMergedOverrideConfiguration = new Configuration();
+
// The specified orientation for this window container.
protected int mOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
@@ -48,6 +69,14 @@
return mParent;
}
+ final protected void setParent(WindowContainer parent) {
+ mParent = parent;
+ // Update full configuration of this container and all its children.
+ onConfigurationChanged(mParent != null ? mParent.mFullConfiguration : Configuration.EMPTY);
+ // Update merged override configuration of this container and all its children.
+ onMergedOverrideConfigurationChanged();
+ }
+
// Temp. holders for a chain of containers we are currently processing.
private final LinkedList<WindowContainer> mTmpChain1 = new LinkedList();
private final LinkedList<WindowContainer> mTmpChain2 = new LinkedList();
@@ -61,12 +90,12 @@
*/
@CallSuper
protected void addChild(E child, Comparator<E> comparator) {
- if (child.mParent != null) {
+ if (child.getParent() != null) {
throw new IllegalArgumentException("addChild: container=" + child.getName()
- + " is already a child of container=" + child.mParent.getName()
+ + " is already a child of container=" + child.getParent().getName()
+ " can't add to container=" + getName());
}
- child.mParent = this;
+ child.setParent(this);
if (mChildren.isEmpty() || comparator == null) {
mChildren.add(child);
@@ -87,12 +116,12 @@
/** Adds the input window container has a child of this container at the input index. */
@CallSuper
protected void addChild(E child, int index) {
- if (child.mParent != null) {
+ if (child.getParent() != null) {
throw new IllegalArgumentException("addChild: container=" + child.getName()
- + " is already a child of container=" + child.mParent.getName()
+ + " is already a child of container=" + child.getParent().getName()
+ " can't add to container=" + getName());
}
- child.mParent = this;
+ child.setParent(this);
mChildren.add(index, child);
}
@@ -104,7 +133,7 @@
@CallSuper
void removeChild(E child) {
if (mChildren.remove(child)) {
- child.mParent = null;
+ child.setParent(null);
} else {
throw new IllegalArgumentException("removeChild: container=" + child.getName()
+ " is not a child of container=" + getName());
@@ -158,6 +187,84 @@
return false;
}
+ /**
+ * Returns full configuration applied to this window container.
+ * This method should be used for getting settings applied in each particular level of the
+ * hierarchy.
+ */
+ Configuration getConfiguration() {
+ return mFullConfiguration;
+ }
+
+ /**
+ * Notify that parent config changed and we need to update full configuration.
+ * @see #mFullConfiguration
+ */
+ void onConfigurationChanged(Configuration newParentConfig) {
+ mFullConfiguration.setTo(newParentConfig);
+ mFullConfiguration.updateFrom(mOverrideConfiguration);
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ child.onConfigurationChanged(mFullConfiguration);
+ }
+ }
+
+ /** Returns override configuration applied to this window container. */
+ Configuration getOverrideConfiguration() {
+ return mOverrideConfiguration;
+ }
+
+ /**
+ * Update override configuration and recalculate full config.
+ * @see #mOverrideConfiguration
+ * @see #mFullConfiguration
+ */
+ void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
+ mOverrideConfiguration.setTo(overrideConfiguration);
+ // Update full configuration of this container and all its children.
+ onConfigurationChanged(mParent != null ? mParent.getConfiguration() : Configuration.EMPTY);
+ // Update merged override config of this container and all its children.
+ onMergedOverrideConfigurationChanged();
+ }
+
+ /**
+ * Get merged override configuration from the top of the hierarchy down to this
+ * particular instance. This should be reported to client as override config.
+ */
+ Configuration getMergedOverrideConfiguration() {
+ return mMergedOverrideConfiguration;
+ }
+
+ /**
+ * Update merged override configuration based on corresponding parent's config and notify all
+ * its children. If there is no parent, merged override configuration will set equal to current
+ * override config.
+ * @see #mMergedOverrideConfiguration
+ */
+ private void onMergedOverrideConfigurationChanged() {
+ if (mParent != null) {
+ mMergedOverrideConfiguration.setTo(mParent.getMergedOverrideConfiguration());
+ mMergedOverrideConfiguration.updateFrom(mOverrideConfiguration);
+ } else {
+ mMergedOverrideConfiguration.setTo(mOverrideConfiguration);
+ }
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ child.onMergedOverrideConfigurationChanged();
+ }
+ }
+
+ /**
+ * Notify that the display this container is on has changed.
+ * @param dc The new display this container is on.
+ */
+ void onDisplayChanged(DisplayContent dc) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ child.onDisplayChanged(dc);
+ }
+ }
+
void setWaitingForDrawnIfResizingChanged() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
@@ -285,19 +392,6 @@
}
}
- /**
- * Updates the current all drawn status for this container. That is all its children
- * that should draw something have done so.
- */
- // TODO: The displayId shouldn't be needed as there shouldn't be a container on more than one
- // display. Remove once we migrate DisplayContent to use WindowContainer.
- void updateAllDrawn(int displayId) {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowContainer wc = mChildren.get(i);
- wc.updateAllDrawn(displayId);
- }
- }
-
/** Step currently ongoing animation for App window containers. */
// TODO: The displayId shouldn't be needed as there shouldn't be a container on more than one
// display. Remove once we migrate DisplayContent to use WindowContainer.
@@ -389,16 +483,15 @@
/**
* Rebuilds the WindowList for the input display content.
- * @param dc The display content to rebuild the window list for.
* @param addIndex The index in the window list to add the next entry to.
* @return The next index in the window list to.
*/
// TODO: Hoping we can get rid of WindowList so this method wouldn't be needed.
- int rebuildWindowList(DisplayContent dc, int addIndex) {
+ int rebuildWindowList(int addIndex) {
final int count = mChildren.size();
for (int i = 0; i < count; i++) {
final WindowContainer wc = mChildren.get(i);
- addIndex = wc.rebuildWindowList(dc, addIndex);
+ addIndex = wc.rebuildWindowList(addIndex);
}
return addIndex;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 64d0df9..3ad43ce 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -163,9 +163,9 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
+import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
@@ -203,6 +203,7 @@
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.EventLogTags.WM_TASK_CREATED;
import static com.android.server.wm.AppTransition.TRANSIT_UNSET;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
@@ -213,7 +214,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
@@ -222,12 +222,10 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
@@ -404,11 +402,6 @@
final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>();
/**
- * Mapping from a token IBinder to a WindowToken object.
- */
- final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<>();
-
- /**
* List of window tokens that have finished starting their application,
* and now need to have the policy remove their windows.
*/
@@ -428,17 +421,6 @@
final ArrayList<AppWindowToken> mWindowReplacementTimeouts = new ArrayList<>();
/**
- * The input consumer added to the window manager which consumes input events to windows below
- * it.
- */
- InputConsumerImpl mInputConsumer;
-
- /**
- * The input consumer added to the window manager before all wallpaper windows.
- */
- InputConsumerImpl mWallpaperInputConsumer;
-
- /**
* Windows that are being resized. Used so we can tell the client about
* the resize after closing the transaction in which we resized the
* underlying surface.
@@ -592,12 +574,6 @@
// State while inside of layoutAndPlaceSurfacesLocked().
boolean mFocusMayChange;
- /**
- * Current global configuration information. Contains general settings for the entire system,
- * corresponds to the configuration of the default display.
- */
- Configuration mGlobalConfiguration = new Configuration();
-
// This is held as long as we have the screen frozen, to give us time to
// perform a rotation animation when turning off shows the lock screen which
// changes the orientation.
@@ -641,6 +617,12 @@
WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
SettingsObserver mSettingsObserver;
+ // A count of the windows which are 'seamlessly rotated', e.g. a surface
+ // at an old orientation is being transformed. We freeze orientation updates
+ // while any windows are seamlessly rotated, so we need to track when this
+ // hits zero so we can apply deferred orientation updates.
+ int mSeamlessRotationCount = 0;
+
private final class SettingsObserver extends ContentObserver {
private final Uri mDisplayInversionEnabledUri =
Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
@@ -913,7 +895,7 @@
@Override
public void onAppTransitionFinishedLocked(IBinder token) {
mH.sendEmptyMessage(H.NOTIFY_APP_TRANSITION_FINISHED);
- AppWindowToken atoken = findAppWindowToken(token);
+ final AppWindowToken atoken = mRoot.getAppWindowToken(token);
if (atoken == null) {
return;
}
@@ -1264,7 +1246,8 @@
// excercise to find the appropriate input method target (used for animations
// and dialog adjustments), but for purposes of Z ordering we simply wish to
// place it above the docked divider. Unless it is already above the divider.
- WindowState dockedDivider = w.mDisplayContent.mDividerControllerLocked.getWindow();
+ final WindowState dockedDivider =
+ w.getDisplayContent().mDividerControllerLocked.getWindow();
if (dockedDivider != null && dockedDivider.isVisibleLw()) {
int dividerIndex = windows.indexOf(dockedDivider);
if (dividerIndex > 0 && dividerIndex > i) {
@@ -1282,21 +1265,6 @@
return -1;
}
- void addInputMethodWindowToListLocked(WindowState win) {
- int pos = findDesiredInputMethodWindowIndexLocked(true);
- if (pos >= 0) {
- if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(
- TAG_WM, "Adding input method window " + win + " at " + pos);
- // TODO(multidisplay): IMEs are only supported on the default display.
- getDefaultWindowListLocked().add(pos, win);
- mWindowsChanged = true;
- moveInputMethodDialogsLocked(pos + 1);
- return;
- }
- win.mToken.addWindow(win);
- moveInputMethodDialogsLocked(pos);
- }
-
private void reAddWindowToListInOrderLocked(WindowState win) {
win.mToken.addWindow(win);
// This is a hack to get all of the child windows added as well at the right position. Child
@@ -1311,7 +1279,7 @@
}
}
- void logWindowList(final WindowList windows, String prefix) {
+ private void logWindowList(final WindowList windows, String prefix) {
int N = windows.size();
while (N > 0) {
N--;
@@ -1536,7 +1504,8 @@
final boolean hasParent = parentWindow != null;
// Use existing parent window token for child windows since they go in the same token
// as there parent window so we can apply the same policy on them.
- WindowToken token = mTokenMap.get(hasParent ? parentWindow.mAttrs.token : attrs.token);
+ WindowToken token = mRoot.getWindowToken(
+ hasParent ? parentWindow.mAttrs.token : attrs.token, displayContent);
// If this is a child window, we want to apply the same type checking rules as the
// parent window type.
final int rootType = hasParent ? parentWindow.mAttrs.type : type;
@@ -1588,7 +1557,7 @@
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
}
- token = new WindowToken(this, attrs.token, -1, false);
+ token = new WindowToken(this, attrs.token, -1, false, displayContent);
} else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
atoken = token.asAppWindowToken();
if (atoken == null) {
@@ -1656,11 +1625,11 @@
// It is not valid to use an app token with other system types; we will
// instead make a new token for it (as if null had been passed in for the token).
attrs.token = null;
- token = new WindowToken(this, null, -1, false);
+ token = new WindowToken(this, null, -1, false, displayContent);
}
WindowState win = new WindowState(this, session, client, token, parentWindow,
- appOp[0], seq, attrs, viewVisibility, displayContent, session.mUid);
+ appOp[0], seq, attrs, viewVisibility, session.mUid);
if (win.mDeathRecipient == null) {
// Client has apparently died, so there is no reason to
// continue.
@@ -1751,7 +1720,7 @@
if (type == TYPE_INPUT_METHOD) {
win.mGivenInsetsPending = true;
mInputMethodWindow = win;
- addInputMethodWindowToListLocked(win);
+ win.mToken.addImeWindow(win);
imMayMove = false;
} else if (type == TYPE_INPUT_METHOD_DIALOG) {
mInputMethodDialogs.add(win);
@@ -1985,7 +1954,7 @@
}
}
- public void removeWindow(Session session, IWindow client) {
+ void removeWindow(Session session, IWindow client) {
synchronized(mWindowMap) {
WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
@@ -2026,7 +1995,7 @@
// Window will already be removed from token before this post clean-up method is called.
if (token.isEmpty()) {
if (!token.explicit) {
- mTokenMap.remove(token.token);
+ token.removeImmediately();
} else if (atoken != null) {
// TODO: Should this be moved into AppWindowToken.removeWindow? Might go away after
// re-factor.
@@ -2674,7 +2643,8 @@
// is running.
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "WM#applyAnimationLocked");
if (okToDisplay()) {
- DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
+ final DisplayContent displayContent = atoken.mTask.getDisplayContent();
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final int width = displayInfo.appWidth;
final int height = displayInfo.appHeight;
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG_WM,
@@ -2711,10 +2681,10 @@
if (DEBUG_APP_TRANSITIONS) Slog.d(TAG_WM, "Loading animation for app transition."
+ " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter
+ " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
- Animation a = mAppTransition.loadAnimation(lp, transit, enter,
- mGlobalConfiguration.uiMode, mGlobalConfiguration.orientation, frame,
- displayFrame, insets, surfaceInsets, isVoiceInteraction, freeform,
- atoken.mTask.mTaskId);
+ final Configuration displayConfig = displayContent.getConfiguration();
+ Animation a = mAppTransition.loadAnimation(lp, transit, enter, displayConfig.uiMode,
+ displayConfig.orientation, frame, displayFrame, insets, surfaceInsets,
+ isVoiceInteraction, freeform, atoken.mTask.mTaskId);
if (a != null) {
if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + atoken);
final int containingWidth = frame.width();
@@ -2740,10 +2710,8 @@
== PackageManager.PERMISSION_GRANTED) {
return true;
}
- String msg = "Permission Denial: " + func + " from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid()
- + " requires " + permission;
+ final String msg = "Permission Denial: " + func + " from pid=" + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid() + " requires " + permission;
Slog.w(TAG_WM, msg);
return false;
}
@@ -2752,56 +2720,46 @@
return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn();
}
- AppWindowToken findAppWindowToken(IBinder token) {
- WindowToken wtoken = mTokenMap.get(token);
- if (wtoken == null) {
- return null;
- }
- return wtoken.asAppWindowToken();
- }
-
@Override
public void addWindowToken(IBinder token, int type) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "addWindowToken()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
- WindowToken wtoken = mTokenMap.get(token);
- if (wtoken != null) {
- Slog.w(TAG_WM, "Attempted to add existing input method token: " + token);
- return;
- }
- wtoken = new WindowToken(this, token, type, true);
- if (type == TYPE_WALLPAPER) {
- mWallpaperControllerLocked.addWallpaperToken(wtoken);
- }
+ mRoot.addWindowToken(token, type);
}
}
@Override
public void removeWindowToken(IBinder token) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "removeWindowToken()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
final long origId = Binder.clearCallingIdentity();
- synchronized(mWindowMap) {
- final WindowToken wtoken = mTokenMap.remove(token);
- if (wtoken != null) {
- wtoken.setExiting();
- if (wtoken.windowType == TYPE_WALLPAPER) {
- mWallpaperControllerLocked.removeWallpaperToken(wtoken);
+ try {
+ synchronized (mWindowMap) {
+ final ArrayList<WindowToken> removedTokens = mRoot.removeWindowToken(token);
+ if (removedTokens == null || removedTokens.isEmpty()) {
+ Slog.w(TAG_WM,
+ "removeWindowToken: Attempted to remove non-existing token: " + token);
+ return;
}
- mInputMonitor.updateInputWindowsLw(true /*force*/);
- } else {
- Slog.w(TAG_WM, "Attempted to remove non-existing token: " + token);
+ for (int i = removedTokens.size() - 1; i >= 0; --i) {
+ final WindowToken wtoken = removedTokens.get(i);
+ wtoken.setExiting();
+ if (wtoken.windowType == TYPE_WALLPAPER) {
+ mWallpaperControllerLocked.removeWallpaperToken(wtoken);
+ }
+
+ mInputMonitor.updateInputWindowsLw(true /*force*/);
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- Binder.restoreCallingIdentity(origId);
}
private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken,
@@ -2810,9 +2768,9 @@
+ " atoken=" + atoken + " bounds=" + bounds);
final TaskStack stack = mStackIdToStack.get(stackId);
if (stack == null) {
- throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
+ throw new IllegalArgumentException("createTaskLocked: invalid stackId=" + stackId);
}
- EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
+ EventLog.writeEvent(WM_TASK_CREATED, taskId, stackId);
Task task = new Task(taskId, stack, userId, this, bounds, overrideConfig, isOnTopLauncher);
mTaskIdToTask.put(taskId, task);
stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showForAllUsers);
@@ -2826,8 +2784,7 @@
Rect taskBounds, Configuration overrideConfig, int taskResizeMode,
boolean alwaysFocusable, boolean homeTask, int targetSdkVersion,
int rotationAnimationHint, boolean isOnTopLauncher) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "addAppToken()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "addAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -2846,12 +2803,18 @@
}
synchronized(mWindowMap) {
- AppWindowToken atoken = findAppWindowToken(token.asBinder());
+ AppWindowToken atoken = mRoot.getAppWindowToken(token.asBinder());
if (atoken != null) {
Slog.w(TAG_WM, "Attempted to add existing app token: " + token);
return;
}
- atoken = new AppWindowToken(this, token, voiceInteraction);
+
+ final TaskStack stack = mStackIdToStack.get(stackId);
+ if (stack == null) {
+ throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
+ }
+
+ atoken = new AppWindowToken(this, token, voiceInteraction, stack.getDisplayContent());
atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
atoken.setFillsParent(fullscreen);
atoken.showForAllUsers = showForAllUsers;
@@ -2882,13 +2845,12 @@
public void setAppTask(IBinder token, int taskId, int stackId, Rect taskBounds,
Configuration overrideConfig, int taskResizeMode, boolean homeTask,
boolean isOnTopLauncher) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppTask()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppTask()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
- final AppWindowToken atoken = findAppWindowToken(token);
+ final AppWindowToken atoken = mRoot.getAppWindowToken(token);
if (atoken == null) {
Slog.w(TAG_WM, "Attempted to set task id of non-existing app token: " + token);
return;
@@ -2980,8 +2942,7 @@
@Override
public Configuration updateOrientationFromAppTokens(
Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "updateOrientationFromAppTokens()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "updateOrientationFromAppTokens()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3005,12 +2966,10 @@
Configuration config = null;
if (updateOrientationFromAppTokensLocked(false)) {
- // If we changed the orientation but mOrientationChangeComplete is
- // already true, we used seamless rotation, and we don't need
- // to freeze the screen.
- if (freezeThisOneIfNeeded != null &&
- !mRoot.mOrientationChangeComplete) {
- final AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded);
+ // If we changed the orientation but mOrientationChangeComplete is already true,
+ // we used seamless rotation, and we don't need to freeze the screen.
+ if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
+ final AppWindowToken atoken = mRoot.getAppWindowToken(freezeThisOneIfNeeded);
if (atoken != null) {
atoken.startFreezingScreen();
}
@@ -3094,8 +3053,7 @@
@Override
public int[] setNewConfiguration(Configuration config) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setNewConfiguration()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setNewConfiguration()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3104,11 +3062,7 @@
mWaitingForConfig = false;
mLastFinishedFreezeSource = "new-config";
}
- final boolean configChanged = mGlobalConfiguration.diff(config) != 0;
- if (!configChanged) {
- return null;
- }
- return mRoot.onConfigurationChanged(config);
+ return mRoot.setGlobalConfigurationIfNeeded(config);
}
}
@@ -3124,13 +3078,12 @@
@Override
public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppOrientation()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppOrientation()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
- final AppWindowToken atoken = findAppWindowToken(token.asBinder());
+ final AppWindowToken atoken = mRoot.getAppWindowToken(token.asBinder());
if (atoken == null) {
Slog.w(TAG_WM, "Attempted to set orientation of non-existing app token: " + token);
return;
@@ -3143,9 +3096,9 @@
@Override
public int getAppOrientation(IApplicationToken token) {
synchronized(mWindowMap) {
- AppWindowToken wtoken = findAppWindowToken(token.asBinder());
+ final AppWindowToken wtoken = mRoot.getAppWindowToken(token.asBinder());
if (wtoken == null) {
- return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+ return SCREEN_ORIENTATION_UNSPECIFIED;
}
return wtoken.getOrientation();
@@ -3164,8 +3117,7 @@
@Override
public void setFocusedApp(IBinder token, boolean moveFocusNow) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setFocusedApp()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setFocusedApp()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3175,7 +3127,7 @@
if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Clearing focused app, was " + mFocusedApp);
newFocus = null;
} else {
- newFocus = findAppWindowToken(token);
+ newFocus = mRoot.getAppWindowToken(token);
if (newFocus == null) {
Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token);
}
@@ -3206,8 +3158,7 @@
*/
@Override
public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "prepareAppTransition()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "prepareAppTransition()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
@@ -3335,8 +3286,7 @@
@Override
public void executeAppTransition() {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "executeAppTransition()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "executeAppTransition()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3360,8 +3310,7 @@
int theme, CompatibilityInfo compatInfo,
CharSequence nonLocalizedLabel, int labelRes, int icon, int logo,
int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppStartingWindow()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppStartingWindow()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3370,7 +3319,7 @@
TAG_WM, "setAppStartingWindow: token=" + token + " pkg=" + pkg
+ " transferFrom=" + transferFrom);
- AppWindowToken wtoken = findAppWindowToken(token);
+ final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
if (wtoken == null) {
Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + token);
return false;
@@ -3432,7 +3381,7 @@
}
}
- if (wtoken != null && wtoken.transferStartingWindow(transferFrom)) {
+ if (wtoken.transferStartingWindow(transferFrom)) {
return true;
}
@@ -3457,14 +3406,14 @@
public void removeAppStartingWindow(IBinder token) {
synchronized (mWindowMap) {
- final AppWindowToken wtoken = mTokenMap.get(token).asAppWindowToken();
+ final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
scheduleRemoveStartingWindowLocked(wtoken);
}
}
public void setAppFullscreen(IBinder token, boolean toOpaque) {
synchronized (mWindowMap) {
- final AppWindowToken atoken = findAppWindowToken(token);
+ final AppWindowToken atoken = mRoot.getAppWindowToken(token);
if (atoken != null) {
atoken.setFillsParent(toOpaque);
setWindowOpaqueLocked(token, toOpaque);
@@ -3479,10 +3428,10 @@
}
}
- public void setWindowOpaqueLocked(IBinder token, boolean isOpaque) {
- AppWindowToken wtoken = findAppWindowToken(token);
+ private void setWindowOpaqueLocked(IBinder token, boolean isOpaque) {
+ final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
if (wtoken != null) {
- WindowState win = wtoken.findMainWindow();
+ final WindowState win = wtoken.findMainWindow();
if (win != null) {
win.mWinAnimator.setOpaqueLocked(isOpaque);
}
@@ -3500,14 +3449,12 @@
@Override
public void notifyAppResumed(IBinder token, boolean wasStopped, boolean allowSavedSurface) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "notifyAppResumed()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppResumed()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
- final AppWindowToken wtoken;
- wtoken = findAppWindowToken(token);
+ final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
if (wtoken == null) {
Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " + token);
return;
@@ -3518,14 +3465,13 @@
@Override
public void notifyAppStopped(IBinder token) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "notifyAppStopped()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "notifyAppStopped()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
final AppWindowToken wtoken;
- wtoken = findAppWindowToken(token);
+ wtoken = mRoot.getAppWindowToken(token);
if (wtoken == null) {
Slog.w(TAG_WM, "Attempted to notify stopped of non-existing app token: " + token);
return;
@@ -3536,15 +3482,14 @@
@Override
public void setAppVisibility(IBinder token, boolean visible) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppVisibility()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppVisibility()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
AppWindowToken wtoken;
synchronized(mWindowMap) {
- wtoken = findAppWindowToken(token);
+ wtoken = mRoot.getAppWindowToken(token);
if (wtoken == null) {
Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token);
return;
@@ -3654,8 +3599,7 @@
@Override
public void startAppFreezingScreen(IBinder token, int configChanges) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppFreezingScreen()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -3665,7 +3609,7 @@
return;
}
- final AppWindowToken wtoken = findAppWindowToken(token);
+ final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
if (wtoken == null || wtoken.appToken == null) {
Slog.w(TAG_WM, "Attempted to freeze screen with non-existing app token: " + wtoken);
return;
@@ -3678,19 +3622,18 @@
@Override
public void stopAppFreezingScreen(IBinder token, boolean force) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setAppFreezingScreen()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setAppFreezingScreen()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized(mWindowMap) {
- AppWindowToken wtoken = findAppWindowToken(token);
+ final AppWindowToken wtoken = mRoot.getAppWindowToken(token);
if (wtoken == null || wtoken.appToken == null) {
return;
}
final long origId = Binder.clearCallingIdentity();
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + token
- + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Clear freezing of " + token + ": hidden="
+ + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
wtoken.stopFreezingScreen(true, force);
Binder.restoreCallingIdentity(origId);
}
@@ -3698,76 +3641,18 @@
@Override
public void removeAppToken(IBinder token) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "removeAppToken()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeAppToken()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
- AppWindowToken wtoken = null;
- AppWindowToken startingToken = null;
- boolean delayed = false;
-
final long origId = Binder.clearCallingIdentity();
- synchronized(mWindowMap) {
- WindowToken basewtoken = mTokenMap.remove(token);
- if (basewtoken != null && (wtoken = basewtoken.asAppWindowToken()) != null) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Removing app token: " + wtoken);
- delayed = wtoken.setVisibility(null, false,
- TRANSIT_UNSET, true, wtoken.voiceInteraction);
- mOpeningApps.remove(wtoken);
- wtoken.waitingToShow = false;
- if (mClosingApps.contains(wtoken)) {
- delayed = true;
- } else if (mAppTransition.isTransitionSet()) {
- mClosingApps.add(wtoken);
- delayed = true;
- }
- if (DEBUG_APP_TRANSITIONS) Slog.v(
- TAG_WM, "Removing app " + wtoken + " delayed=" + delayed
- + " animation=" + wtoken.mAppAnimator.animation
- + " animating=" + wtoken.mAppAnimator.animating);
- if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM, "removeAppToken: "
- + wtoken + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
- final TaskStack stack = wtoken.mTask.mStack;
- if (delayed && !wtoken.isEmpty()) {
- // set the token aside because it has an active animation to be finished
- if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG_WM,
- "removeAppToken make exiting: " + wtoken);
- stack.mExitingAppTokens.add(wtoken);
- wtoken.mIsExiting = true;
- } else {
- // Make sure there is no animation running on this token,
- // so any windows associated with it will be removed as
- // soon as their animations are complete
- wtoken.mAppAnimator.clearAnimation();
- wtoken.mAppAnimator.animating = false;
- wtoken.removeIfPossible();
- }
-
- wtoken.removed = true;
- if (wtoken.startingData != null) {
- startingToken = wtoken;
- }
- wtoken.stopFreezingScreen(true, true);
- if (mFocusedApp == wtoken) {
- if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "Removing focused app token:" + wtoken);
- mFocusedApp = null;
- updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
- mInputMonitor.setFocusedAppLw(null);
- }
- } else {
- Slog.w(TAG_WM, "Attempted to remove non-existing app token: " + token);
+ try {
+ synchronized(mWindowMap) {
+ mRoot.removeAppToken(token);
}
-
- if (!delayed && wtoken != null) {
- wtoken.updateReportedVisibilityLocked();
- }
-
- // Will only remove if startingToken non null.
- scheduleRemoveStartingWindowLocked(startingToken);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- Binder.restoreCallingIdentity(origId);
-
}
void scheduleRemoveStartingWindowLocked(AppWindowToken wtoken) {
@@ -4063,7 +3948,7 @@
}
public void positionTaskInStack(int taskId, int stackId, int position, Rect bounds,
- Configuration config) {
+ Configuration overrideConfig) {
synchronized (mWindowMap) {
if (DEBUG_STACK) Slog.i(TAG_WM, "positionTaskInStack: positioning taskId=" + taskId
+ " in stackId=" + stackId + " at " + position);
@@ -4079,7 +3964,7 @@
"positionTaskInStack: could not find stackId=" + stackId);
return;
}
- task.positionTaskInStack(stack, position, bounds, config);
+ task.positionTaskInStack(stack, position, bounds, overrideConfig);
final DisplayContent displayContent = stack.getDisplayContent();
displayContent.setLayoutNeeded();
mWindowPlacerLocked.performSurfacePlacement();
@@ -5450,25 +5335,30 @@
}
}
- public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
- if(DEBUG_ORIENTATION) Slog.v(TAG_WM, "updateRotationUnchecked("
- + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")");
+ private void updateRotationUnchecked(boolean alwaysSendConfiguration,
+ boolean forceRelayout) {
+ if(DEBUG_ORIENTATION) Slog.v(TAG_WM, "updateRotationUnchecked:"
+ + " alwaysSendConfiguration=" + alwaysSendConfiguration
+ + " forceRelayout=" + forceRelayout);
long origId = Binder.clearCallingIdentity();
- boolean changed;
- synchronized(mWindowMap) {
- changed = updateRotationUncheckedLocked(false);
- if (!changed || forceRelayout) {
- getDefaultDisplayContentLocked().setLayoutNeeded();
- mWindowPlacerLocked.performSurfacePlacement();
+
+ try {
+ final boolean rotationChanged;
+ synchronized (mWindowMap) {
+ rotationChanged = updateRotationUncheckedLocked(false);
+ if (!rotationChanged || forceRelayout) {
+ getDefaultDisplayContentLocked().setLayoutNeeded();
+ mWindowPlacerLocked.performSurfacePlacement();
+ }
}
- }
- if (changed || alwaysSendConfiguration) {
- sendNewConfiguration();
+ if (rotationChanged || alwaysSendConfiguration) {
+ sendNewConfiguration();
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
-
- Binder.restoreCallingIdentity(origId);
}
@@ -5479,7 +5369,7 @@
* Returns true if the rotation has been changed. In this case YOU
* MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN.
*/
- public boolean updateRotationUncheckedLocked(boolean inTransaction) {
+ boolean updateRotationUncheckedLocked(boolean inTransaction) {
if (mDeferredRotationPauseCount > 0) {
// Rotation updates have been paused temporarily. Defer the update until
// updates have been resumed.
@@ -5496,6 +5386,13 @@
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
return false;
}
+ if (mDisplayFrozen) {
+ // Even if the screen rotation animation has finished (e.g. isAnimating
+ // returns false), there is still some time where we haven't yet unfrozen
+ // the display. We also need to abort rotation here.
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, still finishing previous rotation");
+ return false;
+ }
if (!mDisplayEnabled) {
// No point choosing a rotation if the display is not enabled.
@@ -5503,12 +5400,44 @@
return false;
}
+ final DisplayContent displayContent = getDefaultDisplayContentLocked();
+ final WindowList windows = displayContent.getWindowList();
+
+ final int oldRotation = mRotation;
+ int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
+ boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, rotation);
+
+ if (rotateSeamlessly) {
+ for (int i = windows.size() - 1; i >= 0; i--) {
+ WindowState w = windows.get(i);
+ // We can't rotate (seamlessly or not) while waiting for the last seamless rotation
+ // to complete (that is, waiting for windows to redraw). It's tempting to check
+ // w.mSeamlessRotationCount but that could be incorrect in the case of window-removal.
+ if (w.mSeamlesslyRotated) {
+ return false;
+ }
+ // In what can only be called an unfortunate workaround we require
+ // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
+ // flag. Due to limitations in the client API, there is no way for
+ // the client to set this flag in a race free fashion. If we seamlessly rotate
+ // a window which does not have this flag, but then gains it, we will get
+ // an incorrect visual result (rotated viewfinder). This means if we want to
+ // support seamlessly rotating windows which could gain this flag, we can't
+ // rotate windows without it. This limits seamless rotation in N to camera framework
+ // users, windows without children, and native code. This is unfortunate but
+ // having the camera work is our primary goal.
+ if (w.isChildWindow() & w.isVisibleNow() &&
+ !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
+ rotateSeamlessly = false;
+ }
+ }
+ }
+
// TODO: Implement forced rotation changes.
// Set mAltOrientation to indicate that the application is receiving
// an orientation that has different metrics than it expected.
// eg. Portrait instead of Landscape.
- int rotation = mPolicy.rotationForOrientationLw(mLastOrientation, mRotation);
boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
mLastOrientation, rotation);
@@ -5531,8 +5460,6 @@
+ ", lastOrientation=" + mLastOrientation);
}
- int oldRotation = mRotation;
-
mRotation = rotation;
mAltOrientation = altOrientation;
mPolicy.setRotationLw(mRotation);
@@ -5541,7 +5468,6 @@
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
mWaitingForConfig = true;
- final DisplayContent displayContent = getDefaultDisplayContentLocked();
displayContent.setLayoutNeeded();
final int[] anim = new int[2];
if (displayContent.isDimming()) {
@@ -5549,33 +5475,6 @@
} else {
mPolicy.selectRotationAnimationLw(anim);
}
- boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, mRotation);
- final WindowList windows = displayContent.getWindowList();
- // We can't rotate seamlessly while an existing seamless rotation is still
- // waiting on windows to finish drawing.
- if (rotateSeamlessly) {
- for (int i = windows.size() - 1; i >= 0; i--) {
- WindowState w = windows.get(i);
- if (w.mSeamlesslyRotated) {
- rotateSeamlessly = false;
- break;
- }
- // In what can only be called an unfortunate workaround we require
- // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
- // flag. Due to limitations in the client API, there is no way for
- // the client to set this flag in a race free fashion. If we seamlessly rotate
- // a window which does not have this flag, but then gains it, we will get
- // an incorrect visual result (rotated viewfinder). This means if we want to
- // support seamlessly rotating windows which could gain this flag, we can't
- // rotate windows without it. This limits seamless rotation in N to camera framework
- // users, windows without children, and native code. This is unfortunate but
- // having the camera work is our primary goal.
- if (w.isChildWindow() & w.isVisibleNow() &&
- !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
- rotateSeamlessly = false;
- }
- }
- }
if (!rotateSeamlessly) {
startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
@@ -5588,6 +5487,10 @@
// When we are rotating seamlessly, we allow the elements to transition
// to their rotated state independently and without a freeze required.
screenRotationAnimation = null;
+
+ // We have to reset this in case a window was removed before it
+ // finished seamless rotation.
+ mSeamlessRotationCount = 0;
}
// We need to update our screen size information to match the new rotation. If the rotation
@@ -5595,7 +5498,7 @@
// the top of the method, the caller is obligated to call computeNewConfigurationLocked().
// By updating the Display info here it will be available to
// computeScreenConfigurationLocked later.
- updateDisplayAndOrientationLocked(mGlobalConfiguration.uiMode);
+ updateDisplayAndOrientationLocked(mRoot.getConfiguration().uiMode);
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
if (!inTransaction) {
@@ -6130,10 +6033,25 @@
/**
* Instruct the Activity Manager to fetch new configurations, update global configuration
* and broadcast changes to config-changed listeners if appropriate.
+ * NOTE: Can't be called with the window manager lock held since it call into activity manager.
*/
void sendNewConfiguration() {
try {
- mActivityManager.updateConfiguration(null);
+ final boolean configUpdated = mActivityManager.updateConfiguration(null);
+ if (!configUpdated) {
+ // Something changed (E.g. device rotation), but no configuration update is needed.
+ // E.g. changing device rotation by 180 degrees. Go ahead and perform surface
+ // placement to unfreeze the display since we froze it when the rotation was updated
+ // in updateRotationUncheckedLocked.
+ synchronized (mWindowMap) {
+ if (mWaitingForConfig) {
+ mWaitingForConfig = false;
+ mLastFinishedFreezeSource = "config-unchanged";
+ getDefaultDisplayContentLocked().setLayoutNeeded();
+ mWindowPlacerLocked.performSurfacePlacement();
+ }
+ }
+ }
} catch (RemoteException e) {
}
}
@@ -6601,38 +6519,39 @@
@Override
public void pauseKeyDispatching(IBinder _token) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "pauseKeyDispatching()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "pauseKeyDispatching()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized (mWindowMap) {
- WindowToken token = mTokenMap.get(_token);
- if (token != null) {
- mInputMonitor.pauseDispatchingLw(token);
+ final ArrayList<WindowToken> tokens = mRoot.getWindowTokens(_token);
+ if (tokens != null && !tokens.isEmpty()) {
+ for (int i = tokens.size() - 1; i >= 0; --i) {
+ mInputMonitor.pauseDispatchingLw(tokens.get(i));
+ }
}
}
}
@Override
public void resumeKeyDispatching(IBinder _token) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "resumeKeyDispatching()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "resumeKeyDispatching()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
synchronized (mWindowMap) {
- WindowToken token = mTokenMap.get(_token);
- if (token != null) {
- mInputMonitor.resumeDispatchingLw(token);
+ final ArrayList<WindowToken> tokens = mRoot.getWindowTokens(_token);
+ if (tokens != null && !tokens.isEmpty()) {
+ for (int i = tokens.size() - 1; i >= 0; --i) {
+ mInputMonitor.resumeDispatchingLw(tokens.get(i));
+ }
}
}
}
@Override
public void setEventDispatching(boolean enabled) {
- if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
- "setEventDispatching()")) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "setEventDispatching()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
@@ -6961,8 +6880,8 @@
View view = null;
try {
- final Configuration overrideConfig = wtoken != null && wtoken.mTask != null
- ? wtoken.mTask.mOverrideConfig : null;
+ final Configuration overrideConfig =
+ wtoken != null ? wtoken.getMergedOverrideConfiguration() : null;
view = mPolicy.addStartingWindow(wtoken.token, sd.pkg, sd.theme,
sd.compatInfo, sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo,
sd.windowFlags, overrideConfig);
@@ -7516,8 +7435,8 @@
if (w.mSeamlesslyRotated) {
layoutNeeded = true;
w.setDisplayLayoutNeeded();
+ markForSeamlessRotation(w, false);
}
- w.mSeamlesslyRotated = false;
}
if (layoutNeeded) {
mWindowPlacerLocked.performSurfacePlacement();
@@ -7911,9 +7830,10 @@
displayContent.setLayoutNeeded();
boolean configChanged = updateOrientationFromAppTokensLocked(false);
- mTempConfiguration.setTo(mGlobalConfiguration);
+ final Configuration globalConfig = mRoot.getConfiguration();
+ mTempConfiguration.setTo(globalConfig);
computeScreenConfigurationLocked(mTempConfiguration);
- configChanged |= mGlobalConfiguration.diff(mTempConfiguration) != 0;
+ configChanged |= globalConfig.diff(mTempConfiguration) != 0;
if (configChanged) {
mWaitingForConfig = true;
@@ -8056,108 +7976,6 @@
return changes;
}
- void updateResizingWindows(final WindowState w) {
- final WindowStateAnimator winAnimator = w.mWinAnimator;
- if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq && !w.isGoneForLayoutLw()) {
- final Task task = w.getTask();
- // In the case of stack bound animations, the window frames will update (unlike other
- // animations which just modify various transformation properties). We don't want to
- // notify the client of frame changes in this case. Not only is it a lot of churn, but
- // the frame may not correspond to the surface size or the onscreen area at various
- // phases in the animation, and the client will become sad and confused.
- if (task != null && task.mStack.getBoundsAnimating()) {
- return;
- }
- w.setReportResizeHints();
- boolean configChanged = w.isConfigChanged();
- if (DEBUG_CONFIGURATION && configChanged) {
- Slog.v(TAG_WM, "Win " + w + " config changed: " + mGlobalConfiguration);
- }
- final boolean dragResizingChanged = w.isDragResizeChanged()
- && !w.isDragResizingChangeReported();
-
- if (localLOGV) Slog.v(TAG_WM, "Resizing " + w + ": configChanged=" + configChanged
- + " dragResizingChanged=" + dragResizingChanged + " last=" + w.mLastFrame
- + " frame=" + w.mFrame);
-
- // We update mLastFrame always rather than in the conditional with the
- // last inset variables, because mFrameSizeChanged only tracks the
- // width and height changing.
- w.mLastFrame.set(w.mFrame);
-
- if (w.mContentInsetsChanged
- || w.mVisibleInsetsChanged
- || winAnimator.mSurfaceResized
- || w.mOutsetsChanged
- || w.mFrameSizeChanged
- || configChanged
- || dragResizingChanged
- || !w.isResizedWhileNotDragResizingReported()) {
- if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
- Slog.v(TAG_WM, "Resize reasons for w=" + w + ": "
- + " contentInsetsChanged=" + w.mContentInsetsChanged
- + " " + w.mContentInsets.toShortString()
- + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
- + " " + w.mVisibleInsets.toShortString()
- + " stableInsetsChanged=" + w.mStableInsetsChanged
- + " " + w.mStableInsets.toShortString()
- + " outsetsChanged=" + w.mOutsetsChanged
- + " " + w.mOutsets.toShortString()
- + " surfaceResized=" + winAnimator.mSurfaceResized
- + " configChanged=" + configChanged
- + " dragResizingChanged=" + dragResizingChanged
- + " resizedWhileNotDragResizingReported="
- + w.isResizedWhileNotDragResizingReported());
- }
-
- // If it's a dead window left on screen, and the configuration changed,
- // there is nothing we can do about it. Remove the window now.
- if (w.mAppToken != null && w.mAppDied) {
- w.mAppToken.removeDeadWindows();
- return;
- }
-
- w.mLastOverscanInsets.set(w.mOverscanInsets);
- w.mLastContentInsets.set(w.mContentInsets);
- w.mLastVisibleInsets.set(w.mVisibleInsets);
- w.mLastStableInsets.set(w.mStableInsets);
- w.mLastOutsets.set(w.mOutsets);
- makeWindowFreezingScreenIfNeededLocked(w);
- // If the orientation is changing, or we're starting or ending
- // a drag resizing action, then we need to hold off on unfreezing
- // the display until this window has been redrawn; to do that,
- // we need to go through the process of getting informed by the
- // application when it has finished drawing.
- if (w.mOrientationChanging || dragResizingChanged
- || w.isResizedWhileNotDragResizing()) {
- if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) {
- Slog.v(TAG_WM, "Orientation or resize start waiting for draw"
- + ", mDrawState=DRAW_PENDING in " + w
- + ", surfaceController " + winAnimator.mSurfaceController);
- }
- winAnimator.mDrawState = DRAW_PENDING;
- if (w.mAppToken != null) {
- w.mAppToken.clearAllDrawn();
- }
- }
- if (!mResizingWindows.contains(w)) {
- if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG_WM,
- "Resizing window " + w);
- mResizingWindows.add(w);
- }
- } else if (w.mOrientationChanging) {
- if (w.isDrawnLw()) {
- if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
- "Orientation not waiting for draw in "
- + w + ", surfaceController " + winAnimator.mSurfaceController);
- w.mOrientationChanging = false;
- w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
- - mDisplayFreezeTime);
- }
- }
- }
- }
-
void checkDrawnWindowsLocked() {
if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
return;
@@ -8207,10 +8025,10 @@
} else {
if (DEBUG_KEEP_SCREEN_ON) {
Slog.d(TAG_KEEP_SCREEN_ON, "Releasing screen wakelock, obscured by "
- + mRoot.mObsuringWindow);
+ + mRoot.mObscuringWindow);
}
mLastWakeLockHoldingWindow = null;
- mLastWakeLockObscuringWindow = mRoot.mObsuringWindow;
+ mLastWakeLockObscuringWindow = mRoot.mObscuringWindow;
mPolicy.keepScreenOnStoppedLw();
mHoldingScreenWakeLock.release();
}
@@ -8624,68 +8442,25 @@
}
}
- private static final class HideNavInputConsumer extends InputConsumerImpl
- implements WindowManagerPolicy.InputConsumer {
- private final InputEventReceiver mInputEventReceiver;
-
- HideNavInputConsumer(WindowManagerService service, Looper looper,
- InputEventReceiver.Factory inputEventReceiverFactory) {
- super(service, "input consumer", null);
- mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
- mClientChannel, looper);
- }
-
- @Override
- public void dismiss() {
- if (mService.removeInputConsumer()) {
- synchronized (mService.mWindowMap) {
- mInputEventReceiver.dispose();
- disposeChannelsLw();
- }
- }
- }
- }
-
@Override
- public WindowManagerPolicy.InputConsumer addInputConsumer(Looper looper,
+ public WindowManagerPolicy.InputConsumer createInputConsumer(Looper looper, String name,
InputEventReceiver.Factory inputEventReceiverFactory) {
synchronized (mWindowMap) {
- HideNavInputConsumer inputConsumerImpl = new HideNavInputConsumer(
- this, looper, inputEventReceiverFactory);
- mInputConsumer = inputConsumerImpl;
- mInputMonitor.updateInputWindowsLw(true);
- return inputConsumerImpl;
- }
- }
-
- boolean removeInputConsumer() {
- synchronized (mWindowMap) {
- if (mInputConsumer != null) {
- mInputConsumer = null;
- mInputMonitor.updateInputWindowsLw(true);
- return true;
- }
- return false;
+ return mInputMonitor.createInputConsumer(looper, name, inputEventReceiverFactory);
}
}
@Override
- public void createWallpaperInputConsumer(InputChannel inputChannel) {
+ public void createInputConsumer(String name, InputChannel inputChannel) {
synchronized (mWindowMap) {
- mWallpaperInputConsumer = new InputConsumerImpl(this, "wallpaper input", inputChannel);
- mWallpaperInputConsumer.mWindowHandle.hasWallpaper = true;
- mInputMonitor.updateInputWindowsLw(true);
+ mInputMonitor.createInputConsumer(name, inputChannel);
}
}
@Override
- public void removeWallpaperInputConsumer() {
+ public boolean destroyInputConsumer(String name) {
synchronized (mWindowMap) {
- if (mWallpaperInputConsumer != null) {
- mWallpaperInputConsumer.disposeChannelsLw();
- mWallpaperInputConsumer = null;
- mInputMonitor.updateInputWindowsLw(true);
- }
+ return mInputMonitor.destroyInputConsumer(name);
}
}
@@ -8755,7 +8530,7 @@
public void notifyAppRelaunching(IBinder token) {
synchronized (mWindowMap) {
- AppWindowToken appWindow = findAppWindowToken(token);
+ final AppWindowToken appWindow = mRoot.getAppWindowToken(token);
if (appWindow != null) {
appWindow.startRelaunching();
}
@@ -8764,7 +8539,7 @@
public void notifyAppRelaunchingFinished(IBinder token) {
synchronized (mWindowMap) {
- AppWindowToken appWindow = findAppWindowToken(token);
+ final AppWindowToken appWindow = mRoot.getAppWindowToken(token);
if (appWindow != null) {
appWindow.finishRelaunching();
}
@@ -8773,7 +8548,7 @@
public void notifyAppRelaunchesCleared(IBinder token) {
synchronized (mWindowMap) {
- final AppWindowToken appWindow = findAppWindowToken(token);
+ final AppWindowToken appWindow = mRoot.getAppWindowToken(token);
if (appWindow != null) {
appWindow.clearRelaunching();
}
@@ -8785,32 +8560,19 @@
return getDefaultDisplayContentLocked().getDockedDividerController().getContentInsets();
}
- void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
+ private void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
mPolicy.dump(" ", pw, args);
}
- void dumpAnimatorLocked(PrintWriter pw, String[] args, boolean dumpAll) {
+ private void dumpAnimatorLocked(PrintWriter pw, String[] args, boolean dumpAll) {
pw.println("WINDOW MANAGER ANIMATOR STATE (dumpsys window animator)");
mAnimator.dumpLocked(pw, " ", dumpAll);
}
- void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
+ private void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
- if (!mTokenMap.isEmpty()) {
- pw.println(" All tokens:");
- Iterator<WindowToken> it = mTokenMap.values().iterator();
- while (it.hasNext()) {
- WindowToken token = it.next();
- pw.print(" "); pw.print(token);
- if (dumpAll) {
- pw.println(':');
- token.dump(pw, " ");
- } else {
- pw.println();
- }
- }
- }
+ mRoot.dumpTokens(pw, dumpAll);
mWallpaperControllerLocked.dumpTokens(pw, " ", dumpAll);
if (!mFinishedStarting.isEmpty()) {
pw.println();
@@ -8838,7 +8600,7 @@
}
}
- void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
+ private void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
for (int i=0; i<mSessions.size(); i++) {
Session s = mSessions.valueAt(i);
@@ -8847,13 +8609,13 @@
}
}
- void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
+ private void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
ArrayList<WindowState> windows) {
pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
}
- void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
+ private void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
ArrayList<WindowState> windows) {
mRoot.dumpWindowsNoHeader(pw, dumpAll, windows);
@@ -8959,7 +8721,7 @@
}
}
pw.println();
- pw.print(" mGlobalConfiguration="); pw.println(mGlobalConfiguration);
+ pw.print(" mGlobalConfiguration="); pw.println(mRoot.getConfiguration());
pw.print(" mHasPermanentDpad="); pw.println(mHasPermanentDpad);
pw.print(" mCurrentFocus="); pw.println(mCurrentFocus);
if (mLastFocus != mCurrentFocus) {
@@ -9342,7 +9104,7 @@
*/
public void setWillReplaceWindow(IBinder token, boolean animate) {
synchronized (mWindowMap) {
- final AppWindowToken appWindowToken = findAppWindowToken(token);
+ final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token);
if (appWindowToken == null || !appWindowToken.hasContentToDisplay()) {
Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+ token);
@@ -9364,9 +9126,9 @@
*/
// TODO: The s at the end of the method name is the only difference with the name of the method
// above. We should combine them or find better names.
- public void setWillReplaceWindows(IBinder token, boolean childrenOnly) {
+ void setWillReplaceWindows(IBinder token, boolean childrenOnly) {
synchronized (mWindowMap) {
- final AppWindowToken appWindowToken = findAppWindowToken(token);
+ final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token);
if (appWindowToken == null || !appWindowToken.hasContentToDisplay()) {
Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+ token);
@@ -9394,7 +9156,7 @@
*/
public void scheduleClearWillReplaceWindows(IBinder token, boolean replacing) {
synchronized (mWindowMap) {
- final AppWindowToken appWindowToken = findAppWindowToken(token);
+ final AppWindowToken appWindowToken = mRoot.getAppWindowToken(token);
if (appWindowToken == null) {
Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token "
+ token);
@@ -9574,6 +9336,7 @@
*/
public int getSmallestWidthForTaskBounds(Rect bounds) {
synchronized (mWindowMap) {
+ // TODO(multi-display): Use correct display content here
return getDefaultDisplayContentLocked().getDockedDividerController()
.getSmallestWidthDpForBounds(bounds);
}
@@ -9676,6 +9439,26 @@
mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver);
}
+ void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) {
+ if (seamlesslyRotated == w.mSeamlesslyRotated) {
+ return;
+ }
+ w.mSeamlesslyRotated = seamlesslyRotated;
+ if (seamlesslyRotated) {
+ mSeamlessRotationCount++;
+ } else {
+ mSeamlessRotationCount--;
+ }
+ if (mSeamlessRotationCount == 0) {
+ if (DEBUG_ORIENTATION) {
+ Slog.i(TAG, "Performing post-rotate rotation after seamless rotation");
+ }
+ if (updateRotationUncheckedLocked(false)) {
+ mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
+ }
+ }
+ }
+
private final class LocalService extends WindowManagerInternal {
@Override
public void requestTraversalFromDisplayManager() {
@@ -9839,9 +9622,12 @@
public void removeWindowToken(IBinder token, boolean removeWindows) {
synchronized(mWindowMap) {
if (removeWindows) {
- final WindowToken wtoken = mTokenMap.remove(token);
- if (wtoken != null) {
- wtoken.removeAllWindows();
+ final ArrayList<WindowToken> removedTokens = mRoot.removeWindowToken(token);
+ if (removedTokens != null && !removedTokens.isEmpty()) {
+ for (int i = removedTokens.size() - 1; i >= 0; --i) {
+ final WindowToken wtoken = removedTokens.get(i);
+ wtoken.removeAllWindows();
+ }
}
}
WindowManagerService.this.removeWindowToken(token);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index cb3f2d0..a13c4d0 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -71,6 +71,7 @@
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
@@ -87,6 +88,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
@@ -131,6 +133,7 @@
import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
import static com.android.server.wm.WindowManagerService.localLOGV;
import static com.android.server.wm.WindowStateAnimator.COMMIT_DRAW_PENDING;
+import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
@@ -155,7 +158,7 @@
// to capture touch events in that area.
static final int RESIZE_HANDLE_WIDTH_IN_DP = 30;
- static final boolean DEBUG_DISABLE_SAVING_SURFACES = false;
+ private static final boolean DEBUG_DISABLE_SAVING_SURFACES = false;
final WindowManagerService mService;
final WindowManagerPolicy mPolicy;
@@ -180,7 +183,7 @@
final boolean mLayoutAttached;
final boolean mIsImWindow;
final boolean mIsWallpaper;
- final boolean mIsFloatingLayer;
+ private final boolean mIsFloatingLayer;
int mSeq;
boolean mEnforceSizeCompat;
int mViewVisibility;
@@ -197,16 +200,16 @@
* animation is done.
*/
boolean mPolicyVisibilityAfterAnim = true;
- boolean mAppOpVisibility = true;
+ private boolean mAppOpVisibility = true;
boolean mPermanentlyHidden; // the window should never be shown again
boolean mAppFreezing;
boolean mHidden; // Used to determine if to show child windows.
boolean mWallpaperVisible; // for wallpaper, what was last vis report?
- boolean mDragResizing;
- boolean mDragResizingChangeReported;
- int mResizeMode;
+ private boolean mDragResizing;
+ private boolean mDragResizingChangeReported;
+ private int mResizeMode;
- RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
+ private RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
/**
* The window size that was requested by the application. These are in
@@ -214,8 +217,8 @@
*/
int mRequestedWidth;
int mRequestedHeight;
- int mLastRequestedWidth;
- int mLastRequestedHeight;
+ private int mLastRequestedWidth;
+ private int mLastRequestedHeight;
int mLayer;
boolean mHaveFrame;
@@ -224,14 +227,12 @@
int mLayoutSeq = -1;
- private final Configuration mTmpConfig = new Configuration();
- // Represents the changes from our override configuration applied
- // to the global configuration. This is the only form of configuration
- // which is suitable for delivery to the client.
- private Configuration mMergedConfiguration = new Configuration();
- // Sticky answer to isConfigChanged(), remains true until new Configuration is assigned.
- // Used only on {@link #TYPE_KEYGUARD}.
- private boolean mConfigHasChanged;
+ /**
+ * Used to store last reported to client configuration and check if we have newer available.
+ * We'll send configuration to client only if it is different from the last applied one and
+ * client won't perform unnecessary updates.
+ */
+ private final Configuration mLastReportedConfiguration = new Configuration();
/**
* Actual position of the surface shown on-screen (may be modified by animation). These are
@@ -244,8 +245,8 @@
* coordinate space (without compatibility scale applied).
*/
final Rect mVisibleInsets = new Rect();
- final Rect mLastVisibleInsets = new Rect();
- boolean mVisibleInsetsChanged;
+ private final Rect mLastVisibleInsets = new Rect();
+ private boolean mVisibleInsetsChanged;
/**
* Insets that are covered by system windows (such as the status bar) and
@@ -254,31 +255,31 @@
*/
final Rect mContentInsets = new Rect();
final Rect mLastContentInsets = new Rect();
- boolean mContentInsetsChanged;
+ private boolean mContentInsetsChanged;
/**
* Insets that determine the area covered by the display overscan region. These are in the
* application's coordinate space (without compatibility scale applied).
*/
final Rect mOverscanInsets = new Rect();
- final Rect mLastOverscanInsets = new Rect();
- boolean mOverscanInsetsChanged;
+ private final Rect mLastOverscanInsets = new Rect();
+ private boolean mOverscanInsetsChanged;
/**
* Insets that determine the area covered by the stable system windows. These are in the
* application's coordinate space (without compatibility scale applied).
*/
final Rect mStableInsets = new Rect();
- final Rect mLastStableInsets = new Rect();
- boolean mStableInsetsChanged;
+ private final Rect mLastStableInsets = new Rect();
+ private boolean mStableInsetsChanged;
/**
* Outsets determine the area outside of the surface where we want to pretend that it's possible
* to draw anyway.
*/
final Rect mOutsets = new Rect();
- final Rect mLastOutsets = new Rect();
- boolean mOutsetsChanged = false;
+ private final Rect mLastOutsets = new Rect();
+ private boolean mOutsetsChanged = false;
/**
* Set to true if we are waiting for this window to receive its
@@ -321,14 +322,14 @@
// "Real" frame that the application sees, in display coordinate space.
final Rect mFrame = new Rect();
final Rect mLastFrame = new Rect();
- boolean mFrameSizeChanged = false;
+ private boolean mFrameSizeChanged = false;
// Frame that is scaled to the application's coordinate space when in
// screen size compatibility mode.
final Rect mCompatFrame = new Rect();
final Rect mContainingFrame = new Rect();
- final Rect mParentFrame = new Rect();
+ private final Rect mParentFrame = new Rect();
// The entire screen area of the {@link TaskStack} this window is in. Usually equal to the
// screen area of the device.
@@ -338,11 +339,11 @@
// is mostly a special case for TV where some displays don’t have the entire display usable.
// {@link WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag can be used to allow
// window display contents to extend into the overscan region.
- final Rect mOverscanFrame = new Rect();
+ private final Rect mOverscanFrame = new Rect();
// The display frame minus the stable insets. This value is always constant regardless of if
// the status bar or navigation bar is visible.
- final Rect mStableFrame = new Rect();
+ private final Rect mStableFrame = new Rect();
// The area not occupied by the status and navigation bars. So, if both status and navigation
// bars are visible, the decor frame is equal to the stable frame.
@@ -350,7 +351,7 @@
// Equal to the decor frame if the IME (e.g. keyboard) is not present. Equal to the decor frame
// minus the area occupied by the IME if the IME is present.
- final Rect mContentFrame = new Rect();
+ private final Rect mContentFrame = new Rect();
// Legacy stuff. Generally equal to the content frame expect when the IME for older apps
// displays hint text.
@@ -358,13 +359,13 @@
// Frame that includes dead area outside of the surface but where we want to pretend that it's
// possible to draw.
- final Rect mOutsetFrame = new Rect();
+ private final Rect mOutsetFrame = new Rect();
/**
* Usually empty. Set to the task's tempInsetFrame. See
*{@link android.app.IActivityManager#resizeDockedStack}.
*/
- final Rect mInsetFrame = new Rect();
+ private final Rect mInsetFrame = new Rect();
boolean mContentChanged;
@@ -446,7 +447,7 @@
* or some other higher level component said so (e.g. activity manager).
* TODO: We should either have different booleans for the removal reason or use a bit-field.
*/
- boolean mWindowRemovalAllowed;
+ private boolean mWindowRemovalAllowed;
/**
* Temp for keeping track of windows that have been removed when
@@ -457,20 +458,17 @@
// Input channel and input window handle used by the input dispatcher.
final InputWindowHandle mInputWindowHandle;
InputChannel mInputChannel;
- InputChannel mClientChannel;
+ private InputChannel mClientChannel;
// Used to improve performance of toString()
- String mStringNameCache;
- CharSequence mLastTitle;
- boolean mWasExiting;
+ private String mStringNameCache;
+ private CharSequence mLastTitle;
+ private boolean mWasExiting;
final WindowStateAnimator mWinAnimator;
boolean mHasSurface = false;
- boolean mNotOnAppsDisplay = false;
- DisplayContent mDisplayContent;
-
/** When true this window can be displayed on screens owther than mOwnerUid's */
private boolean mShowToOwnerOnly;
@@ -486,26 +484,26 @@
// Whether the window was visible when we set the app to invisible last time. WM uses
// this as a hint to restore the surface (if available) for early animation next time
// the app is brought visible.
- boolean mWasVisibleBeforeClientHidden;
+ private boolean mWasVisibleBeforeClientHidden;
// This window will be replaced due to relaunch. This allows window manager
// to differentiate between simple removal of a window and replacement. In the latter case it
// will preserve the old window until the new one is drawn.
boolean mWillReplaceWindow = false;
// If true, the replaced window was already requested to be removed.
- boolean mReplacingRemoveRequested = false;
+ private boolean mReplacingRemoveRequested = false;
// Whether the replacement of the window should trigger app transition animation.
- boolean mAnimateReplacingWindow = false;
+ private boolean mAnimateReplacingWindow = false;
// If not null, the window that will be used to replace the old one. This is being set when
// the window is added and unset when this window reports its first draw.
- WindowState mReplacementWindow = null;
+ private WindowState mReplacementWindow = null;
// For the new window in the replacement transition, if we have
// requested to replace without animation, then we should
// make sure we also don't apply an enter animation for
// the new window.
boolean mSkipEnterAnimationForSeamlessReplacement = false;
// Whether this window is being moved via the resize API
- boolean mMovedByResize;
+ private boolean mMovedByResize;
/**
* Wake lock for drawing.
@@ -514,7 +512,7 @@
* who is preventing the system from suspending.
* This lock is only acquired on first use.
*/
- PowerManager.WakeLock mDrawLock;
+ private PowerManager.WakeLock mDrawLock;
final private Rect mTmpRect = new Rect();
@@ -563,7 +561,7 @@
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
- int viewVisibility, final DisplayContent displayContent, int ownerId) {
+ int viewVisibility, int ownerId) {
mService = service;
mSession = s;
mClient = c;
@@ -587,7 +585,6 @@
};
mAttrs.copyFrom(a);
mViewVisibility = viewVisibility;
- mDisplayContent = displayContent;
mPolicy = mService.mPolicy;
mContext = mService.mContext;
DeathRecipient deathRecipient = new DeathRecipient();
@@ -643,15 +640,10 @@
}
mIsFloatingLayer = mIsImWindow || mIsWallpaper;
- if (mAppToken != null) {
- final DisplayContent appDisplay = getDisplayContent();
- mNotOnAppsDisplay = displayContent != appDisplay;
-
- if (mAppToken.showForAllUsers) {
- // Windows for apps that can show for all users should also show when the
- // device is locked.
- mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
- }
+ if (mAppToken != null && mAppToken.showForAllUsers) {
+ // Windows for apps that can show for all users should also show when the device is
+ // locked.
+ mAttrs.flags |= FLAG_SHOW_WHEN_LOCKED;
}
mWinAnimator = new WindowStateAnimator(this);
@@ -666,7 +658,7 @@
mLayer = 0;
mInputWindowHandle = new InputWindowHandle(
mAppToken != null ? mAppToken.mInputApplicationHandle : null, this,
- displayContent.getDisplayId());
+ getDisplayContent().getDisplayId());
}
void attach() {
@@ -714,6 +706,7 @@
final Task task = getTask();
final boolean fullscreenTask = !isInMultiWindowMode();
final boolean windowsAreFloating = task != null && task.isFloating();
+ final DisplayContent dc = getDisplayContent();
// If the task has temp inset bounds set, we have to make sure all its windows uses
// the temp inset frame. Otherwise different display frames get applied to the main
@@ -779,8 +772,7 @@
layoutXDiff = !mInsetFrame.isEmpty() ? mInsetFrame.left - mContainingFrame.left : 0;
layoutYDiff = !mInsetFrame.isEmpty() ? mInsetFrame.top - mContainingFrame.top : 0;
layoutContainingFrame = !mInsetFrame.isEmpty() ? mInsetFrame : mContainingFrame;
- mTmpRect.set(0, 0, mDisplayContent.getDisplayInfo().logicalWidth,
- mDisplayContent.getDisplayInfo().logicalHeight);
+ mTmpRect.set(0, 0, dc.getDisplayInfo().logicalWidth, dc.getDisplayInfo().logicalHeight);
subtractInsets(mDisplayFrame, layoutContainingFrame, df, mTmpRect);
if (!layoutInParentFrame()) {
subtractInsets(mContainingFrame, layoutContainingFrame, pf, mTmpRect);
@@ -852,7 +844,7 @@
mVisibleFrame.set(mContentFrame);
mStableFrame.set(mContentFrame);
} else if (mAttrs.type == TYPE_DOCK_DIVIDER) {
- mDisplayContent.getDockedDividerController().positionDockedStackedDivider(mFrame);
+ dc.getDockedDividerController().positionDockedStackedDivider(mFrame);
mContentFrame.set(mFrame);
if (!mFrame.equals(mLastFrame)) {
mMovedByResize = true;
@@ -1081,20 +1073,122 @@
|| mOutsetsChanged || mFrameSizeChanged;
}
- public DisplayContent getDisplayContent() {
- if (mAppToken == null || mNotOnAppsDisplay) {
- return mDisplayContent;
+ /**
+ * Adds the window to the resizing list if any of the parameters we use to track the window
+ * dimensions or insets have changed.
+ */
+ void updateResizingWindowIfNeeded() {
+ final WindowStateAnimator winAnimator = mWinAnimator;
+ if (!mHasSurface || mService.mLayoutSeq != mLayoutSeq || isGoneForLayoutLw()) {
+ return;
}
- final TaskStack stack = getStack();
- return stack == null ? mDisplayContent : stack.getDisplayContent();
+
+ final Task task = getTask();
+ // In the case of stack bound animations, the window frames will update (unlike other
+ // animations which just modify various transformation properties). We don't want to
+ // notify the client of frame changes in this case. Not only is it a lot of churn, but
+ // the frame may not correspond to the surface size or the onscreen area at various
+ // phases in the animation, and the client will become sad and confused.
+ if (task != null && task.mStack.getBoundsAnimating()) {
+ return;
+ }
+
+ setReportResizeHints();
+ boolean configChanged = isConfigChanged();
+ if (DEBUG_CONFIGURATION && configChanged) {
+ Slog.v(TAG_WM, "Win " + this + " config changed: " + getConfiguration());
+ }
+
+ final boolean dragResizingChanged = isDragResizeChanged()
+ && !isDragResizingChangeReported();
+
+ if (localLOGV) Slog.v(TAG_WM, "Resizing " + this + ": configChanged=" + configChanged
+ + " dragResizingChanged=" + dragResizingChanged + " last=" + mLastFrame
+ + " frame=" + mFrame);
+
+ // We update mLastFrame always rather than in the conditional with the last inset
+ // variables, because mFrameSizeChanged only tracks the width and height changing.
+ mLastFrame.set(mFrame);
+
+ if (mContentInsetsChanged
+ || mVisibleInsetsChanged
+ || winAnimator.mSurfaceResized
+ || mOutsetsChanged
+ || mFrameSizeChanged
+ || configChanged
+ || dragResizingChanged
+ || !isResizedWhileNotDragResizingReported()) {
+ if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
+ Slog.v(TAG_WM, "Resize reasons for w=" + this + ": "
+ + " contentInsetsChanged=" + mContentInsetsChanged
+ + " " + mContentInsets.toShortString()
+ + " visibleInsetsChanged=" + mVisibleInsetsChanged
+ + " " + mVisibleInsets.toShortString()
+ + " stableInsetsChanged=" + mStableInsetsChanged
+ + " " + mStableInsets.toShortString()
+ + " outsetsChanged=" + mOutsetsChanged
+ + " " + mOutsets.toShortString()
+ + " surfaceResized=" + winAnimator.mSurfaceResized
+ + " configChanged=" + configChanged
+ + " dragResizingChanged=" + dragResizingChanged
+ + " resizedWhileNotDragResizingReported="
+ + isResizedWhileNotDragResizingReported());
+ }
+
+ // If it's a dead window left on screen, and the configuration changed, there is nothing
+ // we can do about it. Remove the window now.
+ if (mAppToken != null && mAppDied) {
+ mAppToken.removeDeadWindows();
+ return;
+ }
+
+ mLastOverscanInsets.set(mOverscanInsets);
+ mLastContentInsets.set(mContentInsets);
+ mLastVisibleInsets.set(mVisibleInsets);
+ mLastStableInsets.set(mStableInsets);
+ mLastOutsets.set(mOutsets);
+ mService.makeWindowFreezingScreenIfNeededLocked(this);
+
+ // If the orientation is changing, or we're starting or ending a drag resizing action,
+ // then we need to hold off on unfreezing the display until this window has been
+ // redrawn; to do that, we need to go through the process of getting informed by the
+ // application when it has finished drawing.
+ if (mOrientationChanging || dragResizingChanged || isResizedWhileNotDragResizing()) {
+ if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) {
+ Slog.v(TAG_WM, "Orientation or resize start waiting for draw"
+ + ", mDrawState=DRAW_PENDING in " + this
+ + ", surfaceController " + winAnimator.mSurfaceController);
+ }
+ winAnimator.mDrawState = DRAW_PENDING;
+ if (mAppToken != null) {
+ mAppToken.clearAllDrawn();
+ }
+ }
+ if (!mService.mResizingWindows.contains(this)) {
+ if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG_WM, "Resizing window " + this);
+ mService.mResizingWindows.add(this);
+ }
+ } else if (mOrientationChanging) {
+ if (isDrawnLw()) {
+ if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Orientation not waiting for draw in "
+ + this + ", surfaceController " + winAnimator.mSurfaceController);
+ mOrientationChanging = false;
+ mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
+ - mService.mDisplayFreezeTime);
+ }
+ }
}
- public DisplayInfo getDisplayInfo() {
+ DisplayContent getDisplayContent() {
+ return mToken.getDisplayContent();
+ }
+
+ DisplayInfo getDisplayInfo() {
final DisplayContent displayContent = getDisplayContent();
return displayContent != null ? displayContent.getDisplayInfo() : null;
}
- public int getDisplayId() {
+ int getDisplayId() {
final DisplayContent displayContent = getDisplayContent();
if (displayContent == null) {
return -1;
@@ -1115,8 +1209,8 @@
}
// Some system windows (e.g. "Power off" dialog) don't have a task, but we would still
// associate them with some stack to enable dimming.
- return mAttrs.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
- && mDisplayContent != null ? mDisplayContent.getHomeStack() : null;
+ final DisplayContent dc = getDisplayContent();
+ return mAttrs.type >= FIRST_SYSTEM_WINDOW && dc != null ? dc.getHomeStack() : null;
}
/**
@@ -1194,7 +1288,22 @@
@Override
boolean isVisible() {
- if ((mAppToken == null || !mAppToken.hiddenRequested) && isVisibleUnchecked()) {
+ // TODO: The check for hiddenRequested is commented out below, because the window can still
+ // be visible on screen when the flag is true. We would like the isVisible() method to
+ // return an answer closer to if the window is truly visible (can't be an exact answer
+ // without checking the surface state), so comment out the check for now so we can test to
+ // see what problem it causes.
+ // If it doesn't cause any issues, then we can remove just before we lock down the current
+ // release (O) and also consolidate this method with #isVisibleUnchecked() and possibly
+ // other methods like isVisibleNow().
+ // If it does cause problems, then we can look if there are other ways to solve the problem.
+ // If there isn't then uncomment and document here why it is needed.
+ if (/*(mAppToken == null || !mAppToken.hiddenRequested) && */isVisibleUnchecked()
+ // TODO: The window isn't considered visible when the token is hidden, however
+ // uncommenting the check below breaks the visual transition from an app to the launcher
+ // if the home buttons is pressed. Need to investigate an fix that issue before
+ // uncommenting.
+ /* && !mToken.hidden*/) {
// Is this window visible? It is not visible if there is no surface, or we are in the
// process of running an exit animation that will remove the surface, or its app token
// has been hidden.
@@ -1426,7 +1535,7 @@
* Return true if the window is opaque and fully drawn. This indicates
* it may obscure windows behind it.
*/
- boolean isOpaqueDrawn() {
+ private boolean isOpaqueDrawn() {
// When there is keyguard, wallpaper could be placed over the secure app
// window but invisible. We need to check wallpaper visibility explicitly
// to determine if it's occluding apps.
@@ -1557,10 +1666,49 @@
}
/**
+ * If the window has moved due to its containing content frame changing, then notify the
+ * listeners and optionally animate it. Simply checking a change of position is not enough,
+ * because being move due to dock divider is not a trigger for animation.
+ */
+ void handleWindowMovedIfNeeded() {
+ if (!hasMoved()) {
+ return;
+ }
+
+ // Frame has moved, containing content frame has also moved, and we're not currently
+ // animating... let's do something.
+ final int left = mFrame.left;
+ final int top = mFrame.top;
+ final Task task = getTask();
+ final boolean adjustedForMinimizedDockOrIme = task != null
+ && (task.mStack.isAdjustedForMinimizedDockedStack()
+ || task.mStack.isAdjustedForIme());
+ if (mService.okToDisplay()
+ && (mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
+ && !isDragResizing() && !adjustedForMinimizedDockOrIme
+ && (task == null || getTask().mStack.hasMovementAnimations())
+ && !mWinAnimator.mLastHidden) {
+ mWinAnimator.setMoveAnimation(left, top);
+ }
+
+ //TODO (multidisplay): Accessibility supported only for the default display.
+ if (mService.mAccessibilityController != null
+ && getDisplayContent().getDisplayId() == Display.DEFAULT_DISPLAY) {
+ mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+ }
+
+ try {
+ mClient.moved(left, top);
+ } catch (RemoteException e) {
+ }
+ mMovedByResize = false;
+ }
+
+ /**
* Return whether this window has moved. (Only makes
* sense to call from performLayoutAndPlaceSurfacesLockedInner().)
*/
- boolean hasMoved() {
+ private boolean hasMoved() {
return mHasSurface && (mContentChanged || mMovedByResize)
&& !mAnimatingExit
&& (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
@@ -1583,21 +1731,9 @@
&& mFrame.right >= displayInfo.appWidth && mFrame.bottom >= displayInfo.appHeight;
}
+ /** Returns true if last applied config was not yet requested by client. */
boolean isConfigChanged() {
- getMergedConfig(mTmpConfig);
-
- // If the merged configuration is still empty, it means that we haven't issued the
- // configuration to the client yet and we need to return true so the configuration updates.
- boolean configChanged = mMergedConfiguration.equals(Configuration.EMPTY)
- || mTmpConfig.diff(mMergedConfiguration) != 0;
-
- if ((mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
- // Retain configuration changed status until resetConfiguration called.
- mConfigHasChanged |= configChanged;
- configChanged = mConfigHasChanged;
- }
-
- return configChanged;
+ return !mLastReportedConfiguration.equals(getConfiguration());
}
boolean isAdjustedForMinimizedDock() {
@@ -1852,12 +1988,12 @@
}
void scheduleAnimationIfDimming() {
- if (mDisplayContent == null) {
+ final DisplayContent dc = getDisplayContent();
+ if (dc == null) {
return;
}
final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
- if (dimLayerUser != null && mDisplayContent.mDimLayerController.isDimming(
- dimLayerUser, mWinAnimator)) {
+ if (dimLayerUser != null && dc.mDimLayerController.isDimming(dimLayerUser, mWinAnimator)) {
// Force an animation pass just to update the mDimLayer layer.
mService.scheduleAnimationLocked();
}
@@ -1970,16 +2106,17 @@
return;
}
+ final DisplayContent dc = getDisplayContent();
if (!mAnimatingExit && mAppDied) {
// If app died visible, apply a dim over the window to indicate that it's inactive
- mDisplayContent.mDimLayerController.applyDimAbove(getDimLayerUser(), mWinAnimator);
+ dc.mDimLayerController.applyDimAbove(getDimLayerUser(), mWinAnimator);
} else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0
- && mDisplayContent != null && !mAnimatingExit && isVisibleUnchecked()) {
- mDisplayContent.mDimLayerController.applyDimBehind(getDimLayerUser(), mWinAnimator);
+ && dc != null && !mAnimatingExit && isVisibleUnchecked()) {
+ dc.mDimLayerController.applyDimBehind(getDimLayerUser(), mWinAnimator);
}
}
- DimLayer.DimLayerUser getDimLayerUser() {
+ private DimLayer.DimLayerUser getDimLayerUser() {
Task task = getTask();
if (task != null) {
return task;
@@ -2038,8 +2175,9 @@
}
void setDisplayLayoutNeeded() {
- if (mDisplayContent != null) {
- mDisplayContent.setLayoutNeeded();
+ final DisplayContent dc = getDisplayContent();
+ if (dc != null) {
+ dc.setLayoutNeeded();
}
}
@@ -2132,10 +2270,10 @@
mTurnOnScreen = true;
}
if (isConfigChanged()) {
- final Configuration newConfig = updateConfiguration();
+ outConfig.setTo(getConfiguration());
if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this + " visible with new config: "
- + newConfig);
- outConfig.setTo(newConfig);
+ + outConfig);
+ mLastReportedConfiguration.setTo(outConfig);
}
}
@@ -2503,6 +2641,8 @@
return unfrozeWindows;
}
+ mAppFreezing = false;
+
if (mHasSurface && !mOrientationChanging
&& mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "set mOrientationChanging of " + this);
@@ -2758,18 +2898,19 @@
@Override
public boolean isDimming() {
final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
- return dimLayerUser != null && mDisplayContent != null &&
- mDisplayContent.mDimLayerController.isDimming(dimLayerUser, mWinAnimator);
+ final DisplayContent dc = getDisplayContent();
+ return dimLayerUser != null && dc != null
+ && dc.mDimLayerController.isDimming(dimLayerUser, mWinAnimator);
}
- public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
+ void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
mShowToOwnerOnly = showToOwnerOnly;
}
boolean isHiddenFromUserLocked() {
// Child windows are evaluated based on their parent window.
final WindowState win = getTopParentWindow();
- if (win.mAttrs.type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
+ if (win.mAttrs.type < FIRST_SYSTEM_WINDOW
&& win.mAppToken != null && win.mAppToken.showForAllUsers) {
// All window frames that are fullscreen extend above status bar, but some don't extend
@@ -2865,35 +3006,13 @@
}
}
- /**
- * Update our current configurations, based on task configuration.
- *
- * @return A configuration suitable for sending to the client.
- */
- private Configuration updateConfiguration() {
- final boolean configChanged = isConfigChanged();
- getMergedConfig(mMergedConfiguration);
- mConfigHasChanged = false;
- if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) {
- Slog.i(TAG, "Sending new config to window " + this + ": " +
- " / mergedConfig=" + mMergedConfiguration);
- }
- return mMergedConfiguration;
- }
-
- private void getMergedConfig(Configuration outConfig) {
+ @Override
+ public Configuration getConfiguration() {
if (mAppToken != null && mAppToken.mFrozenMergedConfig.size() > 0) {
- outConfig.setTo(mAppToken.mFrozenMergedConfig.peek());
- return;
+ return mAppToken.mFrozenMergedConfig.peek();
}
- final Task task = getTask();
- final Configuration overrideConfig = task != null
- ? task.mOverrideConfig
- : Configuration.EMPTY;
- outConfig.setTo(mService.mGlobalConfiguration);
- if (overrideConfig != Configuration.EMPTY) {
- outConfig.updateFrom(overrideConfig);
- }
+
+ return super.getConfiguration();
}
void reportResized() {
@@ -2901,8 +3020,14 @@
try {
if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
+ ": " + mCompatFrame);
- final Configuration newConfig = isConfigChanged() ? updateConfiguration() : null;
- if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING)
+ final Configuration newConfig;
+ if (isConfigChanged()) {
+ newConfig = new Configuration(getConfiguration());
+ mLastReportedConfiguration.setTo(newConfig);
+ } else {
+ newConfig = null;
+ }
+ if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == DRAW_PENDING)
Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
final Rect frame = mFrame;
@@ -2911,7 +3036,7 @@
final Rect visibleInsets = mLastVisibleInsets;
final Rect stableInsets = mLastStableInsets;
final Rect outsets = mLastOutsets;
- final boolean reportDraw = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
+ final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING;
if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
&& mClient instanceof IWindow.Stub) {
// To prevent deadlock simulate one-way call if win.mClient is a local object.
@@ -3078,7 +3203,7 @@
* @return Whether we reported "resize while not drag resizing" to the application.
* @see #isResizedWhileNotDragResizing()
*/
- boolean isResizedWhileNotDragResizingReported() {
+ private boolean isResizedWhileNotDragResizingReported() {
return mResizedWhileNotDragResizingReported;
}
@@ -3086,7 +3211,7 @@
return mResizeMode;
}
- boolean computeDragResizing() {
+ private boolean computeDragResizing() {
final Task task = getTask();
if (task == null) {
return false;
@@ -3104,7 +3229,7 @@
// and the bounds we clip this window to might be different. In order to avoid holes, we
// simulate that we are still resizing so the app fills the hole with the resizing
// background.
- return (mDisplayContent.mDividerControllerLocked.isResizing()
+ return (getDisplayContent().mDividerControllerLocked.isResizing()
|| mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) &&
!task.inFreeformWorkspace() && !isGoneForLayoutLw();
@@ -3120,7 +3245,7 @@
if (task != null && task.isDragResizing()) {
mResizeMode = task.getDragResizeMode();
} else {
- mResizeMode = mDragResizing && mDisplayContent.mDividerControllerLocked.isResizing()
+ mResizeMode = mDragResizing && getDisplayContent().mDividerControllerLocked.isResizing()
? DRAG_RESIZE_MODE_DOCKED_DIVIDER
: DRAG_RESIZE_MODE_FREEFORM;
}
@@ -3140,9 +3265,6 @@
if (stack != null) {
pw.print(" stackId="); pw.print(stack.mStackId);
}
- if (mNotOnAppsDisplay) {
- pw.print(" mNotOnAppsDisplay="); pw.print(mNotOnAppsDisplay);
- }
pw.print(" mSession="); pw.print(mSession);
pw.print(" mClient="); pw.println(mClient.asBinder());
pw.print(prefix); pw.print("mOwnerUid="); pw.print(mOwnerUid);
@@ -3223,7 +3345,9 @@
getTouchableRegion(region);
pw.print(prefix); pw.print("touchable region="); pw.println(region);
}
- pw.print(prefix); pw.print("mMergedConfiguration="); pw.println(mMergedConfiguration);
+ pw.print(prefix); pw.print("mFullConfiguration="); pw.println(getConfiguration());
+ pw.print(prefix); pw.print("mLastReportedConfiguration=");
+ pw.println(mLastReportedConfiguration);
}
pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
@@ -3526,9 +3650,10 @@
}
void requestUpdateWallpaperIfNeeded() {
- if (mDisplayContent != null && (mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
- mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- mDisplayContent.setLayoutNeeded();
+ final DisplayContent dc = getDisplayContent();
+ if (dc != null && (mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
+ dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ dc.setLayoutNeeded();
mService.mWindowPlacerLocked.requestTraversal();
}
@@ -3554,12 +3679,12 @@
return winY;
}
- void transferDimToReplacement() {
+ private void transferDimToReplacement() {
final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
- if (dimLayerUser != null && mDisplayContent != null) {
- mDisplayContent.mDimLayerController.applyDim(dimLayerUser,
- mReplacementWindow.mWinAnimator,
- (mAttrs.flags & FLAG_DIM_BEHIND) != 0 ? true : false);
+ final DisplayContent dc = getDisplayContent();
+ if (dimLayerUser != null && dc != null) {
+ dc.mDimLayerController.applyDim(dimLayerUser,
+ mReplacementWindow.mWinAnimator, (mAttrs.flags & FLAG_DIM_BEHIND) != 0);
}
}
@@ -3657,13 +3782,13 @@
}
if (mAttrs.type == TYPE_INPUT_METHOD) {
- mDisplayContent.mDividerControllerLocked.resetImeHideRequested();
+ getDisplayContent().mDividerControllerLocked.resetImeHideRequested();
}
return true;
}
- void logPerformShow(String prefix) {
+ private void logPerformShow(String prefix) {
if (DEBUG_VISIBILITY
|| (DEBUG_STARTING_WINDOW && mAttrs.type == TYPE_APPLICATION_STARTING)) {
Slog.v(TAG, prefix + this
@@ -3673,11 +3798,11 @@
+ " during animation: policyVis=" + mPolicyVisibility
+ " parentHidden=" + isParentWindowHidden()
+ " tok.hiddenRequested="
- + (mAppToken != null ? mAppToken.hiddenRequested : false)
- + " tok.hidden=" + (mAppToken != null ? mAppToken.hidden : false)
+ + (mAppToken != null && mAppToken.hiddenRequested)
+ + " tok.hidden=" + (mAppToken != null && mAppToken.hidden)
+ " animating=" + mWinAnimator.mAnimating
+ " tok animating="
- + (mWinAnimator.mAppAnimator != null ? mWinAnimator.mAppAnimator.animating : false)
+ + (mWinAnimator.mAppAnimator != null && mWinAnimator.mAppAnimator.animating)
+ " Callers=" + Debug.getCallers(4));
}
}
@@ -3735,13 +3860,8 @@
}
@Override
- int rebuildWindowList(DisplayContent dc, int addIndex) {
- final DisplayContent winDisplayContent = getDisplayContent();
- if (winDisplayContent == dc || winDisplayContent == null) {
- mDisplayContent = dc;
- return reAddWindow(addIndex);
- }
- return addIndex;
+ int rebuildWindowList(int addIndex) {
+ return reAddWindow(addIndex);
}
// TODO: come-up with a better name for this method that represents what it does.
@@ -3928,7 +4048,7 @@
}
public boolean isRtl() {
- return mMergedConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+ return getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
}
void hideWallpaperWindow(boolean wasDeferred, String reason) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 6c7d136..53fb99b 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -966,7 +966,7 @@
mDtDy = tmpFloats[Matrix.MSCALE_Y];
float x = tmpFloats[Matrix.MTRANS_X];
float y = tmpFloats[Matrix.MTRANS_Y];
- mWin.mShownPosition.set((int) x, (int) y);
+ mWin.mShownPosition.set(Math.round(x), Math.round(y));
// Now set the alpha... but because our current hardware
// can't do alpha transformation on a non-opaque surface,
@@ -1059,7 +1059,7 @@
mDtDy = tmpFloats[Matrix.MSCALE_Y];
float x = tmpFloats[Matrix.MTRANS_X];
float y = tmpFloats[Matrix.MTRANS_Y];
- mWin.mShownPosition.set((int) x, (int) y);
+ mWin.mShownPosition.set(Math.round(x), Math.round(y));
mShownAlpha = mAlpha;
} else {
@@ -1350,7 +1350,7 @@
// If we are undergoing seamless rotation, the surface has already
// been set up to persist at it's old location. We need to freeze
// updates until a resize occurs.
- w.mSeamlesslyRotated = w.mSeamlesslyRotated && !mSurfaceResized;
+ mService.markForSeamlessRotation(w, w.mSeamlesslyRotated && !mSurfaceResized);
calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
@@ -1750,7 +1750,7 @@
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
if (mWin.mAttrs.type == TYPE_INPUT_METHOD) {
- mWin.mDisplayContent.adjustForImeIfNeeded();
+ mWin.getDisplayContent().adjustForImeIfNeeded();
if (isEntrance) {
mWin.setDisplayLayoutNeeded();
mService.mWindowPlacerLocked.requestTraversal();
@@ -1936,24 +1936,8 @@
// Compute a transform matrix to undo the coordinate space transformation,
// and present the window at the same physical position it previously occupied.
final int deltaRotation = DisplayContent.deltaRotation(newRotation, oldRotation);
- switch (deltaRotation) {
- case Surface.ROTATION_0:
- transform.reset();
- break;
- case Surface.ROTATION_270:
- transform.setRotate(270, 0, 0);
- transform.postTranslate(0, displayHeight);
- transform.postTranslate(y, 0);
- break;
- case Surface.ROTATION_180:
- transform.reset();
- break;
- case Surface.ROTATION_90:
- transform.setRotate(90, 0, 0);
- transform.postTranslate(displayWidth, 0);
- transform.postTranslate(-y, x);
- break;
- }
+ DisplayContent.createRotationMatrix(deltaRotation, x, y, displayWidth, displayHeight,
+ transform);
// We have two cases:
// 1. Windows with NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
@@ -1991,7 +1975,7 @@
cropRect.set(0, 0, w.mRequestedWidth, w.mRequestedWidth + w.mRequestedHeight);
mSurfaceController.setCropInTransaction(cropRect, false);
} else {
- w.mSeamlesslyRotated = true;
+ mService.markForSeamlessRotation(w, true);
transform.getValues(mService.mTmpFloats);
float DsDx = mService.mTmpFloats[Matrix.MSCALE_X];
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 7acccea..285a75c 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -9,7 +9,17 @@
import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE;
+import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
+import static com.android.server.wm.AppTransition.TRANSIT_TASK_CLOSE;
+import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
+import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
+import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_BACK;
+import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
+import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_CLOSE;
+import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
+import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
+import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_OPEN;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
@@ -25,6 +35,7 @@
import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
+import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
@@ -215,14 +226,6 @@
final int dw = displayInfo.logicalWidth;
final int dh = displayInfo.logicalHeight;
- if (mService.mInputConsumer != null) {
- mService.mInputConsumer.layout(dw, dh);
- }
-
- if (mService.mWallpaperInputConsumer != null) {
- mService.mWallpaperInputConsumer.layout(dw, dh);
- }
-
final int N = windows.size();
int i;
@@ -233,7 +236,7 @@
}
mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mService.mRotation,
- mService.mGlobalConfiguration.uiMode);
+ displayContent.getConfiguration().uiMode);
if (isDefaultDisplay) {
// Not needed on non-default displays.
mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw();
@@ -369,6 +372,7 @@
}
// Window frames may have changed. Tell the input dispatcher about it.
+ mService.mInputMonitor.layoutInputConsumers(dw, dh);
mService.mInputMonitor.setUpdateInputWindowsNeededLw();
if (updateInputWindows) {
mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
@@ -404,8 +408,7 @@
mService.mRoot.mWallpaperMayChange = false;
- // The top-most window will supply the layout params,
- // and we will determine it below.
+ // The top-most window will supply the layout params, and we will determine it below.
LayoutParams animLp = null;
int bestAnimLayer = -1;
boolean fullscreenAnim = false;
@@ -414,21 +417,19 @@
int i;
for (i = 0; i < appsCount; i++) {
final AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
- // Clearing the mAnimatingExit flag before entering animation. It's set to
- // true if app window is removed, or window relayout to invisible.
- // This also affects window visibility. We need to clear it *before*
- // maybeUpdateTransitToWallpaper() as the transition selection depends on
- // wallpaper target visibility.
+ // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
+ // window is removed, or window relayout to invisible. This also affects window
+ // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
+ // transition selection depends on wallpaper target visibility.
wtoken.clearAnimatingFlags();
}
+
// Adjust wallpaper before we pull the lower/upper target, since pending changes
// (like the clearAnimatingFlags() above) might affect wallpaper target result.
- if ((displayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
- mWallpaperControllerLocked.adjustWallpaperWindows()) {
- mService.mLayersController.assignLayersLocked(windows);
- displayContent.setLayoutNeeded();
- }
+ // Or, the opening app window should be a wallpaper target.
+ mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(displayContent,
+ mService.mOpeningApps, windows);
final WindowState lowerWallpaperTarget =
mWallpaperControllerLocked.getLowerWallpaperTarget();
@@ -446,15 +447,11 @@
upperWallpaperAppToken = upperWallpaperTarget.mAppToken;
}
- // Do a first pass through the tokens for two
- // things:
- // (1) Determine if both the closing and opening
- // app token sets are wallpaper targets, in which
- // case special animations are needed
- // (since the wallpaper needs to stay static
- // behind them).
- // (2) Find the layout params of the top-most
- // application window in the tokens, which is
+ // Do a first pass through the tokens for two things:
+ // (1) Determine if both the closing and opening app token sets are wallpaper targets, in
+ // which case special animations are needed (since the wallpaper needs to stay static behind
+ // them).
+ // (2) Find the layout params of the top-most application window in the tokens, which is
// what will control the animation theme.
final int closingAppsCount = mService.mClosingApps.size();
appsCount = closingAppsCount + mService.mOpeningApps.size();
@@ -495,10 +492,8 @@
transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
closingAppHasWallpaper, lowerWallpaperTarget, upperWallpaperTarget);
- // If all closing windows are obscured, then there is
- // no need to do an animation. This is the case, for
- // example, when this transition is being done behind
- // the lock screen.
+ // If all closing windows are obscured, then there is no need to do an animation. This is
+ // the case, for example, when this transition is being done behind the lock screen.
if (!mService.mPolicy.allowAppAnimationsLw()) {
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
"Animations disallowed by keyguard or dream.");
@@ -720,9 +715,8 @@
WindowState upperWallpaperTarget) {
// if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
- final WindowState oldWallpaper =
- mWallpaperControllerLocked.isWallpaperTargetAnimating()
- ? null : wallpaperTarget;
+ final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating()
+ ? null : wallpaperTarget;
final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps;
final ArraySet<AppWindowToken> closingApps = mService.mClosingApps;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
@@ -734,18 +728,17 @@
+ ", closingApps=" + closingApps);
mService.mAnimateWallpaperWithTarget = false;
if (closingAppHasWallpaper && openingAppHasWallpaper) {
- if (DEBUG_APP_TRANSITIONS)
- Slog.v(TAG, "Wallpaper animation!");
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
switch (transit) {
- case AppTransition.TRANSIT_ACTIVITY_OPEN:
- case AppTransition.TRANSIT_TASK_OPEN:
- case AppTransition.TRANSIT_TASK_TO_FRONT:
- transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
+ case TRANSIT_ACTIVITY_OPEN:
+ case TRANSIT_TASK_OPEN:
+ case TRANSIT_TASK_TO_FRONT:
+ transit = TRANSIT_WALLPAPER_INTRA_OPEN;
break;
- case AppTransition.TRANSIT_ACTIVITY_CLOSE:
- case AppTransition.TRANSIT_TASK_CLOSE:
- case AppTransition.TRANSIT_TASK_TO_BACK:
- transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
+ case TRANSIT_ACTIVITY_CLOSE:
+ case TRANSIT_TASK_CLOSE:
+ case TRANSIT_TASK_TO_BACK:
+ transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
break;
}
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
@@ -754,17 +747,15 @@
&& !openingApps.contains(oldWallpaper.mAppToken)
&& closingApps.contains(oldWallpaper.mAppToken)) {
// We are transitioning from an activity with a wallpaper to one without.
- transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit away from wallpaper: "
+ transit = TRANSIT_WALLPAPER_CLOSE;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
+ AppTransition.appTransitionToString(transit));
} else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw() &&
openingApps.contains(wallpaperTarget.mAppToken)) {
// We are transitioning from an activity without
// a wallpaper to now showing the wallpaper
- transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit into wallpaper: "
+ transit = TRANSIT_WALLPAPER_OPEN;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
+ AppTransition.appTransitionToString(transit));
} else {
mService.mAnimateWallpaperWithTarget = true;
@@ -773,7 +764,7 @@
}
private void processApplicationsAnimatingInPlace(int transit) {
- if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {
+ if (transit == TRANSIT_TASK_IN_PLACE) {
// Find the focused window
final WindowState win = mService.getDefaultDisplayContentLocked().findFocusedWindow();
if (win != null) {
@@ -840,13 +831,14 @@
Rect appRect = win != null ? win.getContentFrameLw() :
new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
Rect insets = win != null ? win.mContentInsets : null;
+ final Configuration displayConfig = displayContent.getConfiguration();
// For the new aspect-scaled transition, we want it to always show
// above the animating opening/closing window, and we want to
// synchronize its thumbnail surface with the surface for the
// open/close animation (only on the way down)
anim = mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
- insets, thumbnailHeader, taskId, mService.mGlobalConfiguration.uiMode,
- mService.mGlobalConfiguration.orientation);
+ insets, thumbnailHeader, taskId, displayConfig.uiMode,
+ displayConfig.orientation);
openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
openingAppAnimator.deferThumbnailDestruction =
!mService.mAppTransition.isNextThumbnailTransitionScaleUp();
@@ -897,6 +889,6 @@
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
- pw.println(prefix + "mObsuringWindow=" + mService.mRoot.mObsuringWindow);
+ pw.println(prefix + "mObscuringWindow=" + mService.mRoot.mObscuringWindow);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 177652c..91eab14 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -24,6 +24,7 @@
import java.io.PrintWriter;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_SCRIM;
@@ -77,12 +78,16 @@
// windows will be put to the bottom of the list.
boolean sendingToBottom;
- WindowToken(WindowManagerService service, IBinder _token, int type, boolean _explicit) {
+ // The display this token is on.
+ private DisplayContent mDisplayContent;
+
+ WindowToken(WindowManagerService service, IBinder _token, int type, boolean _explicit,
+ DisplayContent dc) {
mService = service;
token = _token;
windowType = type;
explicit = _explicit;
- mService.mTokenMap.put(token, this);
+ onDisplayChanged(dc);
}
void removeAllWindows() {
@@ -188,6 +193,25 @@
}
}
+ void addImeWindow(WindowState win) {
+ int pos = mService.findDesiredInputMethodWindowIndexLocked(true);
+
+ if (pos < 0) {
+ addWindow(win);
+ mService.moveInputMethodDialogsLocked(pos);
+ return;
+ }
+
+ if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ "Adding input method window " + win + " at " + pos);
+ mDisplayContent.addToWindowList(win, pos);
+ if (!mChildren.contains(win)) {
+ addChild(win, null);
+ }
+ mService.mWindowsChanged = true;
+ mService.moveInputMethodDialogsLocked(pos + 1);
+ }
+
/** Return the first window in the token window list that isn't a starting window or null. */
WindowState getFirstNonStartingWindow() {
final int count = mChildren.size();
@@ -217,6 +241,18 @@
return null;
}
+ /** Return true if this token has a window that wants the wallpaper displayed behind it. */
+ boolean windowsCanBeWallpaperTarget() {
+ for (int j = mChildren.size() - 1; j >= 0; j--) {
+ final WindowState w = mChildren.get(j);
+ if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
void hideWallpaperToken(boolean wasDeferred, String reason) {
for (int j = mChildren.size() - 1; j >= 0; j--) {
final WindowState wallpaper = mChildren.get(j);
@@ -387,6 +423,33 @@
return null;
}
+ DisplayContent getDisplayContent() {
+ return mDisplayContent;
+ }
+
+ @Override
+ void removeImmediately() {
+ super.removeImmediately();
+ if (mDisplayContent != null) {
+ mDisplayContent.removeWindowToken(token);
+ mService.mRoot.removeWindowTokenIfPossible(token);
+ }
+ }
+
+ void onDisplayChanged(DisplayContent dc) {
+ if (mDisplayContent == dc) {
+ return;
+ }
+
+ if (mDisplayContent != null) {
+ mDisplayContent.removeWindowToken(token);
+ }
+ mDisplayContent = dc;
+ mDisplayContent.setWindowToken(token, this);
+
+ super.onDisplayChanged(dc);
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("windows="); pw.println(mChildren);
pw.print(prefix); pw.print("windowType="); pw.print(windowType);
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 9459517..d328ade 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -7,7 +7,6 @@
LOCAL_SRC_FILES += \
$(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
$(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
$(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
$(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
$(LOCAL_REL_DIR)/com_android_server_HardwarePropertiesManagerService.cpp \
@@ -65,4 +64,9 @@
libEGL \
libGLESv2 \
libnetutils \
-
+ libhidl \
+ libhwbinder \
+ libutils \
+ android.hardware.power@1.0 \
+ android.hardware.vibrator@1.0 \
+ android.hardware.light@2.0 \
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
deleted file mode 100644
index d004e30..0000000
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You 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.
- */
-
-#define LOG_TAG "AssetAtlasService"
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include "android/graphics/GraphicsJNI.h"
-
-#include <android_view_GraphicBuffer.h>
-#include <cutils/log.h>
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-// Disable warnings for Skia.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wunused-parameter"
-#include <SkCanvas.h>
-#include <SkBitmap.h>
-#pragma GCC diagnostic pop
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-// Defines
-// ----------------------------------------------------------------------------
-
-// Defines how long to wait for the GPU when uploading the atlas
-// This timeout is defined in nanoseconds (see EGL_KHR_fence_sync extension)
-#define FENCE_TIMEOUT 2000000000
-
-// ----------------------------------------------------------------------------
-// Canvas management
-// ----------------------------------------------------------------------------
-
-#define CLEANUP_GL_AND_RETURN(result) \
- if (fence != EGL_NO_SYNC_KHR) eglDestroySyncKHR(display, fence); \
- if (image) eglDestroyImageKHR(display, image); \
- if (texture) glDeleteTextures(1, &texture); \
- if (surface != EGL_NO_SURFACE) eglDestroySurface(display, surface); \
- if (context != EGL_NO_CONTEXT) eglDestroyContext(display, context); \
- eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); \
- eglReleaseThread(); \
- eglTerminate(display); \
- return result;
-
-static jboolean com_android_server_AssetAtlasService_upload(JNIEnv* env, jobject,
- jobject graphicBuffer, jobject bitmapHandle) {
-
- SkBitmap bitmap;
- GraphicsJNI::getSkBitmap(env, bitmapHandle, &bitmap);
- SkAutoLockPixels alp(bitmap);
-
- // The goal of this method is to copy the bitmap into the GraphicBuffer
- // using the GPU to swizzle the texture content
- sp<GraphicBuffer> buffer(graphicBufferForJavaObject(env, graphicBuffer));
-
- if (buffer != NULL) {
- EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (display == EGL_NO_DISPLAY) return JNI_FALSE;
-
- EGLint major;
- EGLint minor;
- if (!eglInitialize(display, &major, &minor)) {
- ALOGW("Could not initialize EGL");
- return JNI_FALSE;
- }
-
- // We're going to use a 1x1 pbuffer surface later on
- // The configuration doesn't really matter for what we're trying to do
- EGLint configAttrs[] = {
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 0,
- EGL_DEPTH_SIZE, 0,
- EGL_STENCIL_SIZE, 0,
- EGL_NONE
- };
- EGLConfig configs[1];
- EGLint configCount;
- if (!eglChooseConfig(display, configAttrs, configs, 1, &configCount)) {
- ALOGW("Could not select EGL configuration");
- eglReleaseThread();
- eglTerminate(display);
- return JNI_FALSE;
- }
- if (configCount <= 0) {
- ALOGW("Could not find EGL configuration");
- eglReleaseThread();
- eglTerminate(display);
- return JNI_FALSE;
- }
-
- // These objects are initialized below but the default "null"
- // values are used to cleanup properly at any point in the
- // initialization sequence
- GLuint texture = 0;
- EGLImageKHR image = EGL_NO_IMAGE_KHR;
- EGLSurface surface = EGL_NO_SURFACE;
- EGLSyncKHR fence = EGL_NO_SYNC_KHR;
-
- EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
- EGLContext context = eglCreateContext(display, configs[0], EGL_NO_CONTEXT, attrs);
- if (context == EGL_NO_CONTEXT) {
- ALOGW("Could not create EGL context");
- CLEANUP_GL_AND_RETURN(JNI_FALSE);
- }
-
- // Create the 1x1 pbuffer
- EGLint surfaceAttrs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
- surface = eglCreatePbufferSurface(display, configs[0], surfaceAttrs);
- if (surface == EGL_NO_SURFACE) {
- ALOGW("Could not create EGL surface");
- CLEANUP_GL_AND_RETURN(JNI_FALSE);
- }
-
- if (!eglMakeCurrent(display, surface, surface, context)) {
- ALOGW("Could not change current EGL context");
- CLEANUP_GL_AND_RETURN(JNI_FALSE);
- }
-
- // We use an EGLImage to access the content of the GraphicBuffer
- // The EGL image is later bound to a 2D texture
- EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
- EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
- image = eglCreateImageKHR(display, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
- if (image == EGL_NO_IMAGE_KHR) {
- ALOGW("Could not create EGL image");
- CLEANUP_GL_AND_RETURN(JNI_FALSE);
- }
-
- glGenTextures(1, &texture);
- glBindTexture(GL_TEXTURE_2D, texture);
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
- if (glGetError() != GL_NO_ERROR) {
- ALOGW("Could not create/bind texture");
- CLEANUP_GL_AND_RETURN(JNI_FALSE);
- }
-
- // Upload the content of the bitmap in the GraphicBuffer
- glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap.bytesPerPixel());
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
- GL_RGBA, GL_UNSIGNED_BYTE, bitmap.getPixels());
- if (glGetError() != GL_NO_ERROR) {
- ALOGW("Could not upload to texture");
- CLEANUP_GL_AND_RETURN(JNI_FALSE);
- }
-
- // The fence is used to wait for the texture upload to finish
- // properly. We cannot rely on glFlush() and glFinish() as
- // some drivers completely ignore these API calls
- fence = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL);
- if (fence == EGL_NO_SYNC_KHR) {
- ALOGW("Could not create sync fence %#x", eglGetError());
- CLEANUP_GL_AND_RETURN(JNI_FALSE);
- }
-
- // The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
- // pipeline flush (similar to what a glFlush() would do.)
- EGLint waitStatus = eglClientWaitSyncKHR(display, fence,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
- if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
- ALOGW("Failed to wait for the fence %#x", eglGetError());
- CLEANUP_GL_AND_RETURN(JNI_FALSE);
- }
-
- CLEANUP_GL_AND_RETURN(JNI_TRUE);
- }
-
- return JNI_FALSE;
-}
-
-// ----------------------------------------------------------------------------
-// JNI Glue
-// ----------------------------------------------------------------------------
-
-#define FIND_CLASS(var, className) \
- var = env->FindClass(className); \
- LOG_FATAL_IF(! (var), "Unable to find class " className);
-
-#define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \
- var = env->GetMethodID(clazz, methodName, methodDescriptor); \
- LOG_FATAL_IF(!(var), "Unable to find method " methodName);
-
-const char* const kClassPathName = "com/android/server/AssetAtlasService";
-
-static const JNINativeMethod gMethods[] = {
- { "nUploadAtlas", "(Landroid/view/GraphicBuffer;Landroid/graphics/Bitmap;)Z",
- (void*) com_android_server_AssetAtlasService_upload },
-};
-
-int register_android_server_AssetAtlasService(JNIEnv* env) {
- return jniRegisterNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
-}
-
-};
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 03fbd19..cc52260 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -16,6 +16,9 @@
#define LOG_TAG "VibratorService"
+#include <android/hardware/vibrator/1.0/IVibrator.h>
+#include <android/hardware/vibrator/1.0/types.h>
+
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
@@ -26,32 +29,27 @@
#include <stdio.h>
+using android::hardware::getService;
+using android::hardware::vibrator::V1_0::IVibrator;
+using android::hardware::vibrator::V1_0::Status;
+
namespace android
{
-static hw_module_t *gVibraModule = NULL;
-static vibrator_device_t *gVibraDevice = NULL;
+static sp<IVibrator> mHal;
static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
{
- if (gVibraModule != NULL) {
+ /* TODO(b/31632518) */
+ if (mHal != nullptr) {
return;
}
-
- int err = hw_get_module(VIBRATOR_HARDWARE_MODULE_ID, (hw_module_t const**)&gVibraModule);
-
- if (err) {
- ALOGE("Couldn't load %s module (%s)", VIBRATOR_HARDWARE_MODULE_ID, strerror(-err));
- } else {
- if (gVibraModule) {
- vibrator_open(gVibraModule, &gVibraDevice);
- }
- }
+ mHal = IVibrator::getService("vibrator");
}
static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
{
- if (gVibraModule && gVibraDevice) {
+ if (mHal != nullptr) {
return JNI_TRUE;
} else {
return JNI_FALSE;
@@ -60,10 +58,10 @@
static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
{
- if (gVibraDevice) {
- int err = gVibraDevice->vibrator_on(gVibraDevice, timeout_ms);
- if (err != 0) {
- ALOGE("The hw module failed in vibrator_on: %s", strerror(-err));
+ if (mHal != nullptr) {
+ Status retStatus = mHal->on(timeout_ms);
+ if (retStatus == Status::ERR) {
+ ALOGE("vibratorOn command failed.");
}
} else {
ALOGW("Tried to vibrate but there is no vibrator device.");
@@ -72,10 +70,10 @@
static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
{
- if (gVibraDevice) {
- int err = gVibraDevice->vibrator_off(gVibraDevice);
- if (err != 0) {
- ALOGE("The hw module failed in vibrator_off(): %s", strerror(-err));
+ if (mHal != nullptr) {
+ Status retStatus = mHal->off();
+ if (retStatus == Status::ERR) {
+ ALOGE("vibratorOff command failed.");
}
} else {
ALOGW("Tried to stop vibrating but there is no vibrator device.");
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index ecdc71e..b22d5e7 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "BatteryStatsService"
//#define LOG_NDEBUG 0
+#include <android/hardware/power/1.0/IPower.h>
#include <android_runtime/AndroidRuntime.h>
#include <jni.h>
@@ -26,8 +27,6 @@
#include <cutils/log.h>
#include <utils/misc.h>
#include <utils/Log.h>
-#include <hardware/hardware.h>
-#include <hardware/power.h>
#include <suspend/autosuspend.h>
#include <inttypes.h>
@@ -41,6 +40,14 @@
#include <sys/types.h>
#include <unistd.h>
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::power::V1_0::IPower;
+using android::hardware::power::V1_0::PowerStatePlatformSleepState;
+using android::hardware::power::V1_0::PowerStateVoter;
+using android::hardware::power::V1_0::Status;
+using android::hardware::hidl_vec;
+
namespace android
{
@@ -49,7 +56,7 @@
static bool wakeup_init = false;
static sem_t wakeup_sem;
-extern struct power_module* gPowerModule;
+extern sp<IPower> gPowerHal;
static void wakeup_callback(bool success)
{
@@ -174,86 +181,34 @@
}
static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
- int num_modes = -1;
- char *output = (char*)env->GetDirectBufferAddress(outBuf), *offset = output;
+ char *output = (char*)env->GetDirectBufferAddress(outBuf);
+ char *offset = output;
int remaining = (int)env->GetDirectBufferCapacity(outBuf);
- power_state_platform_sleep_state_t *list;
- size_t *voter_list;
int total_added = -1;
if (outBuf == NULL) {
jniThrowException(env, "java/lang/NullPointerException", "null argument");
- goto error;
+ return -1;
}
- if (!gPowerModule) {
- ALOGE("%s: gPowerModule not loaded", POWER_HARDWARE_MODULE_ID);
- goto error;
+ if (gPowerHal == nullptr) {
+ ALOGE("gPowerHal not loaded");
+ return -1;
}
- if (! (gPowerModule->get_platform_low_power_stats && gPowerModule->get_number_of_platform_modes
- && gPowerModule->get_voter_list)) {
- ALOGE("%s: Missing API", POWER_HARDWARE_MODULE_ID);
- goto error;
- }
+ gPowerHal->getPlatformLowPowerStats(
+ [&offset, &remaining, &total_added](hidl_vec<PowerStatePlatformSleepState> states,
+ Status status) {
+ if (status != Status::SUCCESS)
+ return;
+ for (size_t i = 0; i < states.size(); i++) {
+ int added;
+ const PowerStatePlatformSleepState& state = states[i];
- if (gPowerModule->get_number_of_platform_modes) {
- num_modes = gPowerModule->get_number_of_platform_modes(gPowerModule);
- }
-
- if (num_modes < 1) {
- ALOGE("%s: Platform does not even have one low power mode", POWER_HARDWARE_MODULE_ID);
- goto error;
- }
-
- list = (power_state_platform_sleep_state_t *)calloc(num_modes,
- sizeof(power_state_platform_sleep_state_t));
- if (!list) {
- ALOGE("%s: power_state_platform_sleep_state_t allocation failed", POWER_HARDWARE_MODULE_ID);
- goto error;
- }
-
- voter_list = (size_t *)calloc(num_modes, sizeof(*voter_list));
- if (!voter_list) {
- ALOGE("%s: voter_list allocation failed", POWER_HARDWARE_MODULE_ID);
- goto err_free;
- }
-
- gPowerModule->get_voter_list(gPowerModule, voter_list);
-
- for (int i = 0; i < num_modes; i++) {
- list[i].voters = (power_state_voter_t *)calloc(voter_list[i],
- sizeof(power_state_voter_t));
- if (!list[i].voters) {
- ALOGE("%s: voter_t allocation failed", POWER_HARDWARE_MODULE_ID);
- goto err_free;
- }
- }
-
- if (!gPowerModule->get_platform_low_power_stats(gPowerModule, list)) {
- for (int i = 0; i < num_modes; i++) {
- int added;
-
- added = snprintf(offset, remaining,
- "state_%d name=%s time=%" PRIu64 " count=%" PRIu64 " ",
- i + 1, list[i].name, list[i].residency_in_msec_since_boot,
- list[i].total_transitions);
- if (added < 0) {
- break;
- }
- if (added > remaining) {
- added = remaining;
- }
- offset += added;
- remaining -= added;
- total_added += added;
-
- for (unsigned int j = 0; j < list[i].number_of_voters; j++) {
added = snprintf(offset, remaining,
- "voter_%d name=%s time=%" PRIu64 " count=%" PRIu64 " ",
- j + 1, list[i].voters[j].name,
- list[i].voters[j].total_time_in_msec_voted_for_since_boot,
- list[i].voters[j].total_number_of_times_voted_since_boot);
+ "state_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " ",
+ i + 1, state.name.c_str(), state.residencyInMsecSinceBoot,
+ state.totalTransitions);
if (added < 0) {
break;
}
@@ -263,27 +218,37 @@
offset += added;
remaining -= added;
total_added += added;
- }
- if (remaining <= 0) {
- /* rewrite NULL character*/
- offset--;
- total_added--;
- ALOGE("%s module: buffer not enough", POWER_HARDWARE_MODULE_ID);
- break;
+ for (size_t j = 0; j < state.voters.size(); j++) {
+ const PowerStateVoter& voter = state.voters[j];
+ added = snprintf(offset, remaining,
+ "voter_%zu name=%s time=%" PRIu64 " count=%" PRIu64 " ",
+ j + 1, voter.name.c_str(),
+ voter.totalTimeInMsecVotedForSinceBoot,
+ voter.totalNumberOfTimesVotedSinceBoot);
+ if (added < 0) {
+ break;
+ }
+ if (added > remaining) {
+ added = remaining;
+ }
+ offset += added;
+ remaining -= added;
+ total_added += added;
+ }
+
+ if (remaining <= 0) {
+ /* rewrite NULL character*/
+ offset--;
+ total_added--;
+ ALOGE("PowerHal: buffer not enough");
+ break;
+ }
}
}
- }
+ );
*offset = 0;
total_added += 1;
-
-err_free:
- for (int i = 0; i < num_modes; i++) {
- free(list[i].voters);
- }
- free(list);
- free(voter_list);
-error:
return total_added;
}
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index c8e3946..e6072bb 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -20,136 +20,105 @@
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
+#include <android/hardware/light/2.0/ILight.h>
+#include <android/hardware/light/2.0/types.h>
#include <utils/misc.h>
#include <utils/Log.h>
-#include <hardware/hardware.h>
-#include <hardware/lights.h>
-
+#include <map>
#include <stdio.h>
-namespace android
-{
+namespace android {
-// These values must correspond with the LIGHT_ID constants in
-// LightsService.java
-enum {
- LIGHT_INDEX_BACKLIGHT = 0,
- LIGHT_INDEX_KEYBOARD = 1,
- LIGHT_INDEX_BUTTONS = 2,
- LIGHT_INDEX_BATTERY = 3,
- LIGHT_INDEX_NOTIFICATIONS = 4,
- LIGHT_INDEX_ATTENTION = 5,
- LIGHT_INDEX_BLUETOOTH = 6,
- LIGHT_INDEX_WIFI = 7,
- LIGHT_COUNT
-};
+using ILight = ::android::hardware::light::V2_0::ILight;
+using Brightness = ::android::hardware::light::V2_0::Brightness;
+using Flash = ::android::hardware::light::V2_0::Flash;
+using Type = ::android::hardware::light::V2_0::Type;
+using LightState = ::android::hardware::light::V2_0::LightState;
-struct Devices {
- light_device_t* lights[LIGHT_COUNT];
-};
+static sp<ILight> gLight;
-static light_device_t* get_device(hw_module_t* module, char const* name)
-{
- int err;
- hw_device_t* device;
- err = module->methods->open(module, name, &device);
- if (err == 0) {
- return (light_device_t*)device;
- } else {
- return NULL;
- }
-}
+static bool validate(jint light, jint flash, jint brightness) {
+ bool valid = true;
-static jlong init_native(JNIEnv* /* env */, jobject /* clazz */)
-{
- int err;
- hw_module_t* module;
- Devices* devices;
-
- devices = (Devices*)malloc(sizeof(Devices));
-
- err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
- if (err == 0) {
- devices->lights[LIGHT_INDEX_BACKLIGHT]
- = get_device(module, LIGHT_ID_BACKLIGHT);
- devices->lights[LIGHT_INDEX_KEYBOARD]
- = get_device(module, LIGHT_ID_KEYBOARD);
- devices->lights[LIGHT_INDEX_BUTTONS]
- = get_device(module, LIGHT_ID_BUTTONS);
- devices->lights[LIGHT_INDEX_BATTERY]
- = get_device(module, LIGHT_ID_BATTERY);
- devices->lights[LIGHT_INDEX_NOTIFICATIONS]
- = get_device(module, LIGHT_ID_NOTIFICATIONS);
- devices->lights[LIGHT_INDEX_ATTENTION]
- = get_device(module, LIGHT_ID_ATTENTION);
- devices->lights[LIGHT_INDEX_BLUETOOTH]
- = get_device(module, LIGHT_ID_BLUETOOTH);
- devices->lights[LIGHT_INDEX_WIFI]
- = get_device(module, LIGHT_ID_WIFI);
- } else {
- memset(devices, 0, sizeof(Devices));
+ if (light < 0 || light >= static_cast<int>(Type::COUNT)) {
+ ALOGE("Invalid light parameter %d.", light);
+ valid = false;
}
- return (jlong)devices;
+ if (flash != static_cast<int>(Flash::NONE) &&
+ flash != static_cast<int>(Flash::TIMED) &&
+ flash != static_cast<int>(Flash::HARDWARE)) {
+ ALOGE("Invalid flash parameter %d.", flash);
+ valid = false;
+ }
+
+ if (brightness != static_cast<int>(Brightness::USER) &&
+ brightness != static_cast<int>(Brightness::SENSOR) &&
+ brightness != static_cast<int>(Brightness::LOW_PERSISTENCE)) {
+ ALOGE("Invalid brightness parameter %d.", brightness);
+ valid = false;
+ }
+
+ return valid;
}
-static void finalize_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr)
-{
- Devices* devices = (Devices*)ptr;
- if (devices == NULL) {
+static void setLight_native(
+ JNIEnv* /* env */,
+ jobject /* clazz */,
+ jint light,
+ jint colorARGB,
+ jint flashMode,
+ jint onMS,
+ jint offMS,
+ jint brightnessMode) {
+
+ if (!validate(light, flashMode, brightnessMode)) {
return;
}
- free(devices);
-}
-
-static void setLight_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr,
- jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode)
-{
- Devices* devices = (Devices*)ptr;
- light_state_t state;
-
- if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {
- return ;
+ // TODO(b/31632518)
+ if (gLight == nullptr) {
+ gLight = ILight::getService("light");
}
- uint32_t version = devices->lights[light]->common.version;
+ if (gLight == nullptr) {
+ ALOGE("LightService unable to get ILight interface.");
+ return;
+ }
- memset(&state, 0, sizeof(light_state_t));
+ Type type = static_cast<Type>(light);
+ Flash flash = static_cast<Flash>(flashMode);
+ Brightness brightness = static_cast<Brightness>(brightnessMode);
- if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
- if (light != LIGHT_INDEX_BACKLIGHT) {
+ LightState state{};
+
+ if (brightnessMode == static_cast<int>(Brightness::LOW_PERSISTENCE)) {
+ if (light != static_cast<int>(Type::BACKLIGHT)) {
ALOGE("Cannot set low-persistence mode for non-backlight device.");
return;
}
- if (version < LIGHTS_DEVICE_API_VERSION_2_0) {
- // HAL impl has not been upgraded to support this.
- return;
- }
+ state.flashMode = Flash::NONE;
} else {
// Only set non-brightness settings when not in low-persistence mode
state.color = colorARGB;
- state.flashMode = flashMode;
- state.flashOnMS = onMS;
- state.flashOffMS = offMS;
+ state.flashMode = flash;
+ state.flashOnMs = onMS;
+ state.flashOffMs = offMS;
}
- state.brightnessMode = brightnessMode;
+ state.brightnessMode = brightness;
{
ALOGD_IF_SLOW(50, "Excessive delay setting light");
- devices->lights[light]->set_light(devices->lights[light], &state);
+ gLight->setLight(type, state);
}
}
static const JNINativeMethod method_table[] = {
- { "init_native", "()J", (void*)init_native },
- { "finalize_native", "(J)V", (void*)finalize_native },
- { "setLight_native", "(JIIIIII)V", (void*)setLight_native },
+ { "setLight_native", "(IIIIII)V", (void*)setLight_native },
};
-int register_android_server_LightsService(JNIEnv *env)
-{
+int register_android_server_LightsService(JNIEnv *env) {
return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
method_table, NELEM(method_table));
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e8d4c58..25e819c 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1087,6 +1087,7 @@
method_name,
"([B)V");
env_->CallVoidMethod(object_, method, array);
+ env_->DeleteLocalRef(array);
}
jobject JavaObject::get() {
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 048ef76..b2372a3 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
+#include <android/hardware/power/1.0/IPower.h>
#include "JNIHelp.h"
#include "jni.h"
@@ -37,6 +38,13 @@
#include "com_android_server_power_PowerManagerService.h"
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::power::V1_0::IPower;
+using android::hardware::power::V1_0::PowerHint;
+using android::hardware::power::V1_0::Feature;
+using android::hardware::hidl_vec;
+
namespace android {
// ----------------------------------------------------------------------------
@@ -48,8 +56,7 @@
// ----------------------------------------------------------------------------
static jobject gPowerManagerServiceObj;
-struct power_module* gPowerModule;
-
+sp<IPower> gPowerHal;
static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
// Throttling interval for user activity calls.
@@ -69,8 +76,8 @@
void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
// Tell the power HAL when user activity occurs.
- if (gPowerModule && gPowerModule->powerHint) {
- gPowerModule->powerHint(gPowerModule, POWER_HINT_INTERACTION, NULL);
+ if (gPowerHal != nullptr) {
+ gPowerHal->powerHint(PowerHint::INTERACTION, 0);
}
if (gPowerManagerServiceObj) {
@@ -99,16 +106,13 @@
}
// ----------------------------------------------------------------------------
-
+//TODO(b/31632518)
static void nativeInit(JNIEnv* env, jobject obj) {
gPowerManagerServiceObj = env->NewGlobalRef(obj);
- status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID,
- (hw_module_t const**)&gPowerModule);
- if (!err) {
- gPowerModule->init(gPowerModule);
- } else {
- ALOGE("Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err));
+ gPowerHal = IPower::getService("power");
+ if (gPowerHal == nullptr) {
+ ALOGE("Couldn't load PowerHAL module");
}
}
@@ -123,13 +127,13 @@
}
static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
- if (gPowerModule) {
+ if (gPowerHal != nullptr) {
if (enable) {
ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(true) while turning screen on");
- gPowerModule->setInteractive(gPowerModule, true);
+ gPowerHal->setInteractive(true);
} else {
ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(false) while turning screen off");
- gPowerModule->setInteractive(gPowerModule, false);
+ gPowerHal->setInteractive(false);
}
}
}
@@ -145,13 +149,11 @@
}
static void nativeSendPowerHint(JNIEnv *env, jclass clazz, jint hintId, jint data) {
- int data_param = data;
-
- if (gPowerModule && gPowerModule->powerHint) {
+ if (gPowerHal != nullptr) {
if(data)
- gPowerModule->powerHint(gPowerModule, (power_hint_t)hintId, &data_param);
+ gPowerHal->powerHint((PowerHint)hintId, data);
else {
- gPowerModule->powerHint(gPowerModule, (power_hint_t)hintId, NULL);
+ gPowerHal->powerHint((PowerHint)hintId, 0);
}
}
}
@@ -159,8 +161,8 @@
static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint data) {
int data_param = data;
- if (gPowerModule && gPowerModule->setFeature) {
- gPowerModule->setFeature(gPowerModule, (feature_t)featureId, data_param);
+ if (gPowerHal != nullptr) {
+ gPowerHal->setFeature((Feature)featureId, data_param ? true : false);
}
}
@@ -215,7 +217,7 @@
gLastEventTime[i] = LLONG_MIN;
}
gPowerManagerServiceObj = NULL;
- gPowerModule = NULL;
+ gPowerHal = NULL;
return 0;
}
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 327019d..d69c37f 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -21,7 +21,6 @@
namespace android {
int register_android_server_AlarmManagerService(JNIEnv* env);
-int register_android_server_AssetAtlasService(JNIEnv* env);
int register_android_server_BatteryStatsService(JNIEnv* env);
int register_android_server_ConsumerIrService(JNIEnv *env);
int register_android_server_InputApplicationHandle(JNIEnv* env);
@@ -76,7 +75,6 @@
register_android_server_location_GnssLocationProvider(env);
register_android_server_location_FlpHardwareProvider(env);
register_android_server_connectivity_Vpn(env);
- register_android_server_AssetAtlasService(env);
register_android_server_ConsumerIrService(env);
register_android_server_BatteryStatsService(env);
register_android_server_hdmi_HdmiCecController(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0c57179..88d8dd0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -221,6 +221,7 @@
private static final String ATTR_PERMISSION_POLICY = "permission-policy";
private static final String ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED =
"device-provisioning-config-applied";
+ private static final String ATTR_DEVICE_PAIRED = "device-paired";
private static final String ATTR_DELEGATED_CERT_INSTALLER = "delegated-cert-installer";
private static final String ATTR_APPLICATION_RESTRICTIONS_MANAGER
@@ -301,6 +302,7 @@
private static final int CODE_NONSYSTEM_USER_EXISTS = 5;
private static final int CODE_ACCOUNTS_NOT_EMPTY = 6;
private static final int CODE_NOT_SYSTEM_USER = 7;
+ private static final int CODE_HAS_PAIRED = 8;
@Retention(RetentionPolicy.SOURCE)
@IntDef({ CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING,
@@ -344,6 +346,11 @@
*/
boolean mHasFeature;
+ /**
+ * Whether or not this device is a watch.
+ */
+ boolean mIsWatch;
+
private final SecurityLogMonitor mSecurityLogMonitor;
private final AtomicBoolean mRemoteBugreportServiceIsActive = new AtomicBoolean();
@@ -424,6 +431,7 @@
int mPasswordOwner = -1;
long mLastMaximumTimeToLock = -1;
boolean mUserSetupComplete = false;
+ boolean mPaired = false;
int mUserProvisioningState;
int mPermissionPolicy;
@@ -496,12 +504,6 @@
}
});
}
- // STOPSHIP: Remove this code once all dogfood devices are fixed. See b/31754835
- if (Intent.ACTION_BOOT_COMPLETED.equals(action) && !mOwners.hasDeviceOwner()
- && !isBackupServiceEnabledInternal()) {
- setBackupServiceEnabledInternal(true);
- Slog.w(LOG_TAG, "Fix backup for device that is not in Device Owner mode.");
- }
if (Intent.ACTION_USER_UNLOCKED.equals(action)
|| Intent.ACTION_USER_STARTED.equals(action)
|| KeyChain.ACTION_TRUST_STORE_CHANGED.equals(action)) {
@@ -617,7 +619,7 @@
static final long DEF_MAXIMUM_TIME_TO_UNLOCK = 0;
long maximumTimeToUnlock = DEF_MAXIMUM_TIME_TO_UNLOCK;
- long strongAuthUnlockTimeout = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+ long strongAuthUnlockTimeout = 0; // admin doesn't participate by default
static final int DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE = 0;
int maximumFailedPasswordsForWipe = DEF_MAXIMUM_FAILED_PASSWORDS_FOR_WIPE;
@@ -1621,6 +1623,8 @@
mHasFeature = mContext.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
+ mIsWatch = mContext.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_WATCH);
if (!mHasFeature) {
// Skip the rest of the initialization
return;
@@ -2221,6 +2225,10 @@
out.attribute(null, ATTR_SETUP_COMPLETE,
Boolean.toString(true));
}
+ if (policy.mPaired) {
+ out.attribute(null, ATTR_DEVICE_PAIRED,
+ Boolean.toString(true));
+ }
if (policy.mDeviceProvisioningConfigApplied) {
out.attribute(null, ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED,
Boolean.toString(true));
@@ -2385,6 +2393,10 @@
if (userSetupComplete != null && Boolean.toString(true).equals(userSetupComplete)) {
policy.mUserSetupComplete = true;
}
+ String paired = parser.getAttributeValue(null, ATTR_DEVICE_PAIRED);
+ if (paired != null && Boolean.toString(true).equals(paired)) {
+ policy.mPaired = true;
+ }
String deviceProvisioningConfigApplied = parser.getAttributeValue(null,
ATTR_DEVICE_PROVISIONING_CONFIG_APPLIED);
if (deviceProvisioningConfigApplied != null
@@ -2619,7 +2631,7 @@
// Register an observer for watching for user setup complete.
new SetupContentObserver(mHandler).register();
// Initialize the user setup state, to handle the upgrade case.
- updateUserSetupComplete();
+ updateUserSetupCompleteAndPaired();
List<String> packageList;
synchronized (this) {
@@ -4254,10 +4266,15 @@
return;
}
Preconditions.checkNotNull(who, "ComponentName is null");
- Preconditions.checkArgument(timeoutMs >= MINIMUM_STRONG_AUTH_TIMEOUT_MS,
- "Timeout must not be lower than the minimum strong auth timeout.");
- Preconditions.checkArgument(timeoutMs <= DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS,
- "Timeout must not be higher than the default strong auth timeout.");
+ Preconditions.checkArgument(timeoutMs >= 0, "Timeout must not be a negative number.");
+ // timeoutMs with value 0 means that the admin doesn't participate
+ // timeoutMs is clamped to the interval in case the internal constants change in the future
+ if (timeoutMs != 0 && timeoutMs < MINIMUM_STRONG_AUTH_TIMEOUT_MS) {
+ timeoutMs = MINIMUM_STRONG_AUTH_TIMEOUT_MS;
+ }
+ if (timeoutMs > DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS) {
+ timeoutMs = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+ }
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (this) {
@@ -4273,7 +4290,7 @@
/**
* Return a single admin's strong auth unlock timeout or minimum value (strictest) of all
* admins if who is null.
- * Returns default timeout if not configured.
+ * Returns 0 if not configured for the provided admin.
*/
@Override
public long getRequiredStrongAuthTimeout(ComponentName who, int userId, boolean parent) {
@@ -4284,9 +4301,7 @@
synchronized (this) {
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userId, parent);
- return admin != null ? Math.max(admin.strongAuthUnlockTimeout,
- MINIMUM_STRONG_AUTH_TIMEOUT_MS)
- : DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
+ return admin != null ? admin.strongAuthUnlockTimeout : 0;
}
// Return the strictest policy across all participating admins.
@@ -4294,8 +4309,10 @@
long strongAuthUnlockTimeout = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS;
for (int i = 0; i < admins.size(); i++) {
- strongAuthUnlockTimeout = Math.min(admins.get(i).strongAuthUnlockTimeout,
- strongAuthUnlockTimeout);
+ final long timeout = admins.get(i).strongAuthUnlockTimeout;
+ if (timeout != 0) { // take only participating admins into account
+ strongAuthUnlockTimeout = Math.min(timeout, strongAuthUnlockTimeout);
+ }
}
return Math.max(strongAuthUnlockTimeout, MINIMUM_STRONG_AUTH_TIMEOUT_MS);
}
@@ -6152,6 +6169,13 @@
return getUserData(userHandle).mUserSetupComplete;
}
+ private boolean hasPaired(int userHandle) {
+ if (!mHasFeature) {
+ return true;
+ }
+ return getUserData(userHandle).mPaired;
+ }
+
@Override
public int getUserProvisioningState() {
if (!mHasFeature) {
@@ -6436,6 +6460,9 @@
case CODE_ACCOUNTS_NOT_EMPTY:
throw new IllegalStateException("Not allowed to set the device owner because there "
+ "are already some accounts on the device");
+ case CODE_HAS_PAIRED:
+ throw new IllegalStateException("Not allowed to set the device owner because this "
+ + "device has already paired");
default:
throw new IllegalStateException("Unknown @DeviceOwnerPreConditionCode " + code);
}
@@ -8187,14 +8214,15 @@
}
/**
- * We need to update the internal state of whether a user has completed setup once. After
- * that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes
- * as we don't trust any apps that might try to reset it.
+ * We need to update the internal state of whether a user has completed setup or a
+ * device has paired once. After that, we ignore any changes that reset the
+ * Settings.Secure.USER_SETUP_COMPLETE or Settings.Secure.DEVICE_PAIRED change
+ * as we don't trust any apps that might try to reset them.
* <p>
* Unfortunately, we don't know which user's setup state was changed, so we write all of
* them.
*/
- void updateUserSetupComplete() {
+ void updateUserSetupCompleteAndPaired() {
List<UserInfo> users = mUserManager.getUsers(true);
final int N = users.size();
for (int i = 0; i < N; i++) {
@@ -8209,6 +8237,16 @@
}
}
}
+ if (mIsWatch && mInjector.settingsSecureGetIntForUser(Settings.Secure.DEVICE_PAIRED, 0,
+ userHandle) != 0) {
+ DevicePolicyData policy = getUserData(userHandle);
+ if (!policy.mPaired) {
+ policy.mPaired = true;
+ synchronized (this) {
+ saveSettingsLocked(userHandle);
+ }
+ }
+ }
}
}
@@ -8218,6 +8256,7 @@
Settings.Secure.USER_SETUP_COMPLETE);
private final Uri mDeviceProvisioned = Settings.Global.getUriFor(
Settings.Global.DEVICE_PROVISIONED);
+ private final Uri mPaired = Settings.Secure.getUriFor(Settings.Secure.DEVICE_PAIRED);
public SetupContentObserver(Handler handler) {
super(handler);
@@ -8226,12 +8265,15 @@
void register() {
mInjector.registerContentObserver(mUserSetupComplete, false, this, UserHandle.USER_ALL);
mInjector.registerContentObserver(mDeviceProvisioned, false, this, UserHandle.USER_ALL);
+ if (mIsWatch) {
+ mInjector.registerContentObserver(mPaired, false, this, UserHandle.USER_ALL);
+ }
}
@Override
public void onChange(boolean selfChange, Uri uri) {
- if (mUserSetupComplete.equals(uri)) {
- updateUserSetupComplete();
+ if (mUserSetupComplete.equals(uri) || (mIsWatch && mPaired.equals(uri))) {
+ updateUserSetupCompleteAndPaired();
} else if (mDeviceProvisioned.equals(uri)) {
synchronized (DevicePolicyManagerService.this) {
// Set PROPERTY_DEVICE_OWNER_PRESENT, for the SUW case where setting the property
@@ -8540,15 +8582,16 @@
final PackageManager packageManager = mContext.getPackageManager();
switch (grantState) {
case DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED: {
- packageManager.grantRuntimePermission(packageName, permission, user);
+ mInjector.getPackageManagerInternal().grantRuntimePermission(packageName,
+ permission, user.getIdentifier(), true /* override policy */);
packageManager.updatePermissionFlags(permission, packageName,
PackageManager.FLAG_PERMISSION_POLICY_FIXED,
PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
} break;
case DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED: {
- packageManager.revokeRuntimePermission(packageName,
- permission, user);
+ mInjector.getPackageManagerInternal().revokeRuntimePermission(packageName,
+ permission, user.getIdentifier(), true /* override policy */);
packageManager.updatePermissionFlags(permission, packageName,
PackageManager.FLAG_PERMISSION_POLICY_FIXED,
PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
@@ -8620,19 +8663,13 @@
}
synchronized (this) {
if (mOwners.hasDeviceOwner()) {
- if (!mInjector.userManagerIsSplitSystemUser()) {
- // Only split-system-user systems support managed-profiles in combination with
- // device-owner.
- return false;
- }
- if (mOwners.getDeviceOwnerUserId() != UserHandle.USER_SYSTEM) {
- // Only system device-owner supports managed-profiles. Non-system device-owner
- // doesn't.
- return false;
- }
- if (callingUserId == UserHandle.USER_SYSTEM) {
- // Managed-profiles cannot be setup on the system user, only regular users.
- return false;
+ // STOPSHIP Only allow creating a managed profile if allowed by the device
+ // owner. http://b/31952368
+ if (mInjector.userManagerIsSplitSystemUser()) {
+ if (callingUserId == UserHandle.USER_SYSTEM) {
+ // Managed-profiles cannot be setup on the system user.
+ return false;
+ }
}
}
}
@@ -8692,6 +8729,9 @@
if (!mUserManager.isUserRunning(new UserHandle(deviceOwnerUserId))) {
return CODE_USER_NOT_RUNNING;
}
+ if (mIsWatch && hasPaired(UserHandle.USER_SYSTEM)) {
+ return CODE_HAS_PAIRED;
+ }
if (isAdb) {
// if shell command runs after user setup completed check device status. Otherwise, OK.
if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
@@ -9357,16 +9397,13 @@
return true;
}
synchronized (this) {
- getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
- return isBackupServiceEnabledInternal();
- }
- }
- private boolean isBackupServiceEnabledInternal() {
- try {
- IBackupManager ibm = mInjector.getIBackupManager();
- return ibm != null && ibm.isBackupServiceActive(UserHandle.USER_SYSTEM);
- } catch (RemoteException e) {
- throw new IllegalStateException("Failed requesting backup service state.", e);
+ try {
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ IBackupManager ibm = mInjector.getIBackupManager();
+ return ibm != null && ibm.isBackupServiceActive(UserHandle.USER_SYSTEM);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed requesting backup service state.", e);
+ }
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index aba4dc0..deb5238 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -747,7 +747,6 @@
LocationManagerService location = null;
CountryDetectorService countryDetector = null;
ILockSettings lockSettings = null;
- AssetAtlasService atlas = null;
MediaRouterService mediaRouter = null;
// Bring up services needed for UI.
@@ -859,12 +858,7 @@
if (!disableNonCoreServices) {
traceBeginAndSlog("StartClipboardService");
- try {
- ServiceManager.addService(Context.CLIPBOARD_SERVICE,
- new ClipboardService(context));
- } catch (Throwable e) {
- reportWtf("starting Clipboard Service", e);
- }
+ mSystemServiceManager.startService(ClipboardService.class);
traceEnd();
}
@@ -1240,17 +1234,6 @@
traceEnd();
}
- if (!disableNonCoreServices && ZygoteInit.PRELOAD_RESOURCES) {
- traceBeginAndSlog("StartAssetAtlasService");
- try {
- atlas = new AssetAtlasService(context);
- ServiceManager.addService(AssetAtlasService.ASSET_ATLAS_SERVICE, atlas);
- } catch (Throwable e) {
- reportWtf("starting AssetAtlasService", e);
- }
- traceEnd();
- }
-
if (!disableNonCoreServices) {
traceBeginAndSlog("AddGraphicsStatsService");
ServiceManager.addService(GraphicsStatsService.GRAPHICS_STATS_SERVICE,
@@ -1372,12 +1355,9 @@
mmsService = mSystemServiceManager.startService(MmsServiceBroker.class);
traceEnd();
- if (Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0 ||
- UserManager.isDeviceInDemoMode(mSystemContext)) {
- traceBeginAndSlog("StartRetailDemoModeService");
- mSystemServiceManager.startService(RetailDemoModeService.class);
- traceEnd();
- }
+ traceBeginAndSlog("StartRetailDemoModeService");
+ mSystemServiceManager.startService(RetailDemoModeService.class);
+ traceEnd();
// It is now time to start up the app processes...
@@ -1473,7 +1453,6 @@
final CountryDetectorService countryDetectorF = countryDetector;
final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;
- final AssetAtlasService atlasF = atlas;
final InputManagerService inputManagerF = inputManager;
final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
final MediaRouterService mediaRouterF = mediaRouter;
@@ -1591,13 +1570,6 @@
reportWtf("Notifying CommonTimeManagementService running", e);
}
traceEnd();
- traceBeginAndSlog("MakeAtlasServiceReady");
- try {
- if (atlasF != null) atlasF.systemRunning();
- } catch (Throwable e) {
- reportWtf("Notifying AssetAtlasService running", e);
- }
- traceEnd();
traceBeginAndSlog("MakeInputManagerServiceReady");
try {
// TODO(BT) Pass parameter to input manager
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 4c75452..a8356dc 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -283,14 +283,20 @@
mReceiveThread.start();
}
- // Returns seconds since Unix Epoch.
- // TODO: use SystemClock.elapsedRealtime() instead
+ // Returns seconds since device boot.
private static long curTime() {
- return System.currentTimeMillis() / DateUtils.SECOND_IN_MILLIS;
+ return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
+ }
+
+ public static class InvalidRaException extends Exception {
+ public InvalidRaException(String m) {
+ super(m);
+ }
}
// A class to hold information about an RA.
- private class Ra {
+ @VisibleForTesting
+ class Ra {
// From RFC4861:
private static final int ICMP6_RA_HEADER_LEN = 16;
private static final int ICMP6_RA_CHECKSUM_OFFSET =
@@ -362,7 +368,7 @@
} catch (UnsupportedOperationException e) {
// array() failed. Cannot happen, mPacket is array-backed and read-write.
return "???";
- } catch (ClassCastException | UnknownHostException e) {
+ } catch (ClassCastException|UnknownHostException e) {
// Cannot happen.
return "???";
}
@@ -372,16 +378,16 @@
// TODO: Make this static once RA is its own class.
private void prefixOptionToString(StringBuffer sb, int offset) {
String prefix = IPv6AddresstoString(offset + 16);
- int length = uint8(mPacket.get(offset + 2));
- long valid = mPacket.getInt(offset + 4);
- long preferred = mPacket.getInt(offset + 8);
+ int length = getUint8(mPacket, offset + 2);
+ long valid = getUint32(mPacket, offset + 4);
+ long preferred = getUint32(mPacket, offset + 8);
sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
}
private void rdnssOptionToString(StringBuffer sb, int offset) {
- int optLen = uint8(mPacket.get(offset + 1)) * 8;
+ int optLen = getUint8(mPacket, offset + 1) * 8;
if (optLen < 24) return; // Malformed or empty.
- long lifetime = uint32(mPacket.getInt(offset + 4));
+ long lifetime = getUint32(mPacket, offset + 4);
int numServers = (optLen - 8) / 16;
sb.append("DNS ").append(lifetime).append("s");
for (int server = 0; server < numServers; server++) {
@@ -395,7 +401,7 @@
sb.append(String.format("RA %s -> %s %ds ",
IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
- uint16(mPacket.getShort(ICMP6_RA_ROUTER_LIFETIME_OFFSET))));
+ getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
for (int i: mPrefixOptionOffsets) {
prefixOptionToString(sb, i);
}
@@ -403,7 +409,7 @@
rdnssOptionToString(sb, i);
}
return sb.toString();
- } catch (BufferUnderflowException | IndexOutOfBoundsException e) {
+ } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
return "<Malformed RA>";
}
}
@@ -436,16 +442,20 @@
// Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
// (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
// specifications.
- Ra(byte[] packet, int length) {
+ Ra(byte[] packet, int length) throws InvalidRaException {
+ if (length < ICMP6_RA_OPTION_OFFSET) {
+ throw new InvalidRaException("Not an ICMP6 router advertisement");
+ }
+
mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
mLastSeen = curTime();
// Sanity check packet in case a packet arrives before we attach RA filter
// to our packet socket. b/29586253
if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
- uint8(mPacket.get(IPV6_NEXT_HEADER_OFFSET)) != IPPROTO_ICMPV6 ||
- uint8(mPacket.get(ICMP6_TYPE_OFFSET)) != ICMP6_ROUTER_ADVERTISEMENT) {
- throw new IllegalArgumentException("Not an ICMP6 router advertisement");
+ getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
+ getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMP6_ROUTER_ADVERTISEMENT) {
+ throw new InvalidRaException("Not an ICMP6 router advertisement");
}
@@ -466,8 +476,8 @@
mPacket.position(ICMP6_RA_OPTION_OFFSET);
while (mPacket.hasRemaining()) {
final int position = mPacket.position();
- final int optionType = uint8(mPacket.get(position));
- final int optionLength = uint8(mPacket.get(position + 1)) * 8;
+ final int optionType = getUint8(mPacket, position);
+ final int optionLength = getUint8(mPacket, position + 1) * 8;
long lifetime;
switch (optionType) {
case ICMP6_PREFIX_OPTION_TYPE:
@@ -511,7 +521,7 @@
break;
}
if (optionLength <= 0) {
- throw new IllegalArgumentException(String.format(
+ throw new InvalidRaException(String.format(
"Invalid option length opt=%d len=%d", optionType, optionLength));
}
mPacket.position(position + optionLength);
@@ -552,10 +562,10 @@
final long optionLifetime;
switch (lifetimeLength) {
case 2:
- optionLifetime = uint16(byteBuffer.getShort(offset));
+ optionLifetime = getUint16(byteBuffer, offset);
break;
case 4:
- optionLifetime = uint32(byteBuffer.getInt(offset));
+ optionLifetime = getUint32(byteBuffer, offset);
break;
default:
throw new IllegalStateException("bogus lifetime size " + lifetimeLength);
@@ -925,8 +935,8 @@
// Execution will reach the end of the program if no filters match, which will pass the
// packet to the AP.
program = gen.generate();
- } catch (IllegalInstructionException e) {
- Log.e(TAG, "Program failed to generate: ", e);
+ } catch (IllegalInstructionException|IllegalStateException e) {
+ Log.e(TAG, "Failed to generate APF program.", e);
return;
}
mLastTimeInstalledProgram = curTime();
@@ -972,7 +982,8 @@
* if the current APF program should be updated.
* @return a ProcessRaResult enum describing what action was performed.
*/
- private synchronized ProcessRaResult processRa(byte[] packet, int length) {
+ @VisibleForTesting
+ synchronized ProcessRaResult processRa(byte[] packet, int length) {
if (VDBG) hexDump("Read packet = ", packet, length);
// Have we seen this RA before?
@@ -1011,7 +1022,7 @@
try {
ra = new Ra(packet, length);
} catch (Exception e) {
- Log.e(TAG, "Error parsing RA: " + e);
+ Log.e(TAG, "Error parsing RA", e);
return ProcessRaResult.PARSE_ERROR;
}
// Ignore 0 lifetime RAs.
@@ -1150,7 +1161,11 @@
return i & 0xffffffffL;
}
- private static long getUint16(ByteBuffer buffer, int position) {
+ private static int getUint8(ByteBuffer buffer, int position) {
+ return uint8(buffer.get(position));
+ }
+
+ private static int getUint16(ByteBuffer buffer, int position) {
return uint16(buffer.getShort(position));
}
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index 9aa66fe..ef4bc02 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -7,6 +7,7 @@
import android.os.Build;
import android.os.SystemProperties;
import android.system.OsConstants;
+import com.android.internal.annotations.VisibleForTesting;
import java.io.UnsupportedEncodingException;
import java.net.Inet4Address;
@@ -14,9 +15,8 @@
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.nio.charset.StandardCharsets;
import java.nio.ShortBuffer;
-
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -725,7 +725,8 @@
* A subset of the optional parameters are parsed and are stored
* in object fields.
*/
- public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
+ @VisibleForTesting
+ static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
{
// bootp parameters
int transactionId;
@@ -894,8 +895,12 @@
+ 64 // skip server host name (64 chars)
+ 128); // skip boot file name (128 chars)
- int dhcpMagicCookie = packet.getInt();
+ // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
+ if (packet.remaining() < 4) {
+ throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
+ }
+ int dhcpMagicCookie = packet.getInt();
if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
"Bad magic cookie 0x%08x, should be 0x%08x",
@@ -1090,7 +1095,13 @@
public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
throws ParseException {
ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
- return decodeFullPacket(buffer, pktType);
+ try {
+ return decodeFullPacket(buffer, pktType);
+ } catch (ParseException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage());
+ }
}
/**
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index ee67d953..01d9304 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -33,6 +33,7 @@
import android.net.dhcp.DhcpClient;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpManagerEvent;
+import android.net.util.AvoidBadWifiTracker;
import android.os.INetworkManagementService;
import android.os.Message;
import android.os.RemoteException;
@@ -396,6 +397,7 @@
private final NetlinkTracker mNetlinkTracker;
private final WakeupMessage mProvisioningTimeoutAlarm;
private final WakeupMessage mDhcpActionTimeoutAlarm;
+ private final AvoidBadWifiTracker mAvoidBadWifiTracker;
private final LocalLog mLocalLog;
private final MessageHandlingLogger mMsgStateLogger;
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
@@ -470,6 +472,8 @@
Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
}
+ mAvoidBadWifiTracker = new AvoidBadWifiTracker(mContext, getHandler());
+
resetLinkProperties();
mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(),
@@ -670,7 +674,7 @@
// object that is a correct and complete assessment of what changed, taking
// account of the asymmetries described in the comments in this function.
// Then switch to using it everywhere (IpReachabilityMonitor, etc.).
- private static ProvisioningChange compareProvisioning(
+ private ProvisioningChange compareProvisioning(
LinkProperties oldLp, LinkProperties newLp) {
ProvisioningChange delta;
@@ -697,6 +701,25 @@
delta = ProvisioningChange.LOST_PROVISIONING;
}
+ final boolean lostIPv6 = oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned();
+ final boolean lostIPv4Address = oldLp.hasIPv4Address() && !newLp.hasIPv4Address();
+ final boolean lostIPv6Router = oldLp.hasIPv6DefaultRoute() && !newLp.hasIPv6DefaultRoute();
+
+ // If bad wifi avoidance is disabled, then ignore IPv6 loss of
+ // provisioning. Otherwise, when a hotspot that loses Internet
+ // access sends out a 0-lifetime RA to its clients, the clients
+ // will disconnect and then reconnect, avoiding the bad hotspot,
+ // instead of getting stuck on the bad hotspot. http://b/31827713 .
+ //
+ // This is incorrect because if the hotspot then regains Internet
+ // access with a different prefix, TCP connections on the
+ // deprecated addresses will remain stuck.
+ //
+ // Note that we can still be disconnected by IpReachabilityMonitor
+ // if the IPv6 default gateway (but not the IPv6 DNS servers; see
+ // accompanying code in IpReachabilityMonitor) is unreachable.
+ final boolean ignoreIPv6ProvisioningLoss = !mAvoidBadWifiTracker.currentValue();
+
// Additionally:
//
// Partial configurations (e.g., only an IPv4 address with no DNS
@@ -709,8 +732,7 @@
// Because on such a network isProvisioned() will always return false,
// delta will never be LOST_PROVISIONING. So check for loss of
// provisioning here too.
- if ((oldLp.hasIPv4Address() && !newLp.hasIPv4Address()) ||
- (oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned())) {
+ if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) {
delta = ProvisioningChange.LOST_PROVISIONING;
}
@@ -719,8 +741,7 @@
// If the previous link properties had a global IPv6 address and an
// IPv6 default route then also consider the loss of that default route
// to be a loss of provisioning. See b/27962810.
- if (oldLp.hasGlobalIPv6Address() && oldLp.hasIPv6DefaultRoute() &&
- !newLp.hasIPv6DefaultRoute()) {
+ if (oldLp.hasGlobalIPv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) {
delta = ProvisioningChange.LOST_PROVISIONING;
}
@@ -1165,7 +1186,8 @@
public void notifyLost(InetAddress ip, String logMsg) {
mCallback.onReachabilityLost(logMsg);
}
- });
+ },
+ mAvoidBadWifiTracker);
}
}
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index c6da3c3..a883e28 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -34,6 +34,7 @@
import android.net.netlink.StructNdaCacheInfo;
import android.net.netlink.StructNdMsg;
import android.net.netlink.StructNlMsgHdr;
+import android.net.util.AvoidBadWifiTracker;
import android.os.PowerManager;
import android.os.SystemClock;
import android.system.ErrnoException;
@@ -42,15 +43,16 @@
import android.util.Log;
import java.io.InterruptedIOException;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -149,6 +151,7 @@
private final String mInterfaceName;
private final int mInterfaceIndex;
private final Callback mCallback;
+ private final AvoidBadWifiTracker mAvoidBadWifiTracker;
private final NetlinkSocketObserver mNetlinkSocketObserver;
private final Thread mObserverThread;
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
@@ -160,8 +163,7 @@
private Map<InetAddress, Short> mIpWatchList = new HashMap<>();
@GuardedBy("mLock")
private int mIpWatchListVersion;
- @GuardedBy("mLock")
- private boolean mRunning;
+ private volatile boolean mRunning;
// Time in milliseconds of the last forced probe request.
private volatile long mLastProbeTimeMs;
@@ -219,8 +221,12 @@
return errno;
}
- public IpReachabilityMonitor(Context context, String ifName, Callback callback)
- throws IllegalArgumentException {
+ public IpReachabilityMonitor(Context context, String ifName, Callback callback) {
+ this(context, ifName, callback, null);
+ }
+
+ public IpReachabilityMonitor(Context context, String ifName, Callback callback,
+ AvoidBadWifiTracker tracker) throws IllegalArgumentException {
mInterfaceName = ifName;
int ifIndex = -1;
try {
@@ -232,13 +238,14 @@
mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, TAG + "." + mInterfaceName);
mCallback = callback;
+ mAvoidBadWifiTracker = tracker;
mNetlinkSocketObserver = new NetlinkSocketObserver();
mObserverThread = new Thread(mNetlinkSocketObserver);
mObserverThread.start();
}
public void stop() {
- synchronized (mLock) { mRunning = false; }
+ mRunning = false;
clearLinkProperties();
mNetlinkSocketObserver.clearNetlinkSocket();
}
@@ -273,12 +280,6 @@
}
}
- private boolean stillRunning() {
- synchronized (mLock) {
- return mRunning;
- }
- }
-
private static boolean isOnLink(List<RouteInfo> routes, InetAddress ip) {
for (RouteInfo route : routes) {
if (!route.hasGateway() && route.matches(ip)) {
@@ -355,7 +356,11 @@
whatIfLp.removeRoute(route);
}
}
- whatIfLp.removeDnsServer(ip);
+
+ if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
+ // We should do this unconditionally, but alas we cannot: b/31827713.
+ whatIfLp.removeDnsServer(ip);
+ }
}
delta = LinkProperties.compareProvisioning(mLinkProperties, whatIfLp);
@@ -373,13 +378,17 @@
logNudFailed(delta);
}
+ private boolean avoidingBadLinks() {
+ return (mAvoidBadWifiTracker != null) ? mAvoidBadWifiTracker.currentValue() : true;
+ }
+
public void probeAll() {
- Set<InetAddress> ipProbeList = new HashSet<InetAddress>();
+ final List<InetAddress> ipProbeList;
synchronized (mLock) {
- ipProbeList.addAll(mIpWatchList.keySet());
+ ipProbeList = new ArrayList<>(mIpWatchList.keySet());
}
- if (!ipProbeList.isEmpty() && stillRunning()) {
+ if (!ipProbeList.isEmpty() && mRunning) {
// Keep the CPU awake long enough to allow all ARP/ND
// probes a reasonable chance at success. See b/23197666.
//
@@ -390,7 +399,7 @@
}
for (InetAddress target : ipProbeList) {
- if (!stillRunning()) {
+ if (!mRunning) {
break;
}
final int returnValue = probeNeighbor(mInterfaceIndex, target);
@@ -435,21 +444,21 @@
@Override
public void run() {
if (VDBG) { Log.d(TAG, "Starting observing thread."); }
- synchronized (mLock) { mRunning = true; }
+ mRunning = true;
try {
setupNetlinkSocket();
} catch (ErrnoException | SocketException e) {
Log.e(TAG, "Failed to suitably initialize a netlink socket", e);
- synchronized (mLock) { mRunning = false; }
+ mRunning = false;
}
- ByteBuffer byteBuffer;
- while (stillRunning()) {
+ while (mRunning) {
+ final ByteBuffer byteBuffer;
try {
byteBuffer = recvKernelReply();
} catch (ErrnoException e) {
- if (stillRunning()) { Log.w(TAG, "ErrnoException: ", e); }
+ if (mRunning) { Log.w(TAG, "ErrnoException: ", e); }
break;
}
final long whenMs = SystemClock.elapsedRealtime();
@@ -461,7 +470,7 @@
clearNetlinkSocket();
- synchronized (mLock) { mRunning = false; }
+ mRunning = false; // Not a no-op when ErrnoException happened.
if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
}
diff --git a/services/net/java/android/net/util/AvoidBadWifiTracker.java b/services/net/java/android/net/util/AvoidBadWifiTracker.java
new file mode 100644
index 0000000..c14e811
--- /dev/null
+++ b/services/net/java/android/net/util/AvoidBadWifiTracker.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.R;
+
+import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
+
+/**
+ * A class to encapsulate management of the "Smart Networking" capability of
+ * avoiding bad Wi-Fi when, for example upstream connectivity is lost or
+ * certain critical link failures occur.
+ *
+ * This enables the device to switch to another form of connectivity, like
+ * mobile, if it's available and working.
+ *
+ * The Runnable |cb|, if given, is called on the supplied Handler's thread
+ * whether the computed "avoid bad wifi" value changes.
+ *
+ * Disabling this reverts the device to a level of networking sophistication
+ * circa 2012-13 by disabling disparate code paths each of which contribute to
+ * maintaining continuous, working Internet connectivity.
+ *
+ * @hide
+ */
+public class AvoidBadWifiTracker {
+ private static String TAG = AvoidBadWifiTracker.class.getSimpleName();
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Runnable mReevaluateRunnable;
+ private final SettingObserver mSettingObserver;
+ private volatile boolean mAvoidBadWifi = true;
+
+ public AvoidBadWifiTracker(Context ctx, Handler handler) {
+ this(ctx, handler, null);
+ }
+
+ public AvoidBadWifiTracker(Context ctx, Handler handler, Runnable cb) {
+ mContext = ctx;
+ mHandler = handler;
+ mReevaluateRunnable = () -> { if (update() && cb != null) cb.run(); };
+ mSettingObserver = new SettingObserver();
+
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+ mContext.registerReceiverAsUser(new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ reevaluate();
+ }
+ }, UserHandle.ALL, intentFilter, null, null);
+
+ update();
+ }
+
+ public boolean currentValue() {
+ return mAvoidBadWifi;
+ }
+
+ /**
+ * Whether the device or carrier configuration disables avoiding bad wifi by default.
+ */
+ public boolean configRestrictsAvoidBadWifi() {
+ return (mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
+ }
+
+ /**
+ * Whether we should display a notification when wifi becomes unvalidated.
+ */
+ public boolean shouldNotifyWifiUnvalidated() {
+ return configRestrictsAvoidBadWifi() && getSettingsValue() == null;
+ }
+
+ public String getSettingsValue() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ return Settings.Global.getString(resolver, NETWORK_AVOID_BAD_WIFI);
+ }
+
+ @VisibleForTesting
+ public void reevaluate() {
+ mHandler.post(mReevaluateRunnable);
+ }
+
+ public boolean update() {
+ final boolean settingAvoidBadWifi = "1".equals(getSettingsValue());
+ final boolean prev = mAvoidBadWifi;
+ mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
+ return mAvoidBadWifi != prev;
+ }
+
+ private class SettingObserver extends ContentObserver {
+ private final Uri mUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
+
+ public SettingObserver() {
+ super(null);
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(mUri, false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ Slog.wtf(TAG, "Should never be reached.");
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (!mUri.equals(uri)) return;
+ reevaluate();
+ }
+ }
+}
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 1feb816..6558b6e 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -728,7 +728,8 @@
@Override
public void onPackageModified(String packageName) {
if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return;
- UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false);
+ UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false,
+ false /* enforceUserUnlockingOrUnlocked */);
synchronized (mLock) {
if (hadPrintService(userState, packageName)
@@ -743,7 +744,8 @@
@Override
public void onPackageRemoved(String packageName, int uid) {
if (!mUserManager.isUserUnlockingOrUnlocked(getChangingUserId())) return;
- UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false);
+ UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false,
+ false /* enforceUserUnlockingOrUnlocked */);
synchronized (mLock) {
if (hadPrintService(userState, packageName)) {
@@ -762,8 +764,8 @@
// A background user/profile's print jobs are running but there is
// no UI shown. Hence, if the packages of such a user change we need
// to handle it as the change may affect ongoing print jobs.
- UserState userState = getOrCreateUserStateLocked(getChangingUserId(),
- false);
+ UserState userState = getOrCreateUserStateLocked(getChangingUserId(), false,
+ false /* enforceUserUnlockingOrUnlocked */);
boolean stoppedSomePackages = false;
List<PrintServiceInfo> enabledServices = userState
@@ -799,7 +801,7 @@
synchronized (mLock) {
if (hasPrintService(packageName)) {
UserState userState = getOrCreateUserStateLocked(getChangingUserId(),
- false);
+ false, false /* enforceUserUnlockingOrUnlocked */);
userState.updateIfNeededLocked();
}
}
@@ -810,9 +812,14 @@
monitor.register(mContext, BackgroundThread.getHandler().getLooper(),
UserHandle.ALL, true);
}
-
private UserState getOrCreateUserStateLocked(int userId, boolean lowPriority) {
- if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
+ return getOrCreateUserStateLocked(userId, lowPriority,
+ true /* enforceUserUnlockingOrUnlocked */);
+ }
+
+ private UserState getOrCreateUserStateLocked(int userId, boolean lowPriority,
+ boolean enforceUserUnlockingOrUnlocked) {
+ if (enforceUserUnlockingOrUnlocked && !mUserManager.isUserUnlockingOrUnlocked(userId)) {
throw new IllegalStateException(
"User " + userId + " must be unlocked for printing to be available");
}
@@ -840,7 +847,8 @@
UserState userState;
synchronized (mLock) {
- userState = getOrCreateUserStateLocked(userId, true);
+ userState = getOrCreateUserStateLocked(userId, true,
+ false /*enforceUserUnlockingOrUnlocked */);
userState.updateIfNeededLocked();
}
// This is the first time we switch to this user after boot, so
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index f97e557..7c7c299 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -124,7 +124,12 @@
@GuardedBy("mActivityLock")
long mLastUserActivityTime;
- private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ private boolean mSafeBootRestrictionInitialState;
+ private int mPackageVerifierEnableInitialState;
+
+ private IntentReceiver mBroadcastReceiver = null;
+
+ private final class IntentReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (!mDeviceInDemoMode) {
@@ -150,6 +155,9 @@
@Override
public void handleMessage(Message msg) {
+ if (!mDeviceInDemoMode) {
+ return;
+ }
switch (msg.what) {
case MSG_TURN_SCREEN_ON:
if (mInjector.isWakeLockHeld()) {
@@ -219,7 +227,7 @@
if (mDeviceDemoModeUri.equals(uri)) {
mDeviceInDemoMode = UserManager.isDeviceInDemoMode(getContext());
if (mDeviceInDemoMode) {
- putDeviceInDemoMode();
+ startDemoMode();
} else {
mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "0");
if (mInjector.isWakeLockHeld()) {
@@ -238,6 +246,7 @@
}
}
});
+ stopDemoMode();
}
}
@@ -376,10 +385,20 @@
}
private void registerBroadcastReceiver() {
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- filter.addAction(ACTION_RESET_DEMO);
- getContext().registerReceiver(mBroadcastReceiver, filter);
+ if (mBroadcastReceiver == null) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ filter.addAction(ACTION_RESET_DEMO);
+ mBroadcastReceiver = new IntentReceiver();
+ getContext().registerReceiver(mBroadcastReceiver, filter);
+ }
+ }
+
+ private void unregisterBroadcastReceiver() {
+ if (mBroadcastReceiver != null) {
+ getContext().unregisterReceiver(mBroadcastReceiver);
+ mBroadcastReceiver = null;
+ }
}
private String[] getCameraIdsWithFlash() {
@@ -407,9 +426,33 @@
}
}
- private void putDeviceInDemoMode() {
+ private void startDemoMode() {
+ mPreloadAppsInstaller = mInjector.getPreloadAppsInstaller();
+ mInjector.initializeWakeLock();
+ if (mCameraIdsWithFlash == null) {
+ mCameraIdsWithFlash = getCameraIdsWithFlash();
+ }
+ registerBroadcastReceiver();
+
mInjector.systemPropertiesSet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED, "1");
mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
+
+ mSafeBootRestrictionInitialState = mInjector.getUserManager().hasUserRestriction(
+ UserManager.DISALLOW_SAFE_BOOT, UserHandle.SYSTEM);
+ mPackageVerifierEnableInitialState = Settings.Global.getInt(mInjector.getContentResolver(),
+ Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
+ }
+
+ private void stopDemoMode() {
+ mPreloadAppsInstaller = null;
+ mCameraIdsWithFlash = null;
+ mInjector.destroyWakeLock();
+ unregisterBroadcastReceiver();
+
+ mInjector.getUserManager().setUserRestriction(UserManager.DISALLOW_SAFE_BOOT,
+ mSafeBootRestrictionInitialState, UserHandle.SYSTEM);
+ Settings.Global.putInt(mInjector.getContentResolver(),
+ Settings.Global.PACKAGE_VERIFIER_ENABLE, mPackageVerifierEnableInitialState);
}
@Override
@@ -421,25 +464,21 @@
false);
mHandlerThread.start();
mHandler = new MainHandler(mHandlerThread.getLooper());
- publishLocalService(RetailDemoModeServiceInternal.class, mLocalService);
+ mInjector.publishLocalService(this, mLocalService);
}
@Override
public void onBootPhase(int bootPhase) {
switch (bootPhase) {
case PHASE_THIRD_PARTY_APPS_CAN_START:
- mPreloadAppsInstaller = mInjector.getPreloadAppsInstaller();
- mInjector.initializeWakeLock();
- mCameraIdsWithFlash = getCameraIdsWithFlash();
SettingsObserver settingsObserver = new SettingsObserver(mHandler);
settingsObserver.register();
settingsObserver.refreshTimeoutConstants();
- registerBroadcastReceiver();
break;
case PHASE_BOOT_COMPLETED:
if (UserManager.isDeviceInDemoMode(getContext())) {
mDeviceInDemoMode = true;
- putDeviceInDemoMode();
+ startDemoMode();
}
break;
}
@@ -466,8 +505,8 @@
mInjector.getSystemUsersConfiguration(), userId);
mInjector.turnOffAllFlashLights(mCameraIdsWithFlash);
muteVolumeStreams();
- if (!mInjector.isWifiEnabled()) {
- mInjector.enableWifi();
+ if (!mInjector.getWifiManager().isWifiEnabled()) {
+ mInjector.getWifiManager().setWifiEnabled(true);
}
// Disable lock screen for demo users.
mInjector.getLockPatternUtils().setLockScreenDisabled(true, userId);
@@ -526,6 +565,7 @@
private WifiManager mWifiManager;
private Configuration mSystemUserConfiguration;
private PendingIntent mResetDemoPendingIntent;
+ private PreloadAppsInstaller mPreloadAppsInstaller;
Injector(Context context) {
mContext = context;
@@ -535,7 +575,7 @@
return mContext;
}
- private WifiManager getWifiManager() {
+ WifiManager getWifiManager() {
if (mWifiManager == null) {
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
}
@@ -609,7 +649,10 @@
}
PreloadAppsInstaller getPreloadAppsInstaller() {
- return new PreloadAppsInstaller(getContext());
+ if (mPreloadAppsInstaller == null) {
+ mPreloadAppsInstaller = new PreloadAppsInstaller(getContext());
+ }
+ return mPreloadAppsInstaller;
}
void systemPropertiesSet(String key, String value) {
@@ -628,8 +671,14 @@
}
void initializeWakeLock() {
- mWakeLock = getPowerManager().newWakeLock(
- PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
+ if (mWakeLock == null) {
+ mWakeLock = getPowerManager().newWakeLock(
+ PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
+ }
+ }
+
+ void destroyWakeLock() {
+ mWakeLock = null;
}
boolean isWakeLockHeld() {
@@ -644,14 +693,6 @@
mWakeLock.release();
}
- boolean isWifiEnabled() {
- return getWifiManager().isWifiEnabled();
- }
-
- void enableWifi() {
- getWifiManager().setWifiEnabled(true);
- }
-
void logSessionDuration(int duration) {
MetricsLogger.histogram(getContext(), DEMO_SESSION_DURATION, duration);
}
@@ -696,5 +737,10 @@
File getDataPreloadsDirectory() {
return Environment.getDataPreloadsDirectory();
}
+
+ void publishLocalService(RetailDemoModeService service,
+ RetailDemoModeServiceInternal localService) {
+ service.publishLocalService(RetailDemoModeServiceInternal.class, localService);
+ }
}
}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index b76392c..3f5b96e 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -53,6 +53,8 @@
LOCAL_JACK_FLAGS := --multi-dex native
endif # EMMA_INSTRUMENT_STATIC
+LOCAL_STATIC_JAVA_LIBRARIES += ub-uiautomator
+
include $(BUILD_PACKAGE)
#########################################################################
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index b8ace28..3548f28 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -43,6 +43,8 @@
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
<uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+ <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<application>
<uses-library android:name="android.test.runner" />
@@ -155,6 +157,9 @@
</intent-filter>
</activity-alias>
+ <activity android:name="com.android.server.am.TaskStackChangedListenerTest$ActivityA" />
+ <activity android:name="com.android.server.am.TaskStackChangedListenerTest$ActivityB" />
+
</application>
<instrumentation
diff --git a/services/tests/servicestests/src/android/net/apf/ApfTest.java b/services/tests/servicestests/src/android/net/apf/ApfTest.java
index f7c61d1..37807b2 100644
--- a/services/tests/servicestests/src/android/net/apf/ApfTest.java
+++ b/services/tests/servicestests/src/android/net/apf/ApfTest.java
@@ -16,10 +16,6 @@
package android.net.apf;
-import static android.system.OsConstants.*;
-
-import com.android.frameworks.servicestests.R;
-
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
@@ -37,6 +33,10 @@
import android.system.Os;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.LargeTest;
+import static android.system.OsConstants.*;
+
+import com.android.frameworks.servicestests.R;
+import com.android.internal.util.HexDump;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -54,6 +54,7 @@
import java.net.NetworkInterface;
import java.nio.ByteBuffer;
import java.util.List;
+import java.util.Random;
import libcore.io.IoUtils;
import libcore.io.Streams;
@@ -1146,6 +1147,39 @@
buffer.position(original);
}
+ public void testRaParsing() throws Exception {
+ final int maxRandomPacketSize = 512;
+ final Random r = new Random();
+ MockIpManagerCallback cb = new MockIpManagerCallback();
+ TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog);
+ for (int i = 0; i < 1000; i++) {
+ byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
+ r.nextBytes(packet);
+ try {
+ apfFilter.new Ra(packet, packet.length);
+ } catch (ApfFilter.InvalidRaException e) {
+ } catch (Exception e) {
+ throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
+ }
+ }
+ }
+
+ public void testRaProcessing() throws Exception {
+ final int maxRandomPacketSize = 512;
+ final Random r = new Random();
+ MockIpManagerCallback cb = new MockIpManagerCallback();
+ TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST, mLog);
+ for (int i = 0; i < 1000; i++) {
+ byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
+ r.nextBytes(packet);
+ try {
+ apfFilter.processRa(packet, packet.length);
+ } catch (Exception e) {
+ throw new Exception("bad packet: " + HexDump.toHexString(packet), e);
+ }
+ }
+ }
+
/**
* Call the APF interpreter the run {@code program} on {@code packet} pretending the
* filter was installed {@code filter_age} seconds ago.
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index f8eaf7d..bc8baa1 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -16,24 +16,22 @@
package android.net.dhcp;
-import android.net.NetworkUtils;
import android.net.DhcpResults;
import android.net.LinkAddress;
+import android.net.NetworkUtils;
+import android.net.metrics.DhcpErrorEvent;
import android.system.OsConstants;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.util.HexDump;
-
import java.net.Inet4Address;
import java.nio.ByteBuffer;
import java.util.ArrayList;
-
-import junit.framework.TestCase;
-import libcore.util.HexEncoding;
import java.util.Arrays;
+import java.util.Random;
+import junit.framework.TestCase;
import static android.net.dhcp.DhcpPacket.*;
-
public class DhcpPacketTest extends TestCase {
private static Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
@@ -285,7 +283,7 @@
// TODO: Turn all of these into golden files. This will probably require modifying
// Android.mk appropriately, making this into an AndroidTestCase, and adding code to read
// the golden files from the test APK's assets via mContext.getAssets().
- final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// IP header.
"451001480000000080118849c0a89003c0a89ff7" +
// UDP header.
@@ -304,8 +302,7 @@
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options
"638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
- "3a0400000e103b040000189cff00000000000000000000"
- ).toCharArray(), false));
+ "3a0400000e103b040000189cff00000000000000000000"));
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
@@ -316,7 +313,7 @@
@SmallTest
public void testOffer2() throws Exception {
- final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// IP header.
"450001518d0600004011144dc0a82b01c0a82bf7" +
// UDP header.
@@ -335,8 +332,7 @@
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options
"638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
- "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"
- ).toCharArray(), false));
+ "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
assertEquals(337, packet.limit());
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
@@ -347,6 +343,185 @@
assertTrue(dhcpResults.hasMeteredHint());
}
+ @SmallTest
+ public void testBadIpPacket() throws Exception {
+ final byte[] packet = HexDump.hexStringToByteArray(
+ // IP header.
+ "450001518d0600004011144dc0a82b01c0a82bf7");
+
+ try {
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+ } catch (DhcpPacket.ParseException expected) {
+ assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
+ return;
+ }
+ fail("Dhcp packet parsing should have failed");
+ }
+
+ @SmallTest
+ public void testBadDhcpPacket() throws Exception {
+ final byte[] packet = HexDump.hexStringToByteArray(
+ // IP header.
+ "450001518d0600004011144dc0a82b01c0a82bf7" +
+ // UDP header.
+ "00430044013d9ac7" +
+ // BOOTP header.
+ "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000");
+
+ try {
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+ } catch (DhcpPacket.ParseException expected) {
+ assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
+ return;
+ }
+ fail("Dhcp packet parsing should have failed");
+ }
+
+ @SmallTest
+ public void testBadTruncatedOffer() throws Exception {
+ final byte[] packet = HexDump.hexStringToByteArray(
+ // IP header.
+ "450001518d0600004011144dc0a82b01c0a82bf7" +
+ // UDP header.
+ "00430044013d9ac7" +
+ // BOOTP header.
+ "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+ // MAC address.
+ "30766ff2a90c00000000000000000000" +
+ // Server name.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // File, missing one byte
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "00000000000000000000000000000000000000000000000000000000000000");
+
+ try {
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+ } catch (DhcpPacket.ParseException expected) {
+ assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
+ return;
+ }
+ fail("Dhcp packet parsing should have failed");
+ }
+
+ @SmallTest
+ public void testBadOfferWithoutACookie() throws Exception {
+ final byte[] packet = HexDump.hexStringToByteArray(
+ // IP header.
+ "450001518d0600004011144dc0a82b01c0a82bf7" +
+ // UDP header.
+ "00430044013d9ac7" +
+ // BOOTP header.
+ "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+ // MAC address.
+ "30766ff2a90c00000000000000000000" +
+ // Server name.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // File.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000"
+ // No options
+ );
+
+ try {
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+ } catch (DhcpPacket.ParseException expected) {
+ assertDhcpErrorCodes(DhcpErrorEvent.DHCP_NO_COOKIE, expected.errorCode);
+ return;
+ }
+ fail("Dhcp packet parsing should have failed");
+ }
+
+ @SmallTest
+ public void testOfferWithBadCookie() throws Exception {
+ final byte[] packet = HexDump.hexStringToByteArray(
+ // IP header.
+ "450001518d0600004011144dc0a82b01c0a82bf7" +
+ // UDP header.
+ "00430044013d9ac7" +
+ // BOOTP header.
+ "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+ // MAC address.
+ "30766ff2a90c00000000000000000000" +
+ // Server name.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // File.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // Bad cookie
+ "DEADBEEF3501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
+ "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
+
+ try {
+ DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+ } catch (DhcpPacket.ParseException expected) {
+ assertDhcpErrorCodes(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE, expected.errorCode);
+ return;
+ }
+ fail("Dhcp packet parsing should have failed");
+ }
+
+ private void assertDhcpErrorCodes(int expected, int got) {
+ assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
+ }
+
+ public void testTruncatedOfferPackets() throws Exception {
+ final byte[] packet = HexDump.hexStringToByteArray(
+ // IP header.
+ "450001518d0600004011144dc0a82b01c0a82bf7" +
+ // UDP header.
+ "00430044013d9ac7" +
+ // BOOTP header.
+ "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+ // MAC address.
+ "30766ff2a90c00000000000000000000" +
+ // Server name.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // File.
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ "0000000000000000000000000000000000000000000000000000000000000000" +
+ // Options
+ "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
+ "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
+
+ for (int len = 0; len < packet.length; len++) {
+ try {
+ DhcpPacket.decodeFullPacket(packet, len, ENCAP_L3);
+ } catch (ParseException e) {
+ if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
+ fail(String.format("bad truncated packet of length %d", len));
+ }
+ }
+ }
+ }
+
+ public void testRandomPackets() throws Exception {
+ final int maxRandomPacketSize = 512;
+ final Random r = new Random();
+ for (int i = 0; i < 10000; i++) {
+ byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
+ r.nextBytes(packet);
+ try {
+ DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+ } catch (ParseException e) {
+ if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
+ fail("bad packet: " + HexDump.toHexString(packet));
+ }
+ }
+ }
+ }
+
private byte[] mtuBytes(int mtu) {
// 0x1a02: option 26, length 2. 0xff: no more options.
if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
@@ -354,7 +529,7 @@
String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
}
String hexString = String.format("1a02%04xff", mtu);
- return HexEncoding.decode(hexString.toCharArray(), false);
+ return HexDump.hexStringToByteArray(hexString);
}
private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
@@ -372,7 +547,7 @@
@SmallTest
public void testMtu() throws Exception {
- final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// IP header.
"451001480000000080118849c0a89003c0a89ff7" +
// UDP header.
@@ -391,8 +566,7 @@
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options
"638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
- "3a0400000e103b040000189cff00000000"
- ).toCharArray(), false));
+ "3a0400000e103b040000189cff00000000"));
checkMtu(packet, 0, null);
checkMtu(packet, 0, mtuBytes(1501));
@@ -409,7 +583,7 @@
@SmallTest
public void testBadHwaddrLength() throws Exception {
- final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// IP header.
"450001518d0600004011144dc0a82b01c0a82bf7" +
// UDP header.
@@ -428,8 +602,7 @@
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options
"638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
- "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"
- ).toCharArray(), false));
+ "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
String expectedClientMac = "30766FF2A90C";
final int hwAddrLenOffset = 20 + 8 + 2;
@@ -486,7 +659,7 @@
// store any information in the overloaded fields).
//
// For now, we just check that it parses correctly.
- final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// Ethernet header.
"b4cef6000000e80462236e300800" +
// IP header.
@@ -507,8 +680,7 @@
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options
"638253633501023604010101010104ffff000033040000a8c03401030304ac1101010604ac110101" +
- "0000000000000000000000000000000000000000000000ff000000"
- ).toCharArray(), false));
+ "0000000000000000000000000000000000000000000000ff000000"));
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
assertTrue(offerPacket instanceof DhcpOfferPacket);
@@ -519,7 +691,7 @@
@SmallTest
public void testBug2111() throws Exception {
- final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// IP header.
"4500014c00000000ff119beac3eaf3880a3f5d04" +
// UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
@@ -538,8 +710,7 @@
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options.
"638253633501023604c00002fe33040000bfc60104fffff00003040a3f50010608c0000201c0000202" +
- "0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"
- ).toCharArray(), false));
+ "0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"));
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
assertTrue(offerPacket instanceof DhcpOfferPacket);
@@ -550,7 +721,7 @@
@SmallTest
public void testBug2136() throws Exception {
- final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// Ethernet header.
"bcf5ac000000d0c7890000000800" +
// IP header.
@@ -571,8 +742,7 @@
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options.
"6382536335010236040a20ff80330400001c200104fffff00003040a20900106089458413494584135" +
- "0f0b6c616e63732e61632e756b000000000000000000ff00000000"
- ).toCharArray(), false));
+ "0f0b6c616e63732e61632e756b000000000000000000ff00000000"));
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
assertTrue(offerPacket instanceof DhcpOfferPacket);
@@ -584,7 +754,7 @@
@SmallTest
public void testUdpServerAnySourcePort() throws Exception {
- final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// Ethernet header.
"9cd917000000001c2e0000000800" +
// IP header.
@@ -606,8 +776,7 @@
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options.
"6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
- "d18180060f0777766d2e6564751c040a0fffffff000000"
- ).toCharArray(), false));
+ "d18180060f0777766d2e6564751c040a0fffffff000000"));
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
assertTrue(offerPacket instanceof DhcpOfferPacket);
@@ -620,7 +789,7 @@
@SmallTest
public void testUdpInvalidDstPort() throws Exception {
- final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// Ethernet header.
"9cd917000000001c2e0000000800" +
// IP header.
@@ -642,8 +811,7 @@
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options.
"6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
- "d18180060f0777766d2e6564751c040a0fffffff000000"
- ).toCharArray(), false));
+ "d18180060f0777766d2e6564751c040a0fffffff000000"));
try {
DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
@@ -653,7 +821,7 @@
@SmallTest
public void testMultipleRouters() throws Exception {
- final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+ final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// Ethernet header.
"fc3d93000000" + "081735000000" + "0800" +
// IP header.
@@ -674,8 +842,7 @@
"0000000000000000000000000000000000000000000000000000000000000000" +
// Options.
"638253633501023604c0abbd023304000070803a04000038403b04000062700104ffffff00" +
- "0308c0a8bd01ffffff0006080808080808080404ff000000000000"
- ).toCharArray(), false));
+ "0308c0a8bd01ffffff0006080808080808080404ff000000000000"));
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
assertTrue(offerPacket instanceof DhcpOfferPacket);
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 257341b..0f180af 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -53,6 +53,7 @@
import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.metrics.IpConnectivityLog;
+import android.net.util.AvoidBadWifiTracker;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
@@ -600,10 +601,23 @@
}
}
- private class WrappedConnectivityService extends ConnectivityService {
- private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
+ private class WrappedAvoidBadWifiTracker extends AvoidBadWifiTracker {
public boolean configRestrictsAvoidBadWifi;
+ public WrappedAvoidBadWifiTracker(Context c, Handler h, Runnable r) {
+ super(c, h, r);
+ }
+
+ @Override
+ public boolean configRestrictsAvoidBadWifi() {
+ return configRestrictsAvoidBadWifi;
+ }
+ }
+
+ private class WrappedConnectivityService extends ConnectivityService {
+ public WrappedAvoidBadWifiTracker wrappedAvoidBadWifiTracker;
+ private WrappedNetworkMonitor mLastCreatedNetworkMonitor;
+
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
IpConnectivityLog log) {
@@ -653,14 +667,20 @@
}
@Override
- public WakeupMessage makeWakeupMessage(
- Context context, Handler handler, String cmdName, int cmd, Object obj) {
- return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
+ public AvoidBadWifiTracker createAvoidBadWifiTracker(
+ Context c, Handler h, Runnable r) {
+ final WrappedAvoidBadWifiTracker tracker = new WrappedAvoidBadWifiTracker(c, h, r);
+ return tracker;
+ }
+
+ public WrappedAvoidBadWifiTracker getAvoidBadWifiTracker() {
+ return (WrappedAvoidBadWifiTracker) mAvoidBadWifiTracker;
}
@Override
- public boolean configRestrictsAvoidBadWifi() {
- return configRestrictsAvoidBadWifi;
+ public WakeupMessage makeWakeupMessage(
+ Context context, Handler handler, String cmdName, int cmd, Object obj) {
+ return new FakeWakeupMessage(context, handler, cmdName, cmd, 0, 0, obj);
}
public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
@@ -2049,46 +2069,48 @@
@SmallTest
public void testAvoidBadWifiSetting() throws Exception {
final ContentResolver cr = mServiceContext.getContentResolver();
+ final WrappedAvoidBadWifiTracker tracker = mService.getAvoidBadWifiTracker();
final String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
- mService.configRestrictsAvoidBadWifi = false;
+ tracker.configRestrictsAvoidBadWifi = false;
String[] values = new String[] {null, "0", "1"};
for (int i = 0; i < values.length; i++) {
Settings.Global.putInt(cr, settingName, 1);
- mService.updateNetworkAvoidBadWifi();
+ tracker.reevaluate();
mService.waitForIdle();
String msg = String.format("config=false, setting=%s", values[i]);
assertTrue(msg, mService.avoidBadWifi());
- assertFalse(msg, mService.shouldNotifyWifiUnvalidated());
+ assertFalse(msg, tracker.shouldNotifyWifiUnvalidated());
}
- mService.configRestrictsAvoidBadWifi = true;
+ tracker.configRestrictsAvoidBadWifi = true;
Settings.Global.putInt(cr, settingName, 0);
- mService.updateNetworkAvoidBadWifi();
+ tracker.reevaluate();
mService.waitForIdle();
assertFalse(mService.avoidBadWifi());
- assertFalse(mService.shouldNotifyWifiUnvalidated());
+ assertFalse(tracker.shouldNotifyWifiUnvalidated());
Settings.Global.putInt(cr, settingName, 1);
- mService.updateNetworkAvoidBadWifi();
+ tracker.reevaluate();
mService.waitForIdle();
assertTrue(mService.avoidBadWifi());
- assertFalse(mService.shouldNotifyWifiUnvalidated());
+ assertFalse(tracker.shouldNotifyWifiUnvalidated());
Settings.Global.putString(cr, settingName, null);
- mService.updateNetworkAvoidBadWifi();
+ tracker.reevaluate();
mService.waitForIdle();
assertFalse(mService.avoidBadWifi());
- assertTrue(mService.shouldNotifyWifiUnvalidated());
+ assertTrue(tracker.shouldNotifyWifiUnvalidated());
}
@SmallTest
public void testAvoidBadWifi() throws Exception {
- ContentResolver cr = mServiceContext.getContentResolver();
+ final ContentResolver cr = mServiceContext.getContentResolver();
+ final WrappedAvoidBadWifiTracker tracker = mService.getAvoidBadWifiTracker();
// Pretend we're on a carrier that restricts switching away from bad wifi.
- mService.configRestrictsAvoidBadWifi = true;
+ tracker.configRestrictsAvoidBadWifi = true;
// File a request for cell to ensure it doesn't go down.
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
@@ -2107,7 +2129,7 @@
mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
- mService.updateNetworkAvoidBadWifi();
+ tracker.reevaluate();
// Bring up validated cell.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
@@ -2138,14 +2160,14 @@
// Simulate switching to a carrier that does not restrict avoiding bad wifi, and expect
// that we switch back to cell.
- mService.configRestrictsAvoidBadWifi = false;
- mService.updateNetworkAvoidBadWifi();
+ tracker.configRestrictsAvoidBadWifi = false;
+ tracker.reevaluate();
defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// Switch back to a restrictive carrier.
- mService.configRestrictsAvoidBadWifi = true;
- mService.updateNetworkAvoidBadWifi();
+ tracker.configRestrictsAvoidBadWifi = true;
+ tracker.reevaluate();
defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
@@ -2173,7 +2195,7 @@
// Simulate the user selecting "switch" and checking the don't ask again checkbox.
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
- mService.updateNetworkAvoidBadWifi();
+ tracker.reevaluate();
// We now switch to cell.
defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
@@ -2186,11 +2208,11 @@
// Simulate the user turning the cellular fallback setting off and then on.
// We switch to wifi and then to cell.
Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
- mService.updateNetworkAvoidBadWifi();
+ tracker.reevaluate();
defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
- mService.updateNetworkAvoidBadWifi();
+ tracker.reevaluate();
defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
new file mode 100644
index 0000000..5b565a7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountsDbTest.java
@@ -0,0 +1,341 @@
+
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.accounts;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.database.Cursor;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Pair;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for {@link AccountsDb}.
+ * <p>Run with:<pre>
+ * m FrameworksServicesTests &&
+ * adb install \
+ * -r out/target/product/marlin/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ * adb shell am instrument -e class com.android.server.accounts.AccountsDbTest \
+ * -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ * </pre>
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class AccountsDbTest {
+ private static final String PREN_DB = "pren.db";
+ private static final String DE_DB = "de.db";
+ private static final String CE_DB = "ce.db";
+
+ private AccountsDb mAccountsDb;
+ private File preNDb;
+ private File deDb;
+ private File ceDb;
+
+ @Before
+ public void setUp() {
+ Context context = InstrumentationRegistry.getContext();
+ preNDb = new File(context.getCacheDir(), PREN_DB);
+ ceDb = new File(context.getCacheDir(), CE_DB);
+ deDb = new File(context.getCacheDir(), DE_DB);
+ deleteDbFiles();
+ mAccountsDb = AccountsDb.create(context, 0, preNDb, deDb);
+ }
+
+ @After
+ public void tearDown() {
+ deleteDbFiles();
+ }
+
+ private void deleteDbFiles() {
+ AccountsDb.deleteDbFileWarnIfFailed(preNDb);
+ AccountsDb.deleteDbFileWarnIfFailed(ceDb);
+ AccountsDb.deleteDbFileWarnIfFailed(deDb);
+ }
+
+ @Test
+ public void testCeNotAvailableInitially() {
+ Account account = new Account("name", "example.com");
+ long id = mAccountsDb.insertCeAccount(account, "");
+ assertEquals("Insert into CE should fail until CE database is attached", -1, id);
+ }
+
+ @Test
+ public void testDeAccountInsertFindDelete() {
+ Account account = new Account("name", "example.com");
+ long accId = 1;
+ mAccountsDb.insertDeAccount(account, accId);
+ long actualId = mAccountsDb.findDeAccountId(account);
+ assertEquals(accId, actualId);
+ // Delete and verify that account no longer exists
+ mAccountsDb.deleteDeAccount(accId);
+ actualId = mAccountsDb.findDeAccountId(account);
+ assertEquals(-1, actualId);
+ }
+
+ @Test
+ public void testCeAccountInsertFindDelete() {
+ mAccountsDb.attachCeDatabase(ceDb);
+ Account account = new Account("name", "example.com");
+ long accId = mAccountsDb.insertCeAccount(account, "password");
+ long actualId = mAccountsDb.findCeAccountId(account);
+ assertEquals(accId, actualId);
+ // Delete and verify that account no longer exists
+ mAccountsDb.deleteCeAccount(accId);
+ actualId = mAccountsDb.findCeAccountId(account);
+ assertEquals(-1, actualId);
+ }
+
+ @Test
+ public void testAuthTokenInsertFindDelete() {
+ mAccountsDb.attachCeDatabase(ceDb);
+ Account account = new Account("name", "example.com");
+ long accId = mAccountsDb.insertCeAccount(account, "password");
+ mAccountsDb.insertDeAccount(account, accId);
+ long authTokenId = mAccountsDb.insertAuthToken(accId, "type", "token");
+ Map<String, String> authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account);
+ assertEquals(1, authTokensByAccount.size());
+ try (Cursor cursor = mAccountsDb.findAuthtokenForAllAccounts(account.type, "token")) {
+ assertTrue(cursor.moveToNext());
+ }
+ try (Cursor cursor = mAccountsDb.findAuthtokenForAllAccounts(account.type, "nosuchtoken")) {
+ assertFalse(cursor.moveToNext());
+ }
+ mAccountsDb.deleteAuthToken(String.valueOf(authTokenId));
+ // Verify that token no longer exists
+ authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account);
+ assertEquals(0, authTokensByAccount.size());
+ }
+
+ @Test
+ public void testAuthTokenDeletes() {
+ mAccountsDb.attachCeDatabase(ceDb);
+ // 1st account
+ Account account = new Account("name", "example.com");
+ long accId = mAccountsDb.insertCeAccount(account, "password");
+ mAccountsDb.insertDeAccount(account, accId);
+ mAccountsDb.insertAuthToken(accId, "type", "token");
+ mAccountsDb.insertAuthToken(accId, "type2", "token2");
+ // 2nd account
+ Account account2 = new Account("name", "example2.com");
+ long accId2 = mAccountsDb.insertCeAccount(account2, "password");
+ mAccountsDb.insertDeAccount(account2, accId);
+ mAccountsDb.insertAuthToken(accId2, "type", "token");
+
+ mAccountsDb.deleteAuthTokensByAccountId(accId2);
+ Map<String, String> authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account2);
+ assertEquals(0, authTokensByAccount.size());
+ // Authtokens from account 1 are still there
+ authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account);
+ assertEquals(2, authTokensByAccount.size());
+
+ // Delete authtokens from account 1 and verify
+ mAccountsDb.deleteAuthtokensByAccountIdAndType(accId, "type");
+ authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account);
+ assertEquals(1, authTokensByAccount.size());
+ mAccountsDb.deleteAuthtokensByAccountIdAndType(accId, "type2");
+ authTokensByAccount = mAccountsDb.findAuthTokensByAccount(account);
+ assertEquals(0, authTokensByAccount.size());
+ }
+
+ @Test
+ public void testExtrasInsertFindDelete() {
+ mAccountsDb.attachCeDatabase(ceDb);
+ Account account = new Account("name", "example.com");
+ long accId = mAccountsDb.insertCeAccount(account, "password");
+ mAccountsDb.insertDeAccount(account, accId);
+ String extraKey = "extra_key";
+ String extraValue = "extra_value";
+ long extraId = mAccountsDb.insertExtra(accId, extraKey, extraValue);
+ // Test find methods
+ long actualExtraId = mAccountsDb.findExtrasIdByAccountId(accId, extraKey);
+ assertEquals(extraId, actualExtraId);
+ Map<String, String> extras = mAccountsDb.findUserExtrasForAccount(account);
+ assertEquals(1, extras.size());
+ assertEquals(extraValue, extras.get(extraKey));
+ // Test update
+ String newExtraValue = "extra_value2";
+ mAccountsDb.updateExtra(extraId, newExtraValue);
+ String newValue = mAccountsDb.findUserExtrasForAccount(account).get(extraKey);
+ assertEquals(newExtraValue, newValue);
+
+ // Delete account and verify that extras cascade removed
+ mAccountsDb.deleteCeAccount(accId);
+ actualExtraId = mAccountsDb.findExtrasIdByAccountId(accId, extraKey);
+ assertEquals(-1, actualExtraId);
+ }
+
+ @Test
+ public void testGrantsInsertFindDelete() {
+ mAccountsDb.attachCeDatabase(ceDb);
+ Account account = new Account("name", "example.com");
+ long accId = mAccountsDb.insertCeAccount(account, "password");
+ mAccountsDb.insertDeAccount(account, accId);
+ int testUid = 100500;
+ long grantId = mAccountsDb.insertGrant(accId, "tokenType", testUid);
+ assertTrue(grantId > 0);
+ List<Integer> allUidGrants = mAccountsDb.findAllUidGrants();
+ List<Integer> expectedUids = Arrays.asList(testUid);
+ assertEquals(expectedUids, allUidGrants);
+
+ long matchingGrantsCount = mAccountsDb.findMatchingGrantsCount(
+ testUid, "tokenType", account);
+ assertEquals(1, matchingGrantsCount);
+ // Test nonexistent type
+ matchingGrantsCount = mAccountsDb.findMatchingGrantsCount(
+ testUid, "noSuchType", account);
+ assertEquals(0, matchingGrantsCount);
+
+ matchingGrantsCount = mAccountsDb.findMatchingGrantsCountAnyToken(testUid, account);
+ assertEquals(1, matchingGrantsCount);
+
+ List<Pair<String, Integer>> allAccountGrants = mAccountsDb.findAllAccountGrants();
+ assertEquals(1, allAccountGrants.size());
+ assertEquals(account.name, allAccountGrants.get(0).first);
+ assertEquals(testUid, (int)allAccountGrants.get(0).second);
+
+ mAccountsDb.deleteGrantsByUid(testUid);
+ allUidGrants = mAccountsDb.findAllUidGrants();
+ assertTrue("Test grants should be removed", allUidGrants.isEmpty());
+ }
+
+ @Test
+ public void testSharedAccountsInsertFindDelete() {
+ Account account = new Account("name", "example.com");
+ long accId = 0;
+ mAccountsDb.insertDeAccount(account, accId);
+ long sharedAccId = mAccountsDb.insertSharedAccount(account);
+ long foundSharedAccountId = mAccountsDb.findSharedAccountId(account);
+ assertEquals(sharedAccId, foundSharedAccountId);
+ List<Account> sharedAccounts = mAccountsDb.getSharedAccounts();
+ List<Account> expectedList = Arrays.asList(account);
+ assertEquals(expectedList, sharedAccounts);
+
+ // Delete and verify
+ mAccountsDb.deleteSharedAccount(account);
+ foundSharedAccountId = mAccountsDb.findSharedAccountId(account);
+ assertEquals(-1, foundSharedAccountId);
+ }
+
+ @Test
+ public void testMetaInsertFindDelete() {
+ int testUid = 100500;
+ String authenticatorType = "authType";
+ mAccountsDb.insertOrReplaceMetaAuthTypeAndUid(authenticatorType, testUid);
+ Map<String, Integer> metaAuthUid = mAccountsDb.findMetaAuthUid();
+ assertEquals(1, metaAuthUid.size());
+ assertEquals(testUid, (int)metaAuthUid.get(authenticatorType));
+
+ // Delete and verify
+ boolean deleteResult = mAccountsDb.deleteMetaByAuthTypeAndUid(authenticatorType, testUid);
+ assertTrue(deleteResult);
+ metaAuthUid = mAccountsDb.findMetaAuthUid();
+ assertEquals(0, metaAuthUid.size());
+ }
+
+ @Test
+ public void testUpdateDeAccountLastAuthenticatedTime() {
+ Account account = new Account("name", "example.com");
+ long accId = 1;
+ mAccountsDb.insertDeAccount(account, accId);
+ long now = System.currentTimeMillis();
+ mAccountsDb.updateAccountLastAuthenticatedTime(account);
+ long time = mAccountsDb.findAccountLastAuthenticatedTime(account);
+ assertTrue("LastAuthenticatedTime should be current", time >= now);
+ }
+
+ @Test
+ public void testRenameAccount() {
+ mAccountsDb.attachCeDatabase(ceDb);
+ Account account = new Account("name", "example.com");
+ long accId = mAccountsDb.insertCeAccount(account, "password");
+ mAccountsDb.insertDeAccount(account, accId);
+ mAccountsDb.renameDeAccount(accId, "newName", "name");
+ Account newAccount = mAccountsDb.findAllDeAccounts().get(accId);
+ assertEquals("newName", newAccount.name);
+
+ String prevName = mAccountsDb.findDeAccountPreviousName(newAccount);
+ assertEquals("name", prevName);
+ mAccountsDb.renameCeAccount(accId, "newName");
+ long foundAccId = mAccountsDb.findCeAccountId(account);
+ assertEquals("Account shouldn't be found under the old name", -1, foundAccId);
+ foundAccId = mAccountsDb.findCeAccountId(newAccount);
+ assertEquals(accId, foundAccId);
+ }
+
+ @Test
+ public void testUpdateCeAccountPassword() {
+ mAccountsDb.attachCeDatabase(ceDb);
+ Account account = new Account("name", "example.com");
+ long accId = mAccountsDb.insertCeAccount(account, "password");
+ String newPassword = "newPassword";
+ mAccountsDb.updateCeAccountPassword(accId, newPassword);
+ String actualPassword = mAccountsDb
+ .findAccountPasswordByNameAndType(account.name, account.type);
+ assertEquals(newPassword, actualPassword);
+ }
+
+ @Test
+ public void testFindCeAccountsNotInDe() {
+ mAccountsDb.attachCeDatabase(ceDb);
+ Account account = new Account("name", "example.com");
+ long accId = mAccountsDb.insertCeAccount(account, "password");
+ mAccountsDb.insertDeAccount(account, accId);
+
+ Account accountNotInDe = new Account("name2", "example.com");
+ mAccountsDb.insertCeAccount(accountNotInDe, "password");
+
+ List<Account> ceAccounts = mAccountsDb.findCeAccountsNotInDe();
+ List<Account> expectedList = Arrays.asList(accountNotInDe);
+ assertEquals(expectedList, ceAccounts);
+ }
+
+ @Test
+ public void testCrossDbTransactions() {
+ mAccountsDb.attachCeDatabase(ceDb);
+ mAccountsDb.beginTransaction();
+ Account account = new Account("name", "example.com");
+ long accId;
+ accId = mAccountsDb.insertCeAccount(account, "password");
+ accId = mAccountsDb.insertDeAccount(account, accId);
+ long actualId = mAccountsDb.findCeAccountId(account);
+ assertEquals(accId, actualId);
+ actualId = mAccountsDb.findDeAccountId(account);
+ assertEquals(accId, actualId);
+ mAccountsDb.endTransaction();
+ // Verify that records were removed
+ actualId = mAccountsDb.findCeAccountId(account);
+ assertEquals(-1, actualId);
+ actualId = mAccountsDb.findDeAccountId(account);
+ assertEquals(-1, actualId);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ConfigurationContainerTests.java b/services/tests/servicestests/src/com/android/server/am/ConfigurationContainerTests.java
new file mode 100644
index 0000000..92c442e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/ConfigurationContainerTests.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import android.content.res.Configuration;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test class for {@link ConfigurationContainer}. Mostly duplicates configuration tests from
+ * {@link com.android.server.wm.WindowContainerTests}.
+ *
+ * Build: mmma -j32 frameworks/base/services/tests/servicestests
+ * Install: adb install -r out/target/product/$TARGET_PRODUCT/data/app/FrameworksServicesTests/FrameworksServicesTests.apk
+ * Run: adb shell am instrument -w -e class com.android.server.am.ConfigurationContainerTests com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ConfigurationContainerTests {
+
+ @Test
+ public void testConfigurationInit() throws Exception {
+ // Check root container initial config.
+ final TestConfigurationContainer root = new TestConfigurationContainer();
+ assertEquals(Configuration.EMPTY, root.getOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, root.getMergedOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, root.getConfiguration());
+
+ // Check child initial config.
+ final TestConfigurationContainer child1 = root.addChild();
+ assertEquals(Configuration.EMPTY, child1.getOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, child1.getMergedOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, child1.getConfiguration());
+
+ // Check child initial config if root has overrides.
+ final Configuration rootOverrideConfig = new Configuration();
+ rootOverrideConfig.fontScale = 1.3f;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+ final TestConfigurationContainer child2 = root.addChild();
+ assertEquals(Configuration.EMPTY, child2.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, child2.getMergedOverrideConfiguration());
+ assertEquals(rootOverrideConfig, child2.getConfiguration());
+
+ // Check child initial config if root has parent config set.
+ final Configuration rootParentConfig = new Configuration();
+ rootParentConfig.fontScale = 0.8f;
+ rootParentConfig.orientation = SCREEN_ORIENTATION_LANDSCAPE;
+ root.onConfigurationChanged(rootParentConfig);
+ final Configuration rootFullConfig = new Configuration(rootParentConfig);
+ rootFullConfig.updateFrom(rootOverrideConfig);
+
+ final TestConfigurationContainer child3 = root.addChild();
+ assertEquals(Configuration.EMPTY, child3.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, child3.getMergedOverrideConfiguration());
+ assertEquals(rootFullConfig, child3.getConfiguration());
+ }
+
+ @Test
+ public void testConfigurationChangeOnAddRemove() throws Exception {
+ // Init root's config.
+ final TestConfigurationContainer root = new TestConfigurationContainer();
+ final Configuration rootOverrideConfig = new Configuration();
+ rootOverrideConfig.fontScale = 1.3f;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+ // Init child's config.
+ final TestConfigurationContainer child = root.addChild();
+ final Configuration childOverrideConfig = new Configuration();
+ childOverrideConfig.densityDpi = 320;
+ child.onOverrideConfigurationChanged(childOverrideConfig);
+
+ // Check configuration update when child is removed from parent.
+ root.removeChild(child);
+ assertEquals(childOverrideConfig, child.getOverrideConfiguration());
+ assertEquals(childOverrideConfig, child.getMergedOverrideConfiguration());
+ assertEquals(childOverrideConfig, child.getConfiguration());
+
+ // It may be paranoia... but let's check if parent's config didn't change after removal.
+ assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getConfiguration());
+
+ // Check configuration update when child is added to parent.
+ final Configuration mergedOverrideConfig = new Configuration(root.getConfiguration());
+ mergedOverrideConfig.updateFrom(childOverrideConfig);
+ root.addChild(child);
+ assertEquals(childOverrideConfig, child.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig, child.getMergedOverrideConfiguration());
+ assertEquals(mergedOverrideConfig, child.getConfiguration());
+ }
+
+ @Test
+ public void testConfigurationChangePropagation() throws Exception {
+ // Builds 3-level vertical hierarchy with one configuration container on each level.
+ // In addition to different overrides on each level, everyone in hierarchy will have one
+ // common overridden value - orientation;
+
+ // Init root's config.
+ final TestConfigurationContainer root = new TestConfigurationContainer();
+ final Configuration rootOverrideConfig = new Configuration();
+ rootOverrideConfig.fontScale = 1.3f;
+ rootOverrideConfig.orientation = SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+ // Init children.
+ final TestConfigurationContainer child1 = root.addChild();
+ final Configuration childOverrideConfig1 = new Configuration();
+ childOverrideConfig1.densityDpi = 320;
+ childOverrideConfig1.orientation = SCREEN_ORIENTATION_LANDSCAPE;
+ child1.onOverrideConfigurationChanged(childOverrideConfig1);
+
+ final TestConfigurationContainer child2 = child1.addChild();
+ final Configuration childOverrideConfig2 = new Configuration();
+ childOverrideConfig2.screenWidthDp = 150;
+ childOverrideConfig2.orientation = SCREEN_ORIENTATION_PORTRAIT;
+ child2.onOverrideConfigurationChanged(childOverrideConfig2);
+
+ // Check configuration on all levels when root override is updated.
+ rootOverrideConfig.smallestScreenWidthDp = 200;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+ final Configuration mergedOverrideConfig1 = new Configuration(rootOverrideConfig);
+ mergedOverrideConfig1.updateFrom(childOverrideConfig1);
+ final Configuration mergedConfig1 = new Configuration(mergedOverrideConfig1);
+
+ final Configuration mergedOverrideConfig2 = new Configuration(mergedOverrideConfig1);
+ mergedOverrideConfig2.updateFrom(childOverrideConfig2);
+ final Configuration mergedConfig2 = new Configuration(mergedOverrideConfig2);
+
+ assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getConfiguration());
+
+ assertEquals(childOverrideConfig1, child1.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig1, child1.getConfiguration());
+
+ assertEquals(childOverrideConfig2, child2.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig2, child2.getConfiguration());
+
+ // Check configuration on all levels when root parent config is updated.
+ final Configuration rootParentConfig = new Configuration();
+ rootParentConfig.screenHeightDp = 100;
+ rootParentConfig.orientation = SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+ root.onConfigurationChanged(rootParentConfig);
+ final Configuration mergedRootConfig = new Configuration(rootParentConfig);
+ mergedRootConfig.updateFrom(rootOverrideConfig);
+
+ mergedConfig1.setTo(mergedRootConfig);
+ mergedConfig1.updateFrom(mergedOverrideConfig1);
+
+ mergedConfig2.setTo(mergedConfig1);
+ mergedConfig2.updateFrom(mergedOverrideConfig2);
+
+ assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+ assertEquals(mergedRootConfig, root.getConfiguration());
+
+ assertEquals(childOverrideConfig1, child1.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig1, child1.getConfiguration());
+
+ assertEquals(childOverrideConfig2, child2.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig2, child2.getConfiguration());
+ }
+
+ /**
+ * Contains minimal implementation of {@link ConfigurationContainer}'s abstract behavior needed
+ * for testing.
+ */
+ private class TestConfigurationContainer
+ extends ConfigurationContainer<TestConfigurationContainer> {
+ private List<TestConfigurationContainer> mChildren = new ArrayList<>();
+ private TestConfigurationContainer mParent;
+
+ TestConfigurationContainer addChild(TestConfigurationContainer childContainer) {
+ childContainer.mParent = this;
+ childContainer.onParentChanged();
+ mChildren.add(childContainer);
+ return childContainer;
+ }
+
+ TestConfigurationContainer addChild() {
+ return addChild(new TestConfigurationContainer());
+ }
+
+ void removeChild(TestConfigurationContainer child) {
+ child.mParent = null;
+ child.onParentChanged();
+ }
+
+ @Override
+ protected int getChildCount() {
+ return mChildren.size();
+ }
+
+ @Override
+ protected TestConfigurationContainer getChildAt(int index) {
+ return mChildren.get(index);
+ }
+
+ @Override
+ protected ConfigurationContainer getParent() {
+ return mParent;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java b/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java
new file mode 100644
index 0000000..b47d17e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/TaskStackChangedListenerTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static android.support.test.InstrumentationRegistry.getInstrumentation;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.ITaskStackListener;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiDevice;
+
+import com.android.internal.annotations.GuardedBy;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TaskStackChangedListenerTest extends ITaskStackListener.Stub {
+
+ private IActivityManager mService;
+
+ private static final Object sLock = new Object();
+ @GuardedBy("sLock")
+ private static boolean sTaskStackChangedCalled;
+ private static boolean sActivityBResumed;
+
+ @Before
+ public void setUp() throws Exception {
+ mService = ActivityManagerNative.getDefault();
+ mService.registerTaskStackListener(this);
+ }
+
+ @Test
+ public void testTaskStackChanged_afterFinish() throws Exception {
+ Context ctx = InstrumentationRegistry.getContext();
+ ctx.startActivity(new Intent(ctx, ActivityA.class));
+ UiDevice.getInstance(getInstrumentation()).waitForIdle();
+ synchronized (sLock) {
+ Assert.assertTrue(sTaskStackChangedCalled);
+ }
+ Assert.assertTrue(sActivityBResumed);
+ }
+
+ @Override
+ public void onTaskStackChanged() throws RemoteException {
+ synchronized (sLock) {
+ sTaskStackChangedCalled = true;
+ }
+ }
+
+ @Override
+ public void onActivityPinned() throws RemoteException {
+ }
+
+ @Override
+ public void onPinnedActivityRestartAttempt() throws RemoteException {
+ }
+
+ @Override
+ public void onPinnedStackAnimationEnded() throws RemoteException {
+ }
+
+ @Override
+ public void onActivityForcedResizable(String packageName, int taskId) throws RemoteException {
+ }
+
+ @Override
+ public void onActivityDismissingDockedStack() throws RemoteException {
+ }
+
+ public static class ActivityA extends Activity {
+
+ private boolean mActivityBLaunched = false;
+
+ @Override
+ protected void onPostResume() {
+ super.onPostResume();
+ if (mActivityBLaunched) {
+ return;
+ }
+ mActivityBLaunched = true;
+ finish();
+ startActivity(new Intent(this, ActivityB.class));
+ }
+ }
+
+ public static class ActivityB extends Activity {
+
+ @Override
+ protected void onPostResume() {
+ super.onPostResume();
+ synchronized (sLock) {
+ sTaskStackChangedCalled = false;
+ }
+ sActivityBResumed = true;
+ finish();
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java b/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 63d5d9fb..9e2fd62 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -158,7 +158,8 @@
void log(int netId, int[] latencies) {
for (int l : latencies) {
- mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l);
+ mNetdEventListenerService.onDnsEvent(netId, EVENT_TYPE, RETURN_CODE, l, null, null, 0,
+ 0);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java b/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java
index 5d8b843..b51b277 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java
+++ b/services/tests/servicestests/src/com/android/server/connectivity/VpnTest.java
@@ -25,9 +25,11 @@
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.net.NetworkInfo.DetailedState;
import android.net.UidRange;
import android.os.INetworkManagementService;
import android.os.Looper;
@@ -43,6 +45,8 @@
import java.util.Map;
import java.util.Set;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -88,14 +92,18 @@
@Mock private PackageManager mPackageManager;
@Mock private INetworkManagementService mNetService;
@Mock private AppOpsManager mAppOps;
+ @Mock private NotificationManager mNotificationManager;
@Override
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
setMockedPackages(mPackages);
+ when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
+ when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
+ .thenReturn(mNotificationManager);
doNothing().when(mNetService).registerObserver(any());
}
@@ -103,7 +111,7 @@
public void testRestrictedProfilesAreAddedToVpn() {
setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
- final Vpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null);
@@ -117,7 +125,7 @@
public void testManagedProfilesAreNotAddedToVpn() {
setMockedUsers(primaryUser, managedProfileA);
- final Vpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null);
@@ -130,7 +138,7 @@
public void testAddUserToVpnOnlyAddsOneUser() {
setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
- final Vpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
final Set<UidRange> ranges = new ArraySet<>();
vpn.addUserToRanges(ranges, primaryUser.id, null, null);
@@ -141,7 +149,7 @@
@SmallTest
public void testUidWhiteAndBlacklist() throws Exception {
- final Vpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
final UidRange user = UidRange.createForUser(primaryUser.id);
final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
@@ -166,15 +174,15 @@
@SmallTest
public void testLockdownChangingPackage() throws Exception {
- final MockVpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
final UidRange user = UidRange.createForUser(primaryUser.id);
// Default state.
- vpn.assertUnblocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
// Set always-on without lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
- vpn.assertUnblocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
// Set always-on with lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
@@ -182,8 +190,8 @@
new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
}));
- vpn.assertBlocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
- vpn.assertUnblocked(user.start + PKG_UIDS[1]);
+ assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[1]);
// Switch to another app.
assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
@@ -195,13 +203,13 @@
new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
}));
- vpn.assertBlocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
- vpn.assertUnblocked(user.start + PKG_UIDS[3]);
+ assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[3]);
}
@SmallTest
public void testLockdownAddingAProfile() throws Exception {
- final MockVpn vpn = new MockVpn(primaryUser.id);
+ final Vpn vpn = spyVpn(primaryUser.id);
setMockedUsers(primaryUser);
// Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
@@ -220,7 +228,7 @@
}));
// Verify restricted user isn't affected at first.
- vpn.assertUnblocked(profile.start + PKG_UIDS[0]);
+ assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
// Add the restricted user.
setMockedUsers(primaryUser, tempProfile);
@@ -239,24 +247,53 @@
}));
}
+ @SmallTest
+ public void testNotificationShownForAlwaysOnApp() {
+ final Vpn vpn = spyVpn(primaryUser.id);
+ final InOrder order = inOrder(vpn);
+ setMockedUsers(primaryUser);
+
+ // Don't show a notification for regular disconnected states.
+ vpn.updateState(DetailedState.DISCONNECTED, TAG);
+ order.verify(vpn).updateAlwaysOnNotificationInternal(false);
+
+ // Start showing a notification for disconnected once always-on.
+ vpn.setAlwaysOnPackage(PKGS[0], false);
+ order.verify(vpn).updateAlwaysOnNotificationInternal(true);
+
+ // Stop showing the notification once connected.
+ vpn.updateState(DetailedState.CONNECTED, TAG);
+ order.verify(vpn).updateAlwaysOnNotificationInternal(false);
+
+ // Show the notification if we disconnect again.
+ vpn.updateState(DetailedState.DISCONNECTED, TAG);
+ order.verify(vpn).updateAlwaysOnNotificationInternal(true);
+
+ // Notification should be cleared after unsetting always-on package.
+ vpn.setAlwaysOnPackage(null, false);
+ order.verify(vpn).updateAlwaysOnNotificationInternal(false);
+ }
+
/**
- * A subclass of {@link Vpn} with some of the fields pre-mocked.
+ * Mock some methods of vpn object.
*/
- private class MockVpn extends Vpn {
- public MockVpn(@UserIdInt int userId) {
- super(Looper.myLooper(), mContext, mNetService, userId);
- }
+ private Vpn spyVpn(@UserIdInt int userId) {
+ final Vpn vpn = spy(new Vpn(Looper.myLooper(), mContext, mNetService, userId));
- public void assertBlocked(int... uids) {
- for (int uid : uids) {
- assertTrue("Uid " + uid + " should be blocked", isBlockingUid(uid));
- }
- }
+ // Block calls to the NotificationManager or PendingIntent#getActivity.
+ doNothing().when(vpn).updateAlwaysOnNotificationInternal(anyBoolean());
+ return vpn;
+ }
- public void assertUnblocked(int... uids) {
- for (int uid : uids) {
- assertFalse("Uid " + uid + " should not be blocked", isBlockingUid(uid));
- }
+ private static void assertBlocked(Vpn vpn, int... uids) {
+ for (int uid : uids) {
+ assertTrue("Uid " + uid + " should be blocked", vpn.isBlockingUid(uid));
+ }
+ }
+
+ private static void assertUnblocked(Vpn vpn, int... uids) {
+ for (int uid : uids) {
+ assertFalse("Uid " + uid + " should not be blocked", vpn.isBlockingUid(uid));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 01b2c3b..56ff621 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1915,6 +1915,61 @@
verifyScreenTimeoutCall(Integer.MAX_VALUE, false);
}
+ public void testSetRequiredStrongAuthTimeout_DeviceOwner() throws Exception {
+ mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+ setupDeviceOwner();
+ mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+ final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1h
+ final long ONE_MINUTE = 60 * 1000;
+
+ // aggregation should be the default if unset by any admin
+ assertEquals(dpm.getRequiredStrongAuthTimeout(null),
+ DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+ // admin not participating by default
+ assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);
+
+ //clamping from the top
+ dpm.setRequiredStrongAuthTimeout(admin1,
+ DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE);
+ assertEquals(dpm.getRequiredStrongAuthTimeout(admin1),
+ DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+ assertEquals(dpm.getRequiredStrongAuthTimeout(null),
+ DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+ // 0 means default
+ dpm.setRequiredStrongAuthTimeout(admin1, 0);
+ assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);
+ assertEquals(dpm.getRequiredStrongAuthTimeout(null),
+ DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+ // clamping from the bottom
+ dpm.setRequiredStrongAuthTimeout(admin1, MINIMUM_STRONG_AUTH_TIMEOUT_MS - ONE_MINUTE);
+ assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS);
+ assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS);
+
+ // value within range
+ dpm.setRequiredStrongAuthTimeout(admin1, MINIMUM_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE);
+ assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS
+ + ONE_MINUTE);
+ assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS
+ + ONE_MINUTE);
+
+ // reset to default
+ dpm.setRequiredStrongAuthTimeout(admin1, 0);
+ assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);
+ assertEquals(dpm.getRequiredStrongAuthTimeout(null),
+ DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
+
+ // negative value
+ try {
+ dpm.setRequiredStrongAuthTimeout(admin1, -ONE_MINUTE);
+ fail("Didn't throw IllegalArgumentException");
+ } catch (IllegalArgumentException iae) {
+ }
+ }
+
private void verifyScreenTimeoutCall(Integer expectedTimeout,
boolean shouldStayOnWhilePluggedInBeCleared) {
if (expectedTimeout == null) {
diff --git a/services/tests/servicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/SnoozeHelperTest.java
new file mode 100644
index 0000000..ec1fdad
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.notification;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SnoozeHelperTest {
+ @Mock SnoozeHelper.Callback mCallback;
+ @Mock AlarmManager mAm;
+ @Mock ManagedServices.UserProfiles mUserProfiles;
+
+ private SnoozeHelper mSnoozeHelper;
+
+ private Context getContext() {
+ return InstrumentationRegistry.getTargetContext();
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mSnoozeHelper = new SnoozeHelper(getContext(), mCallback, mUserProfiles);
+ mSnoozeHelper.setAlarmManager(mAm);
+ }
+
+ @Test
+ public void testSnooze() throws Exception {
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
+ verify(mAm, times(1)).setExactAndAllowWhileIdle(
+ anyInt(), eq((long) 1000), any(PendingIntent.class));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+ }
+
+ @Test
+ public void testCancelByApp() throws Exception {
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
+ mSnoozeHelper.snooze(r2 , UserHandle.USER_SYSTEM, 1000);
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey()));
+
+ mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, r.sbn.getPackageName(), "one", 1);
+ // 3 = one for each snooze, above + one for cancel itself.
+ verify(mAm, times(3)).cancel(any(PendingIntent.class));
+ assertFalse(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey()));
+ }
+
+ @Test
+ public void testCancelAllForUser() throws Exception {
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
+ NotificationRecord r3 = getNotificationRecord("pkg", 3, "three", UserHandle.ALL);
+ mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
+ mSnoozeHelper.snooze(r2 , UserHandle.USER_SYSTEM, 1000);
+ mSnoozeHelper.snooze(r3 , UserHandle.USER_ALL, 1000);
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_ALL, r3.sbn.getPackageName(), r3.getKey()));
+
+ mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, false);
+ // 5 = once for each snooze above (3) + once for each notification canceled (2).
+ verify(mAm, times(5)).cancel(any(PendingIntent.class));
+ assertFalse(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+ assertFalse(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_ALL, r3.sbn.getPackageName(), r3.getKey()));
+ }
+
+ @Test
+ public void testCancelAllByApp() throws Exception {
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
+ NotificationRecord r3 = getNotificationRecord("pkg2", 3, "three", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
+ mSnoozeHelper.snooze(r2 , UserHandle.USER_SYSTEM, 1000);
+ mSnoozeHelper.snooze(r3 , UserHandle.USER_SYSTEM, 1000);
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r3.sbn.getPackageName(), r3.getKey()));
+
+ mSnoozeHelper.cancel(UserHandle.USER_SYSTEM, "pkg2");
+ // 4 = once for each snooze above (3) + once for each notification canceled (1).
+ verify(mAm, times(4)).cancel(any(PendingIntent.class));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
+ assertTrue(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r2.sbn.getPackageName(), r2.getKey()));
+ assertFalse(mSnoozeHelper.isSnoozed(
+ UserHandle.USER_SYSTEM, r3.sbn.getPackageName(), r3.getKey()));
+ }
+
+ @Test
+ public void testRepost() throws Exception {
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
+ NotificationRecord r2 = getNotificationRecord("pkg", 2, "one", UserHandle.ALL);
+ mSnoozeHelper.snooze(r2 , UserHandle.USER_ALL, 1000);
+ mSnoozeHelper.repost(r.sbn.getPackageName(), r.getKey(), UserHandle.USER_SYSTEM);
+ verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
+ }
+
+ @Test
+ public void testUpdate() throws Exception {
+ NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
+ mSnoozeHelper.snooze(r , UserHandle.USER_SYSTEM, 1000);
+ r.getNotification().category = "NEW CATEGORY";
+
+ mSnoozeHelper.update(UserHandle.USER_SYSTEM, r);
+ verify(mCallback, never()).repost(anyInt(), any(NotificationRecord.class));
+
+ mSnoozeHelper.repost(r.sbn.getPackageName(), r.getKey(), UserHandle.USER_SYSTEM);
+ verify(mCallback, times(1)).repost(UserHandle.USER_SYSTEM, r);
+ }
+
+ private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
+ UserHandle user) {
+ Notification n = new Notification.Builder(getContext())
+ .setContentTitle("A")
+ .setGroup("G")
+ .setSortKey("A")
+ .setWhen(1205)
+ .build();
+ return new NotificationRecord(getContext(), new StatusBarNotification(
+ pkg, pkg, id, tag, 0, 0, 0, n, user),
+ new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name"));
+ }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 53c6a33..bd2bb6c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -115,14 +115,14 @@
Settings settings =
new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object());
assertThat(settings.readLPw(createFakeUsers()), is(true));
- assertThat(settings.peekPackageLPr(PACKAGE_NAME_3), is(notNullValue()));
- assertThat(settings.peekPackageLPr(PACKAGE_NAME_1), is(notNullValue()));
+ assertThat(settings.getPackageLPr(PACKAGE_NAME_3), is(notNullValue()));
+ assertThat(settings.getPackageLPr(PACKAGE_NAME_1), is(notNullValue()));
- PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
+ PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_1);
assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DEFAULT));
assertThat(ps.getNotLaunched(0), is(true));
- ps = settings.peekPackageLPr(PACKAGE_NAME_2);
+ ps = settings.getPackageLPr(PACKAGE_NAME_2);
assertThat(ps.getStopped(0), is(false));
assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED_USER));
assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_DEFAULT));
@@ -141,7 +141,7 @@
settings = new Settings(InstrumentationRegistry.getContext().getFilesDir(), new Object());
assertThat(settings.readLPw(createFakeUsers()), is(true));
- PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_2);
+ PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_2);
assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED_USER));
assertThat(ps.getEnabled(1), is(COMPONENT_ENABLED_STATE_DEFAULT));
}
@@ -155,7 +155,7 @@
assertThat(settings.readLPw(createFakeUsers()), is(true));
// Enable/Disable a package
- PackageSetting ps = settings.peekPackageLPr(PACKAGE_NAME_1);
+ PackageSetting ps = settings.getPackageLPr(PACKAGE_NAME_1);
ps.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0, null);
ps.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 1, null);
assertThat(ps.getEnabled(0), is(COMPONENT_ENABLED_STATE_DISABLED));
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 6a434ca..1f0422b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.app.ActivityManager;
import android.os.Bundle;
@@ -46,16 +47,24 @@
private static final int REMOVE_TIMEOUT_MILLIS = 60 * 1000; // 60 seconds
private static final int SWITCH_USER_TIMEOUT_MILLIS = 40 * 1000; // 40 seconds
+ // Packages which are used during tests.
+ private static final String[] PACKAGES = new String[] {
+ "com.android.egg",
+ "com.android.retaildemo"
+ };
+
private final Object mUserRemoveLock = new Object();
private final Object mUserSwitchLock = new Object();
private UserManager mUserManager = null;
+ private PackageManager mPackageManager;
private List<Integer> usersToRemove;
@Override
public void setUp() throws Exception {
super.setUp();
mUserManager = UserManager.get(getContext());
+ mPackageManager = getContext().getPackageManager();
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_SWITCHED);
@@ -185,6 +194,81 @@
assertFalse(mUserManager.isManagedProfile());
}
+ // Verify that disallowed packages are not installed in the managed profile.
+ @MediumTest
+ public void testAddManagedProfile_withDisallowedPackages() throws Exception {
+ final int primaryUserId = mUserManager.getPrimaryUser().id;
+ UserInfo userInfo1 = createProfileForUser("Managed1",
+ UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
+ // Verify that the packagesToVerify are installed by default.
+ for (String pkg : PACKAGES) {
+ assertTrue("Package should be installed in managed profile: " + pkg,
+ isPackageInstalledForUser(pkg, userInfo1.id));
+ }
+ removeUser(userInfo1.id);
+
+ UserInfo userInfo2 = createProfileForUser("Managed2",
+ UserInfo.FLAG_MANAGED_PROFILE, primaryUserId, PACKAGES);
+ // Verify that the packagesToVerify are not installed by default.
+ for (String pkg : PACKAGES) {
+ assertFalse("Package should not be installed in managed profile when disallowed: "
+ + pkg, isPackageInstalledForUser(pkg, userInfo2.id));
+ }
+ }
+
+ // Verify that if any packages are disallowed to install during creation of managed profile can
+ // still be installed later.
+ @MediumTest
+ public void testAddManagedProfile_disallowedPackagesInstalledLater() throws Exception {
+ final int primaryUserId = mUserManager.getPrimaryUser().id;
+ UserInfo userInfo = createProfileForUser("Managed",
+ UserInfo.FLAG_MANAGED_PROFILE, primaryUserId, PACKAGES);
+ // Verify that the packagesToVerify are not installed by default.
+ for (String pkg : PACKAGES) {
+ assertFalse("Package should not be installed in managed profile when disallowed: "
+ + pkg, isPackageInstalledForUser(pkg, userInfo.id));
+ }
+
+ // Verify that the disallowed packages during profile creation can be installed now.
+ for (String pkg : PACKAGES) {
+ assertEquals("Package could not be installed: " + pkg,
+ PackageManager.INSTALL_SUCCEEDED,
+ mPackageManager.installExistingPackageAsUser(pkg, userInfo.id));
+ }
+ }
+
+ // Make sure createProfile would fail if we have DISALLOW_ADD_USER.
+ @MediumTest
+ public void testCreateProfileForUser_disallowAddUser() throws Exception {
+ final int primaryUserId = mUserManager.getPrimaryUser().id;
+ final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, primaryUserHandle);
+ try {
+ UserInfo userInfo = createProfileForUser("Managed",
+ UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
+ assertNull(userInfo);
+ } finally {
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false,
+ primaryUserHandle);
+ }
+ }
+
+ // Make sure createProfileEvenWhenDisallowedForUser bypass DISALLOW_ADD_USER.
+ @MediumTest
+ public void testCreateProfileForUserEvenWhenDisallowed() throws Exception {
+ final int primaryUserId = mUserManager.getPrimaryUser().id;
+ final UserHandle primaryUserHandle = new UserHandle(primaryUserId);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, true, primaryUserHandle);
+ try {
+ UserInfo userInfo = createProfileEvenWhenDisallowedForUser("Managed",
+ UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
+ assertNotNull(userInfo);
+ } finally {
+ mUserManager.setUserRestriction(UserManager.DISALLOW_ADD_USER, false,
+ primaryUserHandle);
+ }
+ }
+
@MediumTest
public void testAddRestrictedProfile() throws Exception {
UserInfo userInfo = createRestrictedProfile("Profile");
@@ -357,6 +441,14 @@
switchUser(startUser);
}
+ private boolean isPackageInstalledForUser(String packageName, int userId) {
+ try {
+ return mPackageManager.getPackageInfoAsUser(packageName, 0, userId) != null;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
private void switchUser(int userId) {
synchronized (mUserSwitchLock) {
ActivityManager am = getContext().getSystemService(ActivityManager.class);
@@ -401,7 +493,23 @@
}
private UserInfo createProfileForUser(String name, int flags, int userHandle) {
- UserInfo profile = mUserManager.createProfileForUser(name, flags, userHandle);
+ return createProfileForUser(name, flags, userHandle, null);
+ }
+
+ private UserInfo createProfileForUser(String name, int flags, int userHandle,
+ String[] disallowedPackages) {
+ UserInfo profile = mUserManager.createProfileForUser(
+ name, flags, userHandle, disallowedPackages);
+ if (profile != null) {
+ usersToRemove.add(profile.id);
+ }
+ return profile;
+ }
+
+ private UserInfo createProfileEvenWhenDisallowedForUser(String name, int flags,
+ int userHandle) {
+ UserInfo profile = mUserManager.createProfileForUserEvenWhenDisallowed(
+ name, flags, userHandle, null);
if (profile != null) {
usersToRemove.add(profile.id);
}
diff --git a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
index 56a170c..e4473ad 100644
--- a/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/retaildemo/RetailDemoModeServiceTest.java
@@ -46,6 +46,7 @@
import android.content.res.Configuration;
import android.media.AudioManager;
import android.net.Uri;
+import android.net.wifi.WifiManager;
import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
@@ -62,7 +63,6 @@
import com.android.internal.util.FakeSettingsProvider;
import com.android.internal.widget.LockPatternUtils;
-import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.retaildemo.RetailDemoModeService.Injector;
@@ -75,7 +75,6 @@
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.io.File;
@@ -97,6 +96,7 @@
private @Mock NotificationManager mNm;
private @Mock ActivityManagerInternal mAmi;
private @Mock AudioManager mAudioManager;
+ private @Mock WifiManager mWifiManager;
private @Mock LockPatternUtils mLockPatternUtils;
private MockPreloadAppsInstaller mPreloadAppsInstaller;
private MockContentResolver mContentResolver;
@@ -135,9 +135,6 @@
@After
public void tearDown() {
- // Remove the RetailDemoModeServiceInternal from LocalServices which would've been
- // added during initialization of RetailDemoModeService in setUp().
- LocalServices.removeServiceForTest(RetailDemoModeServiceInternal.class);
FileUtils.deleteContentsAndDir(mTestPreloadsDir);
}
@@ -145,23 +142,22 @@
public void testDemoUserSetup() throws Exception {
mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
+ mLatch = new CountDownLatch(1);
+ final UserInfo userInfo = new UserInfo();
+ userInfo.id = TEST_DEMO_USER;
+ when(mUm.createUser(anyString(), anyInt())).thenReturn(userInfo);
+
+ setCameraPackage(TEST_CAMERA_PKG);
+ mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+ assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set",
+ "1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED));
+
final ArgumentCaptor<IntentFilter> intentFilter =
ArgumentCaptor.forClass(IntentFilter.class);
verify(mContext).registerReceiver(any(BroadcastReceiver.class), intentFilter.capture());
assertTrue("Not registered for " + Intent.ACTION_SCREEN_OFF,
intentFilter.getValue().hasAction(Intent.ACTION_SCREEN_OFF));
- mLatch = new CountDownLatch(1);
-
- mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
- assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set",
- "1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED));
-
- final UserInfo userInfo = new UserInfo();
- userInfo.id = TEST_DEMO_USER;
- when(mUm.createUser(anyString(), anyInt())).thenReturn(userInfo);
- mInjector.setDemoUserId(TEST_DEMO_USER);
- setCameraPackage(TEST_CAMERA_PKG);
// Wait for the setup to complete.
mLatch.await(SETUP_COMPLETE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
ArgumentCaptor<Integer> flags = ArgumentCaptor.forClass(Integer.class);
@@ -197,7 +193,36 @@
}
@Test
- public void testSettingsObserver() throws Exception {
+ public void testSettingsObserver_disableDemoMode() throws Exception {
+ final RetailDemoModeService.SettingsObserver observer =
+ mService.new SettingsObserver(new Handler(Looper.getMainLooper()));
+ final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE);
+ when(mUm.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT, UserHandle.SYSTEM))
+ .thenReturn(false);
+ Settings.Global.putInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE, 1);
+ // Settings.Global.DEVICE_DEMO_MODE has been set to 1 initially.
+ observer.onChange(false, deviceDemoModeUri);
+ final ArgumentCaptor<BroadcastReceiver> receiver =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mContext).registerReceiver(receiver.capture(), any(IntentFilter.class));
+
+ Settings.Global.putInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
+ new File(mTestPreloadsDir, "dir1").mkdirs();
+ new File(mTestPreloadsDir, "file1").createNewFile();
+ Settings.Global.putInt(mContentResolver, Settings.Global.DEVICE_DEMO_MODE, 0);
+ observer.onChange(false, deviceDemoModeUri);
+ verify(mContext).unregisterReceiver(receiver.getValue());
+ verify(mUm).setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, false, UserHandle.SYSTEM);
+ assertEquals("Package verifier enable value has not been reset", 1,
+ Settings.Global.getInt(mContentResolver, Settings.Global.PACKAGE_VERIFIER_ENABLE));
+ Thread.sleep(20); // Wait for the deletion to complete.
+ // verify that the preloaded directory is emptied.
+ assertEquals("Preloads directory is not emptied",
+ 0, mTestPreloadsDir.list().length);
+ }
+
+ @Test
+ public void testSettingsObserver_enableDemoMode() throws Exception {
final RetailDemoModeService.SettingsObserver observer =
mService.new SettingsObserver(new Handler(Looper.getMainLooper()));
final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE);
@@ -206,14 +231,11 @@
assertEquals(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED + " property not set",
"1", mInjector.systemPropertiesGet(SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED));
- new File(mTestPreloadsDir, "dir1").mkdirs();
- new File(mTestPreloadsDir, "file1").createNewFile();
- Settings.Global.putInt(mContentResolver, Settings.Global.DEVICE_DEMO_MODE, 0);
- observer.onChange(false, deviceDemoModeUri);
- Thread.sleep(20); // Wait for the deletion to complete.
- // verify that the preloaded directory is emptied.
- assertEquals("Preloads directory is not emptied",
- 0, mTestPreloadsDir.list().length);
+ final ArgumentCaptor<IntentFilter> intentFilter =
+ ArgumentCaptor.forClass(IntentFilter.class);
+ verify(mContext).registerReceiver(any(BroadcastReceiver.class), intentFilter.capture());
+ assertTrue("Not registered for " + Intent.ACTION_SCREEN_OFF,
+ intentFilter.getValue().hasAction(Intent.ACTION_SCREEN_OFF));
}
@Test
@@ -227,6 +249,7 @@
final UserInfo userInfo = new UserInfo(TEST_DEMO_USER, "demo_user",
UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL);
when(mUm.getUserInfo(TEST_DEMO_USER)).thenReturn(userInfo);
+ when(mWifiManager.isWifiEnabled()).thenReturn(false);
final int minVolume = -111;
for (int stream : RetailDemoModeService.VOLUME_STREAMS_TO_MUTE) {
when(mAudioManager.getStreamMinVolume(stream)).thenReturn(minVolume);
@@ -238,6 +261,7 @@
verify(mAudioManager).setStreamVolume(stream, minVolume, 0);
}
verify(mLockPatternUtils).setLockScreenDisabled(true, TEST_DEMO_USER);
+ verify(mWifiManager).setWifiEnabled(true);
}
private void setCameraPackage(String pkgName) {
@@ -304,7 +328,6 @@
private class TestInjector extends Injector {
private ArrayMap<String, String> mSystemProperties = new ArrayMap<>();
- private int mDemoUserId = UserHandle.USER_NULL;
TestInjector() {
super(mContext);
@@ -321,6 +344,11 @@
}
@Override
+ WifiManager getWifiManager() {
+ return mWifiManager;
+ }
+
+ @Override
void switchUser(int userId) {
if (mLatch != null) {
mLatch.countDown();
@@ -376,6 +404,10 @@
}
@Override
+ void destroyWakeLock() {
+ }
+
+ @Override
boolean isWakeLockHeld() {
return false;
}
@@ -416,12 +448,13 @@
return mTestPreloadsDir;
}
- String systemPropertiesGet(String key) {
- return mSystemProperties.get(key);
+ @Override
+ void publishLocalService(RetailDemoModeService service,
+ RetailDemoModeServiceInternal localService) {
}
- void setDemoUserId(int userId) {
- mDemoUserId = userId;
+ String systemPropertiesGet(String key) {
+ return mSystemProperties.get(key);
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java b/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java
new file mode 100644
index 0000000..d378b7c56
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java
@@ -0,0 +1,210 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import static com.android.server.utils.PriorityDump.dump;
+
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.verify;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import com.android.server.utils.PriorityDump.PriorityDumper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class PriorityDumpTest {
+
+ private static final String[] EMPTY_ARGS = {};
+
+ @Mock
+ private PriorityDumper mDumper;
+ @Mock
+ private PrintWriter mPw;
+
+ private final FileDescriptor mFd = FileDescriptor.err;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testNullArgs() {
+ dump(mDumper, mFd, mPw, null);
+ verify(mDumper).dump(same(mFd), same(mPw), eq(null));
+ }
+
+ @Test
+ public void testNoArgs() {
+ dump(mDumper, mFd, mPw, EMPTY_ARGS);
+ verify(mDumper).dump(same(mFd), same(mPw), same(EMPTY_ARGS));
+ }
+
+ @Test
+ public void testNonPriorityArgs() {
+ final String[] args = {
+ "--dumb_priority"
+ };
+ dump(mDumper, mFd, mPw, args);
+ verify(mDumper).dump(same(mFd), same(mPw), same(args));
+ }
+
+ @Test
+ public void testMissingPriority() {
+ final String[] args = {
+ "--dump_priority"
+ };
+ dump(mDumper, mFd, mPw, args);
+ verify(mDumper).dump(same(mFd), same(mPw), same(args));
+ }
+
+ @Test
+ public void testInvalidPriorityNoExtraArgs() {
+ final String[] args = {
+ "--dump_priority", "SUPER_HIGH"
+ };
+ dump(mDumper, mFd, mPw, args);
+ verify(mDumper).dump(same(mFd), same(mPw), same(args));
+ }
+
+ @Test
+ public void testInvalidPriorityExtraArgs() {
+ final String[] args = {
+ "--dump_priority", "SUPER_HIGH", "--high", "--five"
+ };
+ dump(mDumper, mFd, mPw, args);
+ verify(mDumper).dump(same(mFd), same(mPw), same(args));
+ }
+
+ @Test
+ public void testNoPriorityCallsAllMethods() {
+ final String[] args = {
+ "1", "2", "3"
+ };
+
+ // Cannot use mDumper here because it would mock the dump() call.
+ final FakeDumper fakeDumper = new FakeDumper();
+
+ dump(fakeDumper, mFd, mPw, args);
+
+ assertSame(mFd, fakeDumper.criticalFd);
+ assertSame(mPw, fakeDumper.criticalPw);
+ assertSame(args, fakeDumper.criticalArgs);
+ assertSame(mFd, fakeDumper.highFd);
+ assertSame(mPw, fakeDumper.highPw);
+ assertSame(args, fakeDumper.highArgs);
+ assertSame(mFd, fakeDumper.normalFd);
+ assertSame(mPw, fakeDumper.normalPw);
+ assertSame(args, fakeDumper.normalArgs);
+ }
+
+ @Test
+ public void testCriticalNoExtraArgs() {
+ dump(mDumper, mFd, mPw, new String[] {
+ "--dump_priority", "CRITICAL"
+ });
+ verify(mDumper).dumpCritical(same(mFd), same(mPw), eq(EMPTY_ARGS));
+ }
+
+ @Test
+ public void testCriticalExtraArgs() {
+ dump(mDumper, mFd, mPw, new String[] {
+ "--dump_priority", "CRITICAL", "--high", "--five"
+ });
+ verify(mDumper).dumpCritical(same(mFd), same(mPw), eq(new String[] {
+ "--high", "--five"
+ }));
+ }
+
+ @Test
+ public void testHighNoExtraArgs() {
+ dump(mDumper, mFd, mPw, new String[] {
+ "--dump_priority", "HIGH"
+ });
+ verify(mDumper).dumpHigh(same(mFd), same(mPw), eq(EMPTY_ARGS));
+ }
+
+ @Test
+ public void testHighExtraArgs() {
+ dump(mDumper, mFd, mPw, new String[] {
+ "--dump_priority", "HIGH", "--high", "--five"
+ });
+ verify(mDumper).dumpHigh(same(mFd), same(mPw), eq(new String[] {
+ "--high", "--five"
+ }));
+ }
+
+ @Test
+ public void testNormalNoExtraArgs() {
+ dump(mDumper, mFd, mPw, new String[] {
+ "--dump_priority", "NORMAL"
+ });
+ verify(mDumper).dumpNormal(same(mFd), same(mPw), eq(EMPTY_ARGS));
+ }
+
+ @Test
+ public void testNormalExtraArgs() {
+ dump(mDumper, mFd, mPw, new String[] {
+ "--dump_priority", "NORMAL", "--high", "--five"
+ });
+ verify(mDumper).dumpNormal(same(mFd), same(mPw), eq(new String[] {
+ "--high", "--five"
+ }));
+ }
+
+ private final class FakeDumper implements PriorityDumper {
+
+ String[] criticalArgs, highArgs, normalArgs;
+ FileDescriptor criticalFd, highFd, normalFd;
+ PrintWriter criticalPw, highPw, normalPw;
+
+ @Override
+ public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
+ criticalFd = fd;
+ criticalPw = pw;
+ criticalArgs = args;
+ }
+
+ @Override
+ public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args) {
+ highFd = fd;
+ highPw = pw;
+ highArgs = args;
+ }
+
+ @Override
+ public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
+ normalFd = fd;
+ normalPw = pw;
+ normalArgs = args;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 7f171fb..0f898e5 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -303,6 +303,31 @@
WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
+ assertEquals(null, mWebViewUpdateServiceImpl.getCurrentWebViewPackage());
+
+ // Now install a package
+ String singlePackage = "singlePackage";
+ packages = new WebViewProviderInfo[]{
+ new WebViewProviderInfo(singlePackage, "", true, false, null)};
+ setupWithPackages(packages);
+ setEnabledAndValidPackageInfos(packages);
+
+ mWebViewUpdateServiceImpl.packageStateChanged(singlePackage,
+ WebViewUpdateService.PACKAGE_ADDED, 0);
+
+ checkPreparationPhasesForPackage(singlePackage, 1 /* number of finished preparations */);
+ assertEquals(singlePackage,
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
+
+ // Remove the package again
+ mTestSystemImpl.removePackageInfo(singlePackage);
+ mWebViewUpdateServiceImpl.packageStateChanged(singlePackage,
+ WebViewUpdateService.PACKAGE_ADDED, 0);
+
+ // Package removed - ensure our interface states that there is no package
+ response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+ assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
+ assertEquals(null, mWebViewUpdateServiceImpl.getCurrentWebViewPackage());
}
public void testFailListingInvalidWebviewPackage() {
@@ -395,7 +420,8 @@
Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
- assertEquals(firstPackage, mWebViewUpdateServiceImpl.getCurrentWebViewPackageName());
+ assertEquals(firstPackage,
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
new Thread(new Runnable() {
@Override
@@ -1243,4 +1269,42 @@
checkPreparationPhasesForPackage(primaryPackage, 3 /* third preparation phase */);
}
+
+ public void testGetCurrentWebViewPackage() {
+ PackageInfo firstPackage = createPackageInfo("first", true /* enabled */,
+ true /* valid */, true /* installed */);
+ firstPackage.versionCode = 100;
+ firstPackage.versionName = "first package version";
+ WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+ new WebViewProviderInfo(firstPackage.packageName, "", true, false, null)};
+ setupWithPackages(packages, true);
+ mTestSystemImpl.setPackageInfo(firstPackage);
+
+ mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+ Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
+ Mockito.argThat(new IsPackageInfoWithName(firstPackage.packageName)));
+
+ mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
+
+ // Ensure the API is correct before running waitForAndGetProvider
+ assertEquals(firstPackage.packageName,
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
+ assertEquals(firstPackage.versionCode,
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionCode);
+ assertEquals(firstPackage.versionName,
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionName);
+
+ WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+ assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
+ assertEquals(firstPackage.packageName, response.packageInfo.packageName);
+
+ // Ensure the API is still correct after running waitForAndGetProvider
+ assertEquals(firstPackage.packageName,
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
+ assertEquals(firstPackage.versionCode,
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionCode);
+ assertEquals(firstPackage.versionName,
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionName);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 27d9d10..74e8c9d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -76,15 +76,14 @@
private WindowState createWindow(WindowState parent, int type, WindowToken token) {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
- return new WindowState(sWm, null, mIWindow, token, parent, 0, 0, attrs, 0,
- sWm.getDefaultDisplayContentLocked(), 0);
+ return new WindowState(sWm, null, mIWindow, token, parent, 0, 0, attrs, 0, 0);
}
/* Used so we can gain access to some protected members of the {@link AppWindowToken} class */
private class TestAppWindowToken extends AppWindowToken {
TestAppWindowToken() {
- super(sWm, null, false);
+ super(sWm, null, false, sWm.getDefaultDisplayContentLocked());
}
int getWindowsCount() {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index eb2372a..6eb347b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -19,6 +19,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import android.content.res.Configuration;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -28,6 +29,8 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static org.junit.Assert.assertEquals;
@@ -377,6 +380,160 @@
assertEquals(1, child2223.compareTo(child21));
}
+ @Test
+ public void testConfigurationInit() throws Exception {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+
+ // Check root container initial config.
+ final TestWindowContainer root = builder.setLayer(0).build();
+ assertEquals(Configuration.EMPTY, root.getOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, root.getMergedOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, root.getConfiguration());
+
+ // Check child initial config.
+ final TestWindowContainer child1 = root.addChildWindow();
+ assertEquals(Configuration.EMPTY, child1.getOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, child1.getMergedOverrideConfiguration());
+ assertEquals(Configuration.EMPTY, child1.getConfiguration());
+
+ // Check child initial config if root has overrides.
+ final Configuration rootOverrideConfig = new Configuration();
+ rootOverrideConfig.fontScale = 1.3f;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+ final TestWindowContainer child2 = root.addChildWindow();
+ assertEquals(Configuration.EMPTY, child2.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, child2.getMergedOverrideConfiguration());
+ assertEquals(rootOverrideConfig, child2.getConfiguration());
+
+ // Check child initial config if root has parent config set.
+ final Configuration rootParentConfig = new Configuration();
+ rootParentConfig.fontScale = 0.8f;
+ rootParentConfig.orientation = SCREEN_ORIENTATION_LANDSCAPE;
+ root.onConfigurationChanged(rootParentConfig);
+ final Configuration rootFullConfig = new Configuration(rootParentConfig);
+ rootFullConfig.updateFrom(rootOverrideConfig);
+
+ final TestWindowContainer child3 = root.addChildWindow();
+ assertEquals(Configuration.EMPTY, child3.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, child3.getMergedOverrideConfiguration());
+ assertEquals(rootFullConfig, child3.getConfiguration());
+ }
+
+ @Test
+ public void testConfigurationChangeOnAddRemove() throws Exception {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+
+ // Init root's config.
+ final TestWindowContainer root = builder.setLayer(0).build();
+ final Configuration rootOverrideConfig = new Configuration();
+ rootOverrideConfig.fontScale = 1.3f;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+ // Init child's config.
+ final TestWindowContainer child = root.addChildWindow();
+ final Configuration childOverrideConfig = new Configuration();
+ childOverrideConfig.densityDpi = 320;
+ child.onOverrideConfigurationChanged(childOverrideConfig);
+
+ // Check configuration update when child is removed from parent.
+ root.removeChild(child);
+ assertEquals(childOverrideConfig, child.getOverrideConfiguration());
+ assertEquals(childOverrideConfig, child.getMergedOverrideConfiguration());
+ assertEquals(childOverrideConfig, child.getConfiguration());
+
+ // It may be paranoia... but let's check if parent's config didn't change after removal.
+ assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getConfiguration());
+
+ // Check configuration update when child is added to parent.
+ final Configuration mergedOverrideConfig = new Configuration(root.getConfiguration());
+ mergedOverrideConfig.updateFrom(childOverrideConfig);
+ root.addChildWindow(child);
+ assertEquals(childOverrideConfig, child.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig, child.getMergedOverrideConfiguration());
+ assertEquals(mergedOverrideConfig, child.getConfiguration());
+ }
+
+ @Test
+ public void testConfigurationChangePropagation() throws Exception {
+ final TestWindowContainerBuilder builder = new TestWindowContainerBuilder();
+
+ // Builds 3-level vertical hierarchy with one window container on each level.
+ // In addition to different overrides on each level, everyone in hierarchy will have one
+ // common overridden value - orientation;
+
+ // Init root's config.
+ final TestWindowContainer root = builder.setLayer(0).build();
+ final Configuration rootOverrideConfig = new Configuration();
+ rootOverrideConfig.fontScale = 1.3f;
+ rootOverrideConfig.orientation = SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+ // Init children.
+ final TestWindowContainer child1 = root.addChildWindow();
+ final Configuration childOverrideConfig1 = new Configuration();
+ childOverrideConfig1.densityDpi = 320;
+ childOverrideConfig1.orientation = SCREEN_ORIENTATION_LANDSCAPE;
+ child1.onOverrideConfigurationChanged(childOverrideConfig1);
+
+ final TestWindowContainer child2 = child1.addChildWindow();
+ final Configuration childOverrideConfig2 = new Configuration();
+ childOverrideConfig2.screenWidthDp = 150;
+ childOverrideConfig2.orientation = SCREEN_ORIENTATION_PORTRAIT;
+ child2.onOverrideConfigurationChanged(childOverrideConfig2);
+
+ // Check configuration on all levels when root override is updated.
+ rootOverrideConfig.smallestScreenWidthDp = 200;
+ root.onOverrideConfigurationChanged(rootOverrideConfig);
+
+ final Configuration mergedOverrideConfig1 = new Configuration(rootOverrideConfig);
+ mergedOverrideConfig1.updateFrom(childOverrideConfig1);
+ final Configuration mergedConfig1 = new Configuration(mergedOverrideConfig1);
+
+ final Configuration mergedOverrideConfig2 = new Configuration(mergedOverrideConfig1);
+ mergedOverrideConfig2.updateFrom(childOverrideConfig2);
+ final Configuration mergedConfig2 = new Configuration(mergedOverrideConfig2);
+
+ assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getConfiguration());
+
+ assertEquals(childOverrideConfig1, child1.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig1, child1.getConfiguration());
+
+ assertEquals(childOverrideConfig2, child2.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig2, child2.getConfiguration());
+
+ // Check configuration on all levels when root parent config is updated.
+ final Configuration rootParentConfig = new Configuration();
+ rootParentConfig.screenHeightDp = 100;
+ rootParentConfig.orientation = SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+ root.onConfigurationChanged(rootParentConfig);
+ final Configuration mergedRootConfig = new Configuration(rootParentConfig);
+ mergedRootConfig.updateFrom(rootOverrideConfig);
+
+ mergedConfig1.setTo(mergedRootConfig);
+ mergedConfig1.updateFrom(mergedOverrideConfig1);
+
+ mergedConfig2.setTo(mergedConfig1);
+ mergedConfig2.updateFrom(mergedOverrideConfig2);
+
+ assertEquals(rootOverrideConfig, root.getOverrideConfiguration());
+ assertEquals(rootOverrideConfig, root.getMergedOverrideConfiguration());
+ assertEquals(mergedRootConfig, root.getConfiguration());
+
+ assertEquals(childOverrideConfig1, child1.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig1, child1.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig1, child1.getConfiguration());
+
+ assertEquals(childOverrideConfig2, child2.getOverrideConfiguration());
+ assertEquals(mergedOverrideConfig2, child2.getMergedOverrideConfiguration());
+ assertEquals(mergedConfig2, child2.getConfiguration());
+ }
+
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
private class TestWindowContainer extends WindowContainer<TestWindowContainer> {
private final int mLayer;
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 1259e0f..3df1df9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -58,7 +58,8 @@
public void setUp() throws Exception {
final Context context = InstrumentationRegistry.getTargetContext();
sWm = TestWindowManagerPolicy.getWindowManagerService(context);
- mWindowToken = new WindowToken(sWm, new Binder(), 0, false);
+ mWindowToken = new WindowToken(sWm, new Binder(), 0, false,
+ sWm.getDefaultDisplayContentLocked());
}
@Test
@@ -162,7 +163,6 @@
private WindowState createWindow(WindowState parent, int type) {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
- return new WindowState(sWm, null, mIWindow, mWindowToken, parent, 0, 0, attrs, 0,
- sWm.getDefaultDisplayContentLocked(), 0);
+ return new WindowState(sWm, null, mIWindow, mWindowToken, parent, 0, 0, attrs, 0, 0);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
index 3279886..1a4dff9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTokenTests.java
@@ -157,15 +157,14 @@
private WindowState createWindow(WindowState parent, int type, WindowToken token) {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type);
- return new WindowState(mWm, null, mIWindow, token, parent, 0, 0, attrs, 0,
- mWm.getDefaultDisplayContentLocked(), 0);
+ return new WindowState(mWm, null, mIWindow, token, parent, 0, 0, attrs, 0, 0);
}
/* Used so we can gain access to some protected members of the {@link WindowToken} class */
private class TestWindowToken extends WindowToken {
TestWindowToken() {
- super(mWm, null, 0, false);
+ super(mWm, null, 0, false, mWm.getDefaultDisplayContentLocked());
}
int getWindowsCount() {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 220626a..a0c6e0e 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -84,6 +84,14 @@
private static final String USB_CONFIG_PROPERTY = "sys.usb.config";
/**
+ * The property which stores the current build type (user/userdebug/eng).
+ */
+ private static final String BUILD_TYPE_PROPERTY = "ro.build.type";
+
+ private static final String BUILD_TYPE_USERDEBUG = "userdebug";
+ private static final String BUILD_TYPE_ENG = "eng";
+
+ /**
* The non-persistent property which stores the current USB actual state.
*/
private static final String USB_STATE_PROPERTY = "sys.usb.state";
@@ -109,9 +117,8 @@
private static final int MSG_SYSTEM_READY = 3;
private static final int MSG_BOOT_COMPLETED = 4;
private static final int MSG_USER_SWITCHED = 5;
- private static final int MSG_SET_USB_DATA_UNLOCKED = 6;
- private static final int MSG_UPDATE_USER_RESTRICTIONS = 7;
- private static final int MSG_UPDATE_HOST_STATE = 8;
+ private static final int MSG_UPDATE_USER_RESTRICTIONS = 6;
+ private static final int MSG_UPDATE_HOST_STATE = 7;
private static final int AUDIO_MODE_SOURCE = 1;
@@ -291,7 +298,7 @@
if (functions != null) {
mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
- setCurrentFunctions(functions);
+ setCurrentFunctions(functions, false);
}
}
@@ -340,14 +347,17 @@
// Restore default functions.
mCurrentFunctions = SystemProperties.get(USB_CONFIG_PROPERTY,
UsbManager.USB_FUNCTION_NONE);
- if (UsbManager.USB_FUNCTION_NONE.equals(mCurrentFunctions)) {
- mCurrentFunctions = UsbManager.USB_FUNCTION_MTP;
- }
mCurrentFunctionsApplied = mCurrentFunctions.equals(
SystemProperties.get(USB_STATE_PROPERTY));
mAdbEnabled = UsbManager.containsFunction(getDefaultFunctions(),
UsbManager.USB_FUNCTION_ADB);
- setEnabledFunctions(null, false);
+
+ String buildType = SystemProperties.get(BUILD_TYPE_PROPERTY);
+ if (buildType.equals(BUILD_TYPE_USERDEBUG) || buildType.equals(BUILD_TYPE_ENG)) {
+ setAdbEnabled(true);
+ }
+
+ setEnabledFunctions(null, false, false);
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
@@ -379,6 +389,14 @@
sendMessage(m);
}
+ public void sendMessage(int what, Object arg, boolean arg1) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.obj = arg;
+ m.arg1 = (arg1 ? 1 : 0);
+ sendMessage(m);
+ }
+
public void updateState(String state) {
int connected, configured;
@@ -443,29 +461,28 @@
return waitForState(config);
}
- private void setUsbDataUnlocked(boolean enable) {
- if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked: " + enable);
- mUsbDataUnlocked = enable;
- updateUsbNotification();
- updateUsbStateBroadcastIfNeeded();
- setEnabledFunctions(mCurrentFunctions, true);
- }
-
private void setAdbEnabled(boolean enable) {
if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
if (enable != mAdbEnabled) {
mAdbEnabled = enable;
+ String oldFunctions = mCurrentFunctions;
- // Due to the persist.sys.usb.config property trigger, changing adb state requires
- // persisting default function
- String oldFunctions = getDefaultFunctions();
- String newFunctions = applyAdbFunction(oldFunctions);
- if (!oldFunctions.equals(newFunctions)) {
- SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunctions);
+ // Persist the adb setting
+ String newFunction = applyAdbFunction(SystemProperties.get(
+ USB_PERSISTENT_CONFIG_PROPERTY, UsbManager.USB_FUNCTION_NONE));
+ SystemProperties.set(USB_PERSISTENT_CONFIG_PROPERTY, newFunction);
+
+ // Changing the persistent config also changes the normal
+ // config. Wait for this to happen before changing again.
+ waitForState(newFunction);
+
+ // Remove mtp from the config if file transfer is not enabled
+ if (oldFunctions.equals(UsbManager.USB_FUNCTION_MTP) &&
+ !mUsbDataUnlocked && enable) {
+ oldFunctions = UsbManager.USB_FUNCTION_NONE;
}
- // After persisting them use the lock-down aware function set
- setEnabledFunctions(mCurrentFunctions, false);
+ setEnabledFunctions(oldFunctions, false, mUsbDataUnlocked);
updateAdbNotification();
}
@@ -477,10 +494,17 @@
/**
* Evaluates USB function policies and applies the change accordingly.
*/
- private void setEnabledFunctions(String functions, boolean forceRestart) {
+ private void setEnabledFunctions(String functions, boolean forceRestart,
+ boolean usbDataUnlocked) {
if (DEBUG) Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
+ "forceRestart=" + forceRestart);
+ if (usbDataUnlocked != mUsbDataUnlocked) {
+ mUsbDataUnlocked = usbDataUnlocked;
+ updateUsbNotification();
+ forceRestart = true;
+ }
+
// Try to set the enabled functions.
final String oldFunctions = mCurrentFunctions;
final boolean oldFunctionsApplied = mCurrentFunctionsApplied;
@@ -517,7 +541,8 @@
}
private boolean trySetEnabledFunctions(String functions, boolean forceRestart) {
- if (functions == null) {
+ if (functions == null || applyAdbFunction(functions)
+ .equals(UsbManager.USB_FUNCTION_NONE)) {
functions = getDefaultFunctions();
}
functions = applyAdbFunction(functions);
@@ -529,9 +554,6 @@
mCurrentFunctions = functions;
mCurrentFunctionsApplied = false;
- // Kick the USB stack to close existing connections.
- setUsbConfig(UsbManager.USB_FUNCTION_NONE);
-
// Set the new USB configuration.
if (!setUsbConfig(functions)) {
Slog.e(TAG, "Failed to switch USB config to " + functions);
@@ -583,7 +605,7 @@
// make sure accessory mode is off
// and restore default functions
Slog.d(TAG, "exited USB accessory mode");
- setEnabledFunctions(null, false);
+ setEnabledFunctions(null, false, false);
if (mCurrentAccessory != null) {
if (mBootCompleted) {
@@ -600,10 +622,6 @@
if (mBroadcastedIntent == null) {
for (String key : keySet) {
if (intent.getBooleanExtra(key, false)) {
- // MTP function is enabled by default.
- if (UsbManager.USB_FUNCTION_MTP.equals(key)) {
- continue;
- }
return true;
}
}
@@ -716,10 +734,7 @@
case MSG_UPDATE_STATE:
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
- if (!mConnected) {
- // When a disconnect occurs, relock access to sensitive user data
- mUsbDataUnlocked = false;
- }
+
updateUsbNotification();
updateAdbNotification();
if (UsbManager.containsFunction(mCurrentFunctions,
@@ -727,7 +742,7 @@
updateCurrentAccessory();
} else if (!mConnected) {
// restore defaults when USB is disconnected
- setEnabledFunctions(null, false);
+ setEnabledFunctions(null, false, false);
}
if (mBootCompleted) {
updateUsbStateBroadcastIfNeeded();
@@ -750,13 +765,10 @@
break;
case MSG_SET_CURRENT_FUNCTIONS:
String functions = (String)msg.obj;
- setEnabledFunctions(functions, false);
+ setEnabledFunctions(functions, false, msg.arg1 == 1);
break;
case MSG_UPDATE_USER_RESTRICTIONS:
- setEnabledFunctions(mCurrentFunctions, false);
- break;
- case MSG_SET_USB_DATA_UNLOCKED:
- setUsbDataUnlocked(msg.arg1 == 1);
+ setEnabledFunctions(mCurrentFunctions, false, mUsbDataUnlocked);
break;
case MSG_SYSTEM_READY:
updateUsbNotification();
@@ -784,8 +796,7 @@
Slog.v(TAG, "Current user switched to " + mCurrentUser
+ "; resetting USB host stack for MTP or PTP");
// avoid leaking sensitive data from previous user
- mUsbDataUnlocked = false;
- setEnabledFunctions(mCurrentFunctions, true);
+ setEnabledFunctions(mCurrentFunctions, true, false);
}
mCurrentUser = msg.arg1;
}
@@ -969,14 +980,10 @@
return UsbManager.containsFunction(SystemProperties.get(USB_CONFIG_PROPERTY), function);
}
- public void setCurrentFunctions(String functions) {
- if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ")");
- mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
- }
-
- public void setUsbDataUnlocked(boolean unlocked) {
- if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked(" + unlocked + ")");
- mHandler.sendMessage(MSG_SET_USB_DATA_UNLOCKED, unlocked);
+ public void setCurrentFunctions(String functions, boolean usbDataUnlocked) {
+ if (DEBUG) Slog.d(TAG, "setCurrentFunctions(" + functions + ", " +
+ usbDataUnlocked + ")");
+ mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, usbDataUnlocked);
}
private void readOemUsbOverrideConfig() {
diff --git a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
index cc0fb8d..e03a14f 100644
--- a/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbProfileGroupSettingsManager.java
@@ -34,6 +34,7 @@
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
+import android.os.AsyncTask;
import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManager;
@@ -42,6 +43,7 @@
import android.util.Slog;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.Immutable;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FastXmlSerializer;
@@ -60,7 +62,9 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import libcore.io.IoUtils;
@@ -87,14 +91,24 @@
private final UserManager mUserManager;
private final @NonNull UsbSettingsManager mSettingsManager;
- // Maps DeviceFilter to user preferred application package
+ /** Maps DeviceFilter to user preferred application package */
+ @GuardedBy("mLock")
private final HashMap<DeviceFilter, UserPackage> mDevicePreferenceMap = new HashMap<>();
- // Maps AccessoryFilter to user preferred application package
+
+ /** Maps AccessoryFilter to user preferred application package */
+ @GuardedBy("mLock")
private final HashMap<AccessoryFilter, UserPackage> mAccessoryPreferenceMap = new HashMap<>();
private final Object mLock = new Object();
/**
+ * If a async task to persist the mDevicePreferenceMap and mAccessoryPreferenceMap is currently
+ * scheduled.
+ */
+ @GuardedBy("mLock")
+ private boolean mIsWriteSettingsScheduled;
+
+ /**
* A package of a user.
*/
@Immutable
@@ -591,6 +605,42 @@
});
}
+ /**
+ * Remove all defaults for a user.
+ *
+ * @param userToRemove The user the defaults belong to.
+ */
+ void removeAllDefaultsForUser(@NonNull UserHandle userToRemove) {
+ synchronized (mLock) {
+ boolean needToPersist = false;
+ Iterator<Map.Entry<DeviceFilter, UserPackage>> devicePreferenceIt = mDevicePreferenceMap
+ .entrySet().iterator();
+ while (devicePreferenceIt.hasNext()) {
+ Map.Entry<DeviceFilter, UserPackage> entry = devicePreferenceIt.next();
+
+ if (entry.getValue().user.equals(userToRemove)) {
+ devicePreferenceIt.remove();
+ needToPersist = true;
+ }
+ }
+
+ Iterator<Map.Entry<AccessoryFilter, UserPackage>> accessoryPreferenceIt =
+ mAccessoryPreferenceMap.entrySet().iterator();
+ while (accessoryPreferenceIt.hasNext()) {
+ Map.Entry<AccessoryFilter, UserPackage> entry = accessoryPreferenceIt.next();
+
+ if (entry.getValue().user.equals(userToRemove)) {
+ accessoryPreferenceIt.remove();
+ needToPersist = true;
+ }
+ }
+
+ if (needToPersist) {
+ scheduleWriteSettingsLocked();
+ }
+ }
+ }
+
private void readPreference(XmlPullParser parser)
throws XmlPullParserException, IOException {
String packageName = null;
@@ -657,7 +707,7 @@
IoUtils.closeQuietly(fis);
}
- writeSettingsLocked();
+ scheduleWriteSettingsLocked();
// Success or failure, we delete single-user file
sSingleUserSettingsFile.delete();
@@ -695,48 +745,68 @@
}
}
- private void writeSettingsLocked() {
- if (DEBUG) Slog.v(TAG, "writeSettingsLocked()");
-
- FileOutputStream fos = null;
- try {
- fos = mSettingsFile.startWrite();
-
- FastXmlSerializer serializer = new FastXmlSerializer();
- serializer.setOutput(fos, StandardCharsets.UTF_8.name());
- serializer.startDocument(null, true);
- serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
- serializer.startTag(null, "settings");
-
- for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
- serializer.startTag(null, "preference");
- serializer.attribute(null, "package", mDevicePreferenceMap.get(filter).packageName);
- serializer.attribute(null, "user",
- String.valueOf(getSerial(mDevicePreferenceMap.get(filter).user)));
- filter.write(serializer);
- serializer.endTag(null, "preference");
- }
-
- for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
- serializer.startTag(null, "preference");
- serializer.attribute(null, "package",
- mAccessoryPreferenceMap.get(filter).packageName);
- serializer.attribute(null, "user",
- String.valueOf(getSerial(mAccessoryPreferenceMap.get(filter).user)));
- filter.write(serializer);
- serializer.endTag(null, "preference");
- }
-
- serializer.endTag(null, "settings");
- serializer.endDocument();
-
- mSettingsFile.finishWrite(fos);
- } catch (IOException e) {
- Slog.e(TAG, "Failed to write settings", e);
- if (fos != null) {
- mSettingsFile.failWrite(fos);
- }
+ /**
+ * Schedule a async task to persist {@link #mDevicePreferenceMap} and
+ * {@link #mAccessoryPreferenceMap}. If a task is already scheduled but not completed, do
+ * nothing as the currently scheduled one will do the work.
+ * <p>Called with {@link #mLock} held.</p>
+ * <p>In the uncommon case that the system crashes in between the scheduling and the write the
+ * update is lost.</p>
+ */
+ private void scheduleWriteSettingsLocked() {
+ if (mIsWriteSettingsScheduled) {
+ return;
+ } else {
+ mIsWriteSettingsScheduled = true;
}
+
+ AsyncTask.execute(() -> {
+ synchronized (mLock) {
+ FileOutputStream fos = null;
+ try {
+ fos = mSettingsFile.startWrite();
+
+ FastXmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(fos, StandardCharsets.UTF_8.name());
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output",
+ true);
+ serializer.startTag(null, "settings");
+
+ for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
+ serializer.startTag(null, "preference");
+ serializer.attribute(null, "package",
+ mDevicePreferenceMap.get(filter).packageName);
+ serializer.attribute(null, "user",
+ String.valueOf(getSerial(mDevicePreferenceMap.get(filter).user)));
+ filter.write(serializer);
+ serializer.endTag(null, "preference");
+ }
+
+ for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
+ serializer.startTag(null, "preference");
+ serializer.attribute(null, "package",
+ mAccessoryPreferenceMap.get(filter).packageName);
+ serializer.attribute(null, "user", String.valueOf(
+ getSerial(mAccessoryPreferenceMap.get(filter).user)));
+ filter.write(serializer);
+ serializer.endTag(null, "preference");
+ }
+
+ serializer.endTag(null, "settings");
+ serializer.endDocument();
+
+ mSettingsFile.finishWrite(fos);
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to write settings", e);
+ if (fos != null) {
+ mSettingsFile.failWrite(fos);
+ }
+ }
+
+ mIsWriteSettingsScheduled = false;
+ }
+ });
}
// Checks to see if a package matches a device or accessory.
@@ -1141,7 +1211,7 @@
}
if (changed) {
- writeSettingsLocked();
+ scheduleWriteSettingsLocked();
}
}
}
@@ -1178,7 +1248,7 @@
}
}
if (changed) {
- writeSettingsLocked();
+ scheduleWriteSettingsLocked();
}
}
}
@@ -1204,7 +1274,7 @@
}
}
if (changed) {
- writeSettingsLocked();
+ scheduleWriteSettingsLocked();
}
}
}
@@ -1237,7 +1307,7 @@
synchronized (mLock) {
if (clearPackageDefaultsLocked(userPackage)) {
- writeSettingsLocked();
+ scheduleWriteSettingsLocked();
}
}
}
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 02c7214..a87ac9e 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -16,6 +16,7 @@
package com.android.server.usb;
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.app.admin.DevicePolicyManager;
@@ -83,7 +84,7 @@
@Override
public void onStopUser(int userHandle) {
- mUsbService.onStopUser(userHandle);
+ mUsbService.onStopUser(UserHandle.of(userHandle));
}
}
@@ -177,10 +178,10 @@
/**
* Execute operations when a user is stopped.
*
- * @param stoppedUserId The id of the used that is stopped
+ * @param stoppedUser The user that is stopped
*/
- private void onStopUser(@UserIdInt int stoppedUserId) {
- mSettingsManager.remove(stoppedUserId);
+ private void onStopUser(@NonNull UserHandle stoppedUser) {
+ mSettingsManager.remove(stoppedUser);
}
public void systemReady() {
@@ -371,7 +372,7 @@
}
@Override
- public void setCurrentFunction(String function) {
+ public void setCurrentFunction(String function, boolean usbDataUnlocked) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
if (!isSupportedCurrentFunction(function)) {
@@ -381,7 +382,7 @@
}
if (mDeviceManager != null) {
- mDeviceManager.setCurrentFunctions(function);
+ mDeviceManager.setCurrentFunctions(function, usbDataUnlocked);
} else {
throw new IllegalStateException("USB device mode not supported");
}
@@ -404,12 +405,6 @@
}
@Override
- public void setUsbDataUnlocked(boolean unlocked) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
- mDeviceManager.setUsbDataUnlocked(unlocked);
- }
-
- @Override
public void allowUsbDebugging(boolean alwaysAllow, String publicKey) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
mDeviceManager.allowUsbDebugging(alwaysAllow, publicKey);
diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
index b251d26..24d5f09 100644
--- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java
@@ -108,11 +108,26 @@
/**
* Remove the settings for a user.
*
- * @param userIdToRemove The user o remove
+ * @param userToRemove The user to remove
*/
- void remove(@UserIdInt int userIdToRemove) {
+ void remove(@NonNull UserHandle userToRemove) {
synchronized (mSettingsByUser) {
- mSettingsByUser.remove(userIdToRemove);
+ mSettingsByUser.remove(userToRemove.getIdentifier());
+ }
+
+ synchronized (mSettingsByProfileGroup) {
+ if (mSettingsByProfileGroup.indexOfKey(userToRemove.getIdentifier()) >= 0) {
+ // The user to remove is the parent user of the group. The parent is the last user
+ // that gets removed. All state will be removed with the user
+ mSettingsByProfileGroup.remove(userToRemove.getIdentifier());
+ } else {
+ // We cannot find the parent user of the user that is removed, hence try to remove
+ // it from all profile groups.
+ int numProfileGroups = mSettingsByProfileGroup.size();
+ for (int i = 0; i < numProfileGroups; i++) {
+ mSettingsByProfileGroup.valueAt(i).removeAllDefaultsForUser(userToRemove);
+ }
+ }
}
}
diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java
index a965342..ecda3cd 100644
--- a/telecomm/java/android/telecom/Log.java
+++ b/telecomm/java/android/telecom/Log.java
@@ -18,9 +18,15 @@
import android.net.Uri;
import android.os.AsyncTask;
+import android.telecom.Logging.EventManager;
+import android.telecom.Logging.Session;
+import android.telecom.Logging.SessionManager;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.IllegalFormatException;
@@ -31,24 +37,270 @@
*
* @hide
*/
-final public class Log {
+public class Log {
- // Generic tag for all Telecom Framework logging
- private static final String TAG = "TelecomFramework";
+ private static final long EXTENDED_LOGGING_DURATION_MILLIS = 60000 * 30; // 30 minutes
- public static final boolean FORCE_LOGGING = false; /* STOP SHIP if true */
+ private static final int EVENTS_TO_CACHE = 10;
+ private static final int EVENTS_TO_CACHE_DEBUG = 20;
+
+ // Generic tag for all Telecom logging
+ @VisibleForTesting
+ public static String TAG = "TelecomFramework";
+
+ private static final boolean FORCE_LOGGING = false; /* STOP SHIP if true */
public static final boolean DEBUG = isLoggable(android.util.Log.DEBUG);
public static final boolean INFO = isLoggable(android.util.Log.INFO);
public static final boolean VERBOSE = isLoggable(android.util.Log.VERBOSE);
public static final boolean WARN = isLoggable(android.util.Log.WARN);
public static final boolean ERROR = isLoggable(android.util.Log.ERROR);
+ // Used to synchronize singleton logging lazy initialization
+ private static final Object sSingletonSync = new Object();
+ private static EventManager sEventManager;
+ private static SessionManager sSessionManager;
+
+ /**
+ * Tracks whether user-activated extended logging is enabled.
+ */
+ private static boolean sIsUserExtendedLoggingEnabled = false;
+
+ /**
+ * The time when user-activated extended logging should be ended. Used to determine when
+ * extended logging should automatically be disabled.
+ */
+ private static long sUserExtendedLoggingStopTime = 0;
+
+ private Log() {
+ }
+
+ public static void d(String prefix, String format, Object... args) {
+ if (sIsUserExtendedLoggingEnabled) {
+ maybeDisableLogging();
+ android.util.Slog.i(TAG, buildMessage(prefix, format, args));
+ } else if (DEBUG) {
+ android.util.Slog.d(TAG, buildMessage(prefix, format, args));
+ }
+ }
+
+ public static void d(Object objectPrefix, String format, Object... args) {
+ if (sIsUserExtendedLoggingEnabled) {
+ maybeDisableLogging();
+ android.util.Slog.i(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
+ } else if (DEBUG) {
+ android.util.Slog.d(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
+ }
+ }
+
+ public static void i(String prefix, String format, Object... args) {
+ if (INFO) {
+ android.util.Slog.i(TAG, buildMessage(prefix, format, args));
+ }
+ }
+
+ public static void i(Object objectPrefix, String format, Object... args) {
+ if (INFO) {
+ android.util.Slog.i(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
+ }
+ }
+
+ public static void v(String prefix, String format, Object... args) {
+ if (sIsUserExtendedLoggingEnabled) {
+ maybeDisableLogging();
+ android.util.Slog.i(TAG, buildMessage(prefix, format, args));
+ } else if (VERBOSE) {
+ android.util.Slog.v(TAG, buildMessage(prefix, format, args));
+ }
+ }
+
+ public static void v(Object objectPrefix, String format, Object... args) {
+ if (sIsUserExtendedLoggingEnabled) {
+ maybeDisableLogging();
+ android.util.Slog.i(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
+ } else if (VERBOSE) {
+ android.util.Slog.v(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
+ }
+ }
+
+ public static void w(String prefix, String format, Object... args) {
+ if (WARN) {
+ android.util.Slog.w(TAG, buildMessage(prefix, format, args));
+ }
+ }
+
+ public static void w(Object objectPrefix, String format, Object... args) {
+ if (WARN) {
+ android.util.Slog.w(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
+ }
+ }
+
+ public static void e(String prefix, Throwable tr, String format, Object... args) {
+ if (ERROR) {
+ android.util.Slog.e(TAG, buildMessage(prefix, format, args), tr);
+ }
+ }
+
+ public static void e(Object objectPrefix, Throwable tr, String format, Object... args) {
+ if (ERROR) {
+ android.util.Slog.e(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args),
+ tr);
+ }
+ }
+
+ public static void wtf(String prefix, Throwable tr, String format, Object... args) {
+ android.util.Slog.wtf(TAG, buildMessage(prefix, format, args), tr);
+ }
+
+ public static void wtf(Object objectPrefix, Throwable tr, String format, Object... args) {
+ android.util.Slog.wtf(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args),
+ tr);
+ }
+
+ public static void wtf(String prefix, String format, Object... args) {
+ String msg = buildMessage(prefix, format, args);
+ android.util.Slog.wtf(TAG, msg, new IllegalStateException(msg));
+ }
+
+ public static void wtf(Object objectPrefix, String format, Object... args) {
+ String msg = buildMessage(getPrefixFromObject(objectPrefix), format, args);
+ android.util.Slog.wtf(TAG, msg, new IllegalStateException(msg));
+ }
+
+ /**
+ * The ease of use methods below only act mostly as proxies to the Session and Event Loggers.
+ * They also control the lazy loaders of the singleton instances, which will never be loaded if
+ * the proxy methods aren't used.
+ *
+ * Please see each method's documentation inside of their respective implementations in the
+ * loggers.
+ */
+
+ public static void startSession(String shortMethodName) {
+ getSessionManager().startSession(shortMethodName, null);
+ }
+
+ public static void startSession(String shortMethodName, String callerIdentification) {
+ getSessionManager().startSession(shortMethodName, callerIdentification);
+ }
+
+ public static Session createSubsession() {
+ return getSessionManager().createSubsession();
+ }
+
+ public static void cancelSubsession(Session subsession) {
+ getSessionManager().cancelSubsession(subsession);
+ }
+
+ public static void continueSession(Session subsession, String shortMethodName) {
+ getSessionManager().continueSession(subsession, shortMethodName);
+ }
+
+ public static void endSession() {
+ getSessionManager().endSession();
+ }
+
+ public static String getSessionId() {
+ // If the Session logger has not been initialized, then there have been no sessions logged.
+ // Don't load it now!
+ synchronized (sSingletonSync) {
+ if (sSessionManager != null) {
+ return getSessionManager().getSessionId();
+ } else {
+ return "";
+ }
+ }
+ }
+
+ public static void addEvent(EventManager.Loggable recordEntry, String event) {
+ getEventManager().event(recordEntry, event, null);
+ }
+
+ public static void addEvent(EventManager.Loggable recordEntry, String event, Object data) {
+ getEventManager().event(recordEntry, event, data);
+ }
+
+ public static void addEvent(EventManager.Loggable recordEntry, String event, String format,
+ Object... args) {
+ getEventManager().event(recordEntry, event, format, args);
+ }
+
+ public static void registerEventListener(EventManager.EventListener e) {
+ getEventManager().registerEventListener(e);
+ }
+
+ public static void addRequestResponsePair(EventManager.TimedEventPair p) {
+ getEventManager().addRequestResponsePair(p);
+ }
+
+ public static void dumpEvents(IndentingPrintWriter pw) {
+ // If the Events logger has not been initialized, then there have been no events logged.
+ // Don't load it now!
+ synchronized (sSingletonSync) {
+ if (sEventManager != null) {
+ getEventManager().dumpEvents(pw);
+ } else {
+ pw.println("No Historical Events Logged.");
+ }
+ }
+ }
+
+ /**
+ * Enable or disable extended telecom logging.
+ *
+ * @param isExtendedLoggingEnabled {@code true} if extended logging should be enabled,
+ * {@code false} if it should be disabled.
+ */
+ public static void setIsExtendedLoggingEnabled(boolean isExtendedLoggingEnabled) {
+ // If the state hasn't changed, bail early.
+ if (sIsUserExtendedLoggingEnabled == isExtendedLoggingEnabled) {
+ return;
+ }
+
+ if (sEventManager != null) {
+ sEventManager.changeEventCacheSize(isExtendedLoggingEnabled ?
+ EVENTS_TO_CACHE_DEBUG : EVENTS_TO_CACHE);
+ }
+
+ sIsUserExtendedLoggingEnabled = isExtendedLoggingEnabled;
+ if (sIsUserExtendedLoggingEnabled) {
+ sUserExtendedLoggingStopTime = System.currentTimeMillis()
+ + EXTENDED_LOGGING_DURATION_MILLIS;
+ } else {
+ sUserExtendedLoggingStopTime = 0;
+ }
+ }
+
+ private static EventManager getEventManager() {
+ // Checking for null again outside of synchronization because we only need to synchronize
+ // during the lazy loading of the events logger. We don't need to synchronize elsewhere.
+ if (sEventManager == null) {
+ synchronized (sSingletonSync) {
+ if (sEventManager == null) {
+ sEventManager = new EventManager(Log::getSessionId);
+ return sEventManager;
+ }
+ }
+ }
+ return sEventManager;
+ }
+
+ private static SessionManager getSessionManager() {
+ // Checking for null again outside of synchronization because we only need to synchronize
+ // during the lazy loading of the session logger. We don't need to synchronize elsewhere.
+ if (sSessionManager == null) {
+ synchronized (sSingletonSync) {
+ if (sSessionManager == null) {
+ sSessionManager = new SessionManager();
+ return sSessionManager;
+ }
+ }
+ }
+ return sSessionManager;
+ }
+
private static MessageDigest sMessageDigest;
- private static final Object sMessageDigestLock = new Object();
- private Log() {}
-
- public static void initMd5Sum() {
+ static void initMd5Sum() {
new AsyncTask<Void, Void, Void>() {
@Override
public Void doInBackground(Void... args) {
@@ -58,96 +310,69 @@
} catch (NoSuchAlgorithmException e) {
md = null;
}
- synchronized (sMessageDigestLock) {
- sMessageDigest = md;
- }
+ sMessageDigest = md;
return null;
}
}.execute();
}
+ public static void setTag(String tag) {
+ TAG = tag;
+ }
+
+ /**
+ * If user enabled extended logging is enabled and the time limit has passed, disables the
+ * extended logging.
+ */
+ private static void maybeDisableLogging() {
+ if (!sIsUserExtendedLoggingEnabled) {
+ return;
+ }
+
+ if (sUserExtendedLoggingStopTime < System.currentTimeMillis()) {
+ sUserExtendedLoggingStopTime = 0;
+ sIsUserExtendedLoggingEnabled = false;
+ }
+ }
+
public static boolean isLoggable(int level) {
return FORCE_LOGGING || android.util.Log.isLoggable(TAG, level);
}
- public static void d(String prefix, String format, Object... args) {
- if (DEBUG) {
- android.util.Log.d(TAG, buildMessage(prefix, format, args));
+ public static String piiHandle(Object pii) {
+ if (pii == null || VERBOSE) {
+ return String.valueOf(pii);
}
- }
- public static void d(Object objectPrefix, String format, Object... args) {
- if (DEBUG) {
- android.util.Log.d(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
+ StringBuilder sb = new StringBuilder();
+ if (pii instanceof Uri) {
+ Uri uri = (Uri) pii;
+ String scheme = uri.getScheme();
+
+ if (!TextUtils.isEmpty(scheme)) {
+ sb.append(scheme).append(":");
+ }
+
+ String textToObfuscate = uri.getSchemeSpecificPart();
+ if (PhoneAccount.SCHEME_TEL.equals(scheme)) {
+ for (int i = 0; i < textToObfuscate.length(); i++) {
+ char c = textToObfuscate.charAt(i);
+ sb.append(PhoneNumberUtils.isDialable(c) ? "*" : c);
+ }
+ } else if (PhoneAccount.SCHEME_SIP.equals(scheme)) {
+ for (int i = 0; i < textToObfuscate.length(); i++) {
+ char c = textToObfuscate.charAt(i);
+ if (c != '@' && c != '.') {
+ c = '*';
+ }
+ sb.append(c);
+ }
+ } else {
+ sb.append(pii(pii));
+ }
}
- }
- public static void i(String prefix, String format, Object... args) {
- if (INFO) {
- android.util.Log.i(TAG, buildMessage(prefix, format, args));
- }
- }
-
- public static void i(Object objectPrefix, String format, Object... args) {
- if (INFO) {
- android.util.Log.i(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
- }
- }
-
- public static void v(String prefix, String format, Object... args) {
- if (VERBOSE) {
- android.util.Log.v(TAG, buildMessage(prefix, format, args));
- }
- }
-
- public static void v(Object objectPrefix, String format, Object... args) {
- if (VERBOSE) {
- android.util.Log.v(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
- }
- }
-
- public static void w(String prefix, String format, Object... args) {
- if (WARN) {
- android.util.Log.w(TAG, buildMessage(prefix, format, args));
- }
- }
-
- public static void w(Object objectPrefix, String format, Object... args) {
- if (WARN) {
- android.util.Log.w(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args));
- }
- }
-
- public static void e(String prefix, Throwable tr, String format, Object... args) {
- if (ERROR) {
- android.util.Log.e(TAG, buildMessage(prefix, format, args), tr);
- }
- }
-
- public static void e(Object objectPrefix, Throwable tr, String format, Object... args) {
- if (ERROR) {
- android.util.Log.e(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args),
- tr);
- }
- }
-
- public static void wtf(String prefix, Throwable tr, String format, Object... args) {
- android.util.Log.wtf(TAG, buildMessage(prefix, format, args), tr);
- }
-
- public static void wtf(Object objectPrefix, Throwable tr, String format, Object... args) {
- android.util.Log.wtf(TAG, buildMessage(getPrefixFromObject(objectPrefix), format, args),
- tr);
- }
-
- public static void wtf(String prefix, String format, Object... args) {
- String msg = buildMessage(prefix, format, args);
- android.util.Log.wtf(TAG, msg, new IllegalStateException(msg));
- }
-
- public static void wtf(Object objectPrefix, String format, Object... args) {
- String msg = buildMessage(getPrefixFromObject(objectPrefix), format, args);
- android.util.Log.wtf(TAG, msg, new IllegalStateException(msg));
+ return sb.toString();
}
/**
@@ -158,47 +383,18 @@
public static String pii(Object pii) {
if (pii == null || VERBOSE) {
return String.valueOf(pii);
- } if (pii instanceof Uri) {
- return piiUri((Uri) pii);
}
return "[" + secureHash(String.valueOf(pii).getBytes()) + "]";
}
- private static String piiUri(Uri handle) {
- StringBuilder sb = new StringBuilder();
- String scheme = handle.getScheme();
- if (!TextUtils.isEmpty(scheme)) {
- sb.append(scheme).append(":");
- }
- String value = handle.getSchemeSpecificPart();
- if (!TextUtils.isEmpty(value)) {
- for (int i = 0; i < value.length(); i++) {
- char c = value.charAt(i);
- if (PhoneNumberUtils.isStartsPostDial(c)) {
- sb.append(c);
- } else if (PhoneNumberUtils.isDialable(c)) {
- sb.append("*");
- } else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
- sb.append("*");
- } else {
- sb.append(c);
- }
- }
- }
- return sb.toString();
-
- }
-
private static String secureHash(byte[] input) {
- synchronized (sMessageDigestLock) {
- if (sMessageDigest != null) {
- sMessageDigest.reset();
- sMessageDigest.update(input);
- byte[] result = sMessageDigest.digest();
- return encodeHex(result);
- } else {
- return "Uninitialized SHA1";
- }
+ if (sMessageDigest != null) {
+ sMessageDigest.reset();
+ sMessageDigest.update(input);
+ byte[] result = sMessageDigest.digest();
+ return encodeHex(result);
+ } else {
+ return "Uninitialized SHA1";
}
}
@@ -221,15 +417,19 @@
}
private static String buildMessage(String prefix, String format, Object... args) {
+ // Incorporate thread ID and calling method into prefix
+ String sessionName = getSessionId();
+ String sessionPostfix = TextUtils.isEmpty(sessionName) ? "" : ": " + sessionName;
+
String msg;
try {
msg = (args == null || args.length == 0) ? format
: String.format(Locale.US, format, args);
} catch (IllegalFormatException ife) {
- wtf("Log", ife, "IllegalFormatException: formatString='%s' numArgs=%d", format,
+ e("Log", ife, "IllegalFormatException: formatString='%s' numArgs=%d", format,
args.length);
msg = format + " (An error occurred while formatting the message.)";
}
- return String.format(Locale.US, "%s: %s", prefix, msg);
+ return String.format(Locale.US, "%s: %s%s", prefix, msg, sessionPostfix);
}
}
diff --git a/telecomm/java/android/telecom/Logging/EventManager.java b/telecomm/java/android/telecom/Logging/EventManager.java
new file mode 100644
index 0000000..8e7a393
--- /dev/null
+++ b/telecomm/java/android/telecom/Logging/EventManager.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom.Logging;
+
+import android.annotation.NonNull;
+import android.telecom.Log;
+import android.text.TextUtils;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.IllegalFormatException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * A utility class that provides the ability to define Events that a subsystem deems important, and
+ * then relate those events to other events so that information can be extracted. For example, a
+ * START and FINISH event can be defined and when a START and then FINISH occurs in a sequence, the
+ * time it took to complete that sequence can be saved to be retrieved later.
+ * @hide
+ */
+
+public class EventManager {
+
+ public static final String TAG = "Logging.Events";
+ public static final int DEFAULT_EVENTS_TO_CACHE = 10; // Arbitrarily chosen.
+
+ public interface Loggable {
+ /**
+ * @return a unique String ID that will allow the Event to be recognized later in the logs.
+ */
+ String getId();
+
+ /**
+ * @return Formatted information about the state that will be printed out later in the logs.
+ */
+ String getDescription();
+ }
+
+ private final Map<Loggable, EventRecord> mCallEventRecordMap = new HashMap<>();
+ private LinkedBlockingQueue<EventRecord> mEventRecords =
+ new LinkedBlockingQueue<>(DEFAULT_EVENTS_TO_CACHE);
+
+ private List<EventListener> mEventListeners = new ArrayList<>();
+
+ public interface EventListener {
+ /**
+ * Notifies the implementation of this method that a new event record has been added.
+ * @param eventRecord Reference to the recently added EventRecord
+ */
+ void eventRecordAdded(EventRecord eventRecord);
+ }
+
+ private SessionManager.ISessionIdQueryHandler mSessionIdHandler;
+ /**
+ * Maps from request events to a list of possible response events. Used to track
+ * end-to-end timing for critical user-facing operations in Telecom.
+ */
+ public final Map<String, List<TimedEventPair>> requestResponsePairs = new HashMap<>();
+
+ private static final Object mSync = new Object();
+
+ /**
+ * Stores the various events.
+ * Also stores all request-response pairs amongst the events.
+ */
+ public static class TimedEventPair {
+ private static final long DEFAULT_TIMEOUT = 3000L;
+
+ String mRequest;
+ String mResponse;
+ String mName;
+ long mTimeoutMillis = DEFAULT_TIMEOUT;
+
+ public TimedEventPair(String request, String response, String name) {
+ this.mRequest = request;
+ this.mResponse = response;
+ this.mName = name;
+ }
+
+ public TimedEventPair(String request, String response, String name, long timeoutMillis) {
+ this.mRequest = request;
+ this.mResponse = response;
+ this.mName = name;
+ this.mTimeoutMillis = timeoutMillis;
+ }
+ }
+
+ public void addRequestResponsePair(TimedEventPair p) {
+ if (requestResponsePairs.containsKey(p.mRequest)) {
+ requestResponsePairs.get(p.mRequest).add(p);
+ } else {
+ ArrayList<TimedEventPair> responses = new ArrayList<>();
+ responses.add(p);
+ requestResponsePairs.put(p.mRequest, responses);
+ }
+ }
+
+ public static class Event {
+ public String eventId;
+ public String sessionId;
+ public long time;
+ public Object data;
+
+ public Event(String eventId, String sessionId, long time, Object data) {
+ this.eventId = eventId;
+ this.sessionId = sessionId;
+ this.time = time;
+ this.data = data;
+ }
+ }
+
+ public class EventRecord {
+ public class EventTiming extends TimedEvent<String> {
+ public String name;
+ public long time;
+
+ public EventTiming(String name, long time) {
+ this.name = name;
+ this.time = time;
+ }
+
+ public String getKey() {
+ return name;
+ }
+
+ public long getTime() {
+ return time;
+ }
+ }
+
+ private class PendingResponse {
+ String requestEventId;
+ long requestEventTimeMillis;
+ long timeoutMillis;
+ String name;
+
+ public PendingResponse(String requestEventId, long requestEventTimeMillis,
+ long timeoutMillis, String name) {
+ this.requestEventId = requestEventId;
+ this.requestEventTimeMillis = requestEventTimeMillis;
+ this.timeoutMillis = timeoutMillis;
+ this.name = name;
+ }
+ }
+
+ private final DateFormat sDateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
+ private final List<Event> mEvents = new LinkedList<>();
+ private final Loggable mRecordEntry;
+
+ public EventRecord(Loggable recordEntry) {
+ mRecordEntry = recordEntry;
+ }
+
+ public Loggable getRecordEntry() {
+ return mRecordEntry;
+ }
+
+ public void addEvent(String event, String sessionId, Object data) {
+ mEvents.add(new Event(event, sessionId, System.currentTimeMillis(), data));
+ Log.i("Event", "RecordEntry %s: %s, %s", mRecordEntry.getId(), event, data);
+ }
+
+ public List<Event> getEvents() {
+ return mEvents;
+ }
+
+ public List<EventTiming> extractEventTimings() {
+ if (mEvents == null) {
+ return Collections.emptyList();
+ }
+
+ LinkedList<EventTiming> result = new LinkedList<>();
+ Map<String, PendingResponse> pendingResponses = new HashMap<>();
+ for (Event event : mEvents) {
+ if (requestResponsePairs.containsKey(event.eventId)) {
+ // This event expects a response, so add that expected response to the maps
+ // of pending events.
+ for (EventManager.TimedEventPair p : requestResponsePairs.get(event.eventId)) {
+ pendingResponses.put(p.mResponse, new PendingResponse(event.eventId,
+ event.time, p.mTimeoutMillis, p.mName));
+ }
+ }
+
+ PendingResponse pendingResponse = pendingResponses.remove(event.eventId);
+ if (pendingResponse != null) {
+ long elapsedTime = event.time - pendingResponse.requestEventTimeMillis;
+ if (elapsedTime < pendingResponse.timeoutMillis) {
+ result.add(new EventTiming(pendingResponse.name, elapsedTime));
+ }
+ }
+ }
+
+ return result;
+ }
+
+ public void dump(IndentingPrintWriter pw) {
+ pw.print(mRecordEntry.getDescription());
+
+ pw.increaseIndent();
+ for (Event event : mEvents) {
+ pw.print(sDateFormat.format(new Date(event.time)));
+ pw.print(" - ");
+ pw.print(event.eventId);
+ if (event.data != null) {
+ pw.print(" (");
+ Object data = event.data;
+
+ if (data instanceof Loggable) {
+ // If the data is another Loggable, then change the data to the
+ // Entry's Event ID instead.
+ EventRecord record = mCallEventRecordMap.get(data);
+ if (record != null) {
+ data = "RecordEntry " + record.mRecordEntry.getId();
+ }
+ }
+
+ pw.print(data);
+ pw.print(")");
+ }
+ if (!TextUtils.isEmpty(event.sessionId)) {
+ pw.print(":");
+ pw.print(event.sessionId);
+ }
+ pw.println();
+ }
+
+ pw.println("Timings (average for this call, milliseconds):");
+ pw.increaseIndent();
+ Map<String, Double> avgEventTimings = EventTiming.averageTimings(extractEventTimings());
+ List<String> eventNames = new ArrayList<>(avgEventTimings.keySet());
+ Collections.sort(eventNames);
+ for (String eventName : eventNames) {
+ pw.printf("%s: %.2f\n", eventName, avgEventTimings.get(eventName));
+ }
+ pw.decreaseIndent();
+ pw.decreaseIndent();
+ }
+ }
+
+ public EventManager(@NonNull SessionManager.ISessionIdQueryHandler l) {
+ mSessionIdHandler = l;
+ }
+
+ public void event(Loggable recordEntry, String event, Object data) {
+ String currentSessionID = mSessionIdHandler.getSessionId();
+
+ if (recordEntry == null) {
+ Log.i(TAG, "Non-call EVENT: %s, %s", event, data);
+ return;
+ }
+ synchronized (mEventRecords) {
+ if (!mCallEventRecordMap.containsKey(recordEntry)) {
+ EventRecord newRecord = new EventRecord(recordEntry);
+ addEventRecord(newRecord);
+ }
+
+ EventRecord record = mCallEventRecordMap.get(recordEntry);
+ record.addEvent(event, currentSessionID, data);
+ }
+ }
+
+ public void event(Loggable recordEntry, String event, String format, Object... args) {
+ String msg;
+ try {
+ msg = (args == null || args.length == 0) ? format
+ : String.format(Locale.US, format, args);
+ } catch (IllegalFormatException ife) {
+ Log.e("Log", ife, "IllegalFormatException: formatString='%s' numArgs=%d", format,
+ args.length);
+ msg = format + " (An error occurred while formatting the message.)";
+ }
+
+ event(recordEntry, event, msg);
+ }
+
+ public void dumpEvents(IndentingPrintWriter pw) {
+ pw.println("Historical Events:");
+ pw.increaseIndent();
+ for (EventRecord eventRecord : mEventRecords) {
+ eventRecord.dump(pw);
+ }
+ pw.decreaseIndent();
+ }
+
+ public void changeEventCacheSize(int newSize) {
+
+ // Resize the event queue.
+ LinkedBlockingQueue<EventRecord> oldEventLog = mEventRecords;
+ mEventRecords = new LinkedBlockingQueue<>(newSize);
+ mCallEventRecordMap.clear();
+
+ oldEventLog.forEach((newRecord -> {
+ Loggable recordEntry = newRecord.getRecordEntry();
+ // Copy the existing queue into the new one.
+ // First remove the oldest entry if no new ones exist.
+ if (mEventRecords.remainingCapacity() == 0) {
+ EventRecord record = mEventRecords.poll();
+ if (record != null) {
+ mCallEventRecordMap.remove(record.getRecordEntry());
+ }
+ }
+
+ // Now add a new entry
+ mEventRecords.add(newRecord);
+ mCallEventRecordMap.put(recordEntry, newRecord);
+
+ // Don't worry about notifying mEventListeners, since we are just resizing the records.
+ }));
+ }
+
+ public void registerEventListener(EventListener e) {
+ if (e != null) {
+ synchronized (mSync) {
+ mEventListeners.add(e);
+ }
+ }
+ }
+
+ private void addEventRecord(EventRecord newRecord) {
+ Loggable recordEntry = newRecord.getRecordEntry();
+
+ // First remove the oldest entry if no new ones exist.
+ if (mEventRecords.remainingCapacity() == 0) {
+ EventRecord record = mEventRecords.poll();
+ if (record != null) {
+ mCallEventRecordMap.remove(record.getRecordEntry());
+ }
+ }
+
+ // Now add a new entry
+ mEventRecords.add(newRecord);
+ mCallEventRecordMap.put(recordEntry, newRecord);
+
+ // TODO: Add Implementation of this in Telecom for Analytics
+ synchronized (mSync) {
+ for (EventListener l : mEventListeners) {
+ l.eventRecordAdded(newRecord);
+ }
+ }
+ }
+}
diff --git a/telecomm/java/android/telecom/Logging/Session.java b/telecomm/java/android/telecom/Logging/Session.java
new file mode 100644
index 0000000..14f4a0f
--- /dev/null
+++ b/telecomm/java/android/telecom/Logging/Session.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom.Logging;
+
+import android.annotation.NonNull;
+
+import java.util.ArrayList;
+
+/**
+ * The session that stores information about a thread's point of entry into the Telecom code that
+ * persists until the thread exits Telecom.
+ * @hide
+ */
+public class Session {
+
+ public static final String START_SESSION = "START_SESSION";
+ public static final String CREATE_SUBSESSION = "CREATE_SUBSESSION";
+ public static final String CONTINUE_SUBSESSION = "CONTINUE_SUBSESSION";
+ public static final String END_SUBSESSION = "END_SUBSESSION";
+ public static final String END_SESSION = "END_SESSION";
+
+ public static final int UNDEFINED = -1;
+
+ private String mSessionId;
+ private String mShortMethodName;
+ private long mExecutionStartTimeMs;
+ private long mExecutionEndTimeMs = UNDEFINED;
+ private Session mParentSession;
+ private ArrayList<Session> mChildSessions;
+ private boolean mIsCompleted = false;
+ private int mChildCounter = 0;
+ // True if this is a subsession that has been started from the same thread as the parent
+ // session. This can happen if Log.startSession(...) is called multiple times on the same
+ // thread in the case of one Telecom entry point method calling another entry point method.
+ // In this case, we can just make this subsession "invisible," but still keep track of it so
+ // that the Log.endSession() calls match up.
+ private boolean mIsStartedFromActiveSession = false;
+ // Optionally provided info about the method/class/component that started the session in order
+ // to make Logging easier. This info will be provided in parentheses along with the session.
+ private String mOwnerInfo;
+
+ public Session(String sessionId, String shortMethodName, long startTimeMs, long threadID,
+ boolean isStartedFromActiveSession, String ownerInfo) {
+ setSessionId(sessionId);
+ setShortMethodName(shortMethodName);
+ mExecutionStartTimeMs = startTimeMs;
+ mParentSession = null;
+ mChildSessions = new ArrayList<>(5);
+ mIsStartedFromActiveSession = isStartedFromActiveSession;
+ mOwnerInfo = ownerInfo;
+ }
+
+ public void setSessionId(@NonNull String sessionId) {
+ if (sessionId == null) {
+ mSessionId = "?";
+ }
+ mSessionId = sessionId;
+ }
+
+ public String getShortMethodName() {
+ return mShortMethodName;
+ }
+
+ public void setShortMethodName(String shortMethodName) {
+ if (shortMethodName == null) {
+ shortMethodName = "";
+ }
+ mShortMethodName = shortMethodName;
+ }
+
+ public void setParentSession(Session parentSession) {
+ mParentSession = parentSession;
+ }
+
+ public void addChild(Session childSession) {
+ if (childSession != null) {
+ mChildSessions.add(childSession);
+ }
+ }
+
+ public void removeChild(Session child) {
+ if (child != null) {
+ mChildSessions.remove(child);
+ }
+ }
+
+ public long getExecutionStartTimeMilliseconds() {
+ return mExecutionStartTimeMs;
+ }
+
+ public void setExecutionStartTimeMs(long startTimeMs) {
+ mExecutionStartTimeMs = startTimeMs;
+ }
+
+ public Session getParentSession() {
+ return mParentSession;
+ }
+
+ public ArrayList<Session> getChildSessions() {
+ return mChildSessions;
+ }
+
+ public boolean isSessionCompleted() {
+ return mIsCompleted;
+ }
+
+ public boolean isStartedFromActiveSession() {
+ return mIsStartedFromActiveSession;
+ }
+
+ // Mark this session complete. This will be deleted by Log when all subsessions are complete
+ // as well.
+ public void markSessionCompleted(long executionEndTimeMs) {
+ mExecutionEndTimeMs = executionEndTimeMs;
+ mIsCompleted = true;
+ }
+
+ public long getLocalExecutionTime() {
+ if (mExecutionEndTimeMs == UNDEFINED) {
+ return UNDEFINED;
+ }
+ return mExecutionEndTimeMs - mExecutionStartTimeMs;
+ }
+
+ public synchronized String getNextChildId() {
+ return String.valueOf(mChildCounter++);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof Session)) {
+ return false;
+ }
+ if (obj == this) {
+ return true;
+ }
+ Session otherSession = (Session) obj;
+ return (mSessionId.equals(otherSession.mSessionId)) &&
+ (mShortMethodName.equals(otherSession.mShortMethodName)) &&
+ mExecutionStartTimeMs == otherSession.mExecutionStartTimeMs &&
+ mParentSession == otherSession.mParentSession &&
+ mChildSessions.equals(otherSession.mChildSessions) &&
+ mIsCompleted == otherSession.mIsCompleted &&
+ mExecutionEndTimeMs == otherSession.mExecutionEndTimeMs &&
+ mChildCounter == otherSession.mChildCounter &&
+ mIsStartedFromActiveSession == otherSession.mIsStartedFromActiveSession &&
+ mOwnerInfo == otherSession.mOwnerInfo;
+ }
+
+ // Builds full session id recursively
+ private String getFullSessionId() {
+ // Cache mParentSession locally to prevent a concurrency problem where
+ // Log.endParentSessions() is called while a logging statement is running (Log.i, for
+ // example) and setting mParentSession to null in a different thread after the null check
+ // occurred.
+ Session parentSession = mParentSession;
+ if (parentSession == null) {
+ return mSessionId;
+ } else {
+ return parentSession.getFullSessionId() + "_" + mSessionId;
+ }
+ }
+
+ // Print out the full Session tree from any subsession node
+ public String printFullSessionTree() {
+ // Get to the top of the tree
+ Session topNode = this;
+ while (topNode.getParentSession() != null) {
+ topNode = topNode.getParentSession();
+ }
+ return topNode.printSessionTree();
+ }
+
+ // Recursively move down session tree using DFS, but print out each node when it is reached.
+ public String printSessionTree() {
+ StringBuilder sb = new StringBuilder();
+ printSessionTree(0, sb);
+ return sb.toString();
+ }
+
+ private void printSessionTree(int tabI, StringBuilder sb) {
+ sb.append(toString());
+ for (Session child : mChildSessions) {
+ sb.append("\n");
+ for (int i = 0; i <= tabI; i++) {
+ sb.append("\t");
+ }
+ child.printSessionTree(tabI + 1, sb);
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (mParentSession != null && mIsStartedFromActiveSession) {
+ // Log.startSession was called from within another active session. Use the parent's
+ // Id instead of the child to reduce confusion.
+ return mParentSession.toString();
+ } else {
+ StringBuilder methodName = new StringBuilder();
+ methodName.append(mShortMethodName);
+ if (mOwnerInfo != null && !mOwnerInfo.isEmpty()) {
+ methodName.append("(InCall package: ");
+ methodName.append(mOwnerInfo);
+ methodName.append(")");
+ }
+ return methodName.toString() + "@" + getFullSessionId();
+ }
+ }
+}
diff --git a/telecomm/java/android/telecom/Logging/SessionManager.java b/telecomm/java/android/telecom/Logging/SessionManager.java
new file mode 100644
index 0000000..a4e8977
--- /dev/null
+++ b/telecomm/java/android/telecom/Logging/SessionManager.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom.Logging;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.util.Base64;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * TODO: Create better Sessions Documentation
+ * @hide
+ */
+
+public class SessionManager {
+
+ // Currently using 3 letters, So don't exceed 64^3
+ private static final long SESSION_ID_ROLLOVER_THRESHOLD = 262144;
+
+ // This parameter can be overridden in Telecom's Timeouts class.
+ public static final long DEFAULT_SESSION_TIMEOUT_MS = 30000L; // 30 seconds
+
+ private static String LOGGING_TAG = "Logging";
+
+ private static final String TIMEOUTS_PREFIX = "telecom.";
+
+ // Synchronized in all method calls
+ private int sCodeEntryCounter = 0;
+ private Context mContext;
+
+ @VisibleForTesting
+ public ConcurrentHashMap<Integer, Session> sSessionMapper = new ConcurrentHashMap<>(100);
+ @VisibleForTesting
+ public Handler sSessionCleanupHandler = new Handler(Looper.getMainLooper());
+ @VisibleForTesting
+ public java.lang.Runnable sCleanStaleSessions = () ->
+ cleanupStaleSessions(getSessionCleanupTimeoutMs());
+
+ // Overridden in LogTest to skip query to ContentProvider
+ private interface ISessionCleanupTimeoutMs {
+ long get();
+ }
+
+ @VisibleForTesting
+ public ISessionCleanupTimeoutMs sSessionCleanupTimeoutMs = () -> {
+ // mContext may be null in some cases, such as testing. For these cases, use the
+ // default value.
+ if (mContext == null) {
+ return DEFAULT_SESSION_TIMEOUT_MS;
+ }
+ return getCleanupTimeout(mContext);
+ };
+
+ // Usage is synchronized on this class.
+ private List<ISessionListener> mSessionListeners = new ArrayList<>();
+
+ public interface ISessionListener {
+ /**
+ * This method is run when a full Session has completed.
+ * @param sessionName The name of the Session that has completed.
+ * @param timeMs The time it took to complete in ms.
+ */
+ void sessionComplete(String sessionName, long timeMs);
+ }
+
+ public interface ISessionIdQueryHandler {
+ String getSessionId();
+ }
+
+ public void setContext(Context context) {
+ mContext = context;
+ }
+
+ public SessionManager() {
+ }
+
+ private long getSessionCleanupTimeoutMs() {
+ return sSessionCleanupTimeoutMs.get();
+ }
+
+ private synchronized void resetStaleSessionTimer() {
+ sSessionCleanupHandler.removeCallbacksAndMessages(null);
+ // Will be null in Log Testing
+ if (sCleanStaleSessions != null) {
+ sSessionCleanupHandler.postDelayed(sCleanStaleSessions, getSessionCleanupTimeoutMs());
+ }
+ }
+
+ /**
+ * Call at an entry point to the Telecom code to track the session. This code must be
+ * accompanied by a Log.endSession().
+ */
+ public synchronized void startSession(String shortMethodName,
+ String callerIdentification) {
+ resetStaleSessionTimer();
+ int threadId = getCallingThreadId();
+ Session activeSession = sSessionMapper.get(threadId);
+ // We have called startSession within an active session that has not ended... Register this
+ // session as a subsession.
+ if (activeSession != null) {
+ Session childSession = createSubsession(true);
+ continueSession(childSession, shortMethodName);
+ return;
+ }
+ Session newSession = new Session(getNextSessionID(), shortMethodName,
+ System.currentTimeMillis(), threadId, false, callerIdentification);
+ sSessionMapper.put(threadId, newSession);
+
+ android.telecom.Log.v(LOGGING_TAG, Session.START_SESSION);
+ }
+
+
+ /**
+ * Notifies the logging system that a subsession will be run at a later point and
+ * allocates the resources. Returns a session object that must be used in
+ * Log.continueSession(...) to start the subsession.
+ */
+ public Session createSubsession() {
+ return createSubsession(false);
+ }
+
+ private synchronized Session createSubsession(boolean isStartedFromActiveSession) {
+ int threadId = getCallingThreadId();
+ Session threadSession = sSessionMapper.get(threadId);
+ if (threadSession == null) {
+ android.telecom.Log.d(LOGGING_TAG, "Log.createSubsession was called with no session " +
+ "active.");
+ return null;
+ }
+ // Start execution time of the session will be overwritten in continueSession(...).
+ Session newSubsession = new Session(threadSession.getNextChildId(),
+ threadSession.getShortMethodName(), System.currentTimeMillis(), threadId,
+ isStartedFromActiveSession, null);
+ threadSession.addChild(newSubsession);
+ newSubsession.setParentSession(threadSession);
+
+ if (!isStartedFromActiveSession) {
+ android.telecom.Log.v(LOGGING_TAG, Session.CREATE_SUBSESSION + " " +
+ newSubsession.toString());
+ } else {
+ android.telecom.Log.v(LOGGING_TAG, Session.CREATE_SUBSESSION +
+ " (Invisible subsession)");
+ }
+ return newSubsession;
+ }
+
+ /**
+ * Cancels a subsession that had Log.createSubsession() called on it, but will never have
+ * Log.continueSession(...) called on it due to an error. Allows the subsession to be cleaned
+ * gracefully instead of being removed by the sSessionCleanupHandler forcefully later.
+ */
+ public synchronized void cancelSubsession(Session subsession) {
+ if (subsession == null) {
+ return;
+ }
+
+ subsession.markSessionCompleted(0);
+ endParentSessions(subsession);
+ }
+
+ /**
+ * Starts the subsession that was created in Log.CreateSubsession. The Log.endSession() method
+ * must be called at the end of this method. The full session will complete when all
+ * subsessions are completed.
+ */
+ public synchronized void continueSession(Session subsession, String shortMethodName) {
+ if (subsession == null) {
+ return;
+ }
+ resetStaleSessionTimer();
+ String callingMethodName = subsession.getShortMethodName();
+ subsession.setShortMethodName(callingMethodName + "->" + shortMethodName);
+ subsession.setExecutionStartTimeMs(System.currentTimeMillis());
+ Session parentSession = subsession.getParentSession();
+ if (parentSession == null) {
+ android.telecom.Log.d(LOGGING_TAG, "Log.continueSession was called with no session " +
+ "active for method %s.", shortMethodName);
+ return;
+ }
+
+ sSessionMapper.put(getCallingThreadId(), subsession);
+ if (!subsession.isStartedFromActiveSession()) {
+ android.telecom.Log.v(LOGGING_TAG, Session.CONTINUE_SUBSESSION);
+ } else {
+ android.telecom.Log.v(LOGGING_TAG, Session.CONTINUE_SUBSESSION +
+ " (Invisible Subsession) with Method " + shortMethodName);
+ }
+ }
+
+ /**
+ * Ends the current session/subsession. Must be called after a Log.startSession(...) and
+ * Log.continueSession(...) call.
+ */
+ public synchronized void endSession() {
+ int threadId = getCallingThreadId();
+ Session completedSession = sSessionMapper.get(threadId);
+ if (completedSession == null) {
+ android.telecom.Log.w(LOGGING_TAG, "Log.endSession was called with no session active.");
+ return;
+ }
+
+ completedSession.markSessionCompleted(System.currentTimeMillis());
+ if (!completedSession.isStartedFromActiveSession()) {
+ android.telecom.Log.v(LOGGING_TAG, Session.END_SUBSESSION + " (dur: " +
+ completedSession.getLocalExecutionTime() + " mS)");
+ } else {
+ android.telecom.Log.v(LOGGING_TAG, Session.END_SUBSESSION +
+ " (Invisible Subsession) (dur: " + completedSession.getLocalExecutionTime() +
+ " ms)");
+ }
+ // Remove after completed so that reference still exists for logging the end events
+ Session parentSession = completedSession.getParentSession();
+ sSessionMapper.remove(threadId);
+ endParentSessions(completedSession);
+ // If this subsession was started from a parent session using Log.startSession, return the
+ // ThreadID back to the parent after completion.
+ if (parentSession != null && !parentSession.isSessionCompleted() &&
+ completedSession.isStartedFromActiveSession()) {
+ sSessionMapper.put(threadId, parentSession);
+ }
+ }
+
+ // Recursively deletes all complete parent sessions of the current subsession if it is a leaf.
+ private void endParentSessions(Session subsession) {
+ // Session is not completed or not currently a leaf, so we can not remove because a child is
+ // still running
+ if (!subsession.isSessionCompleted() || subsession.getChildSessions().size() != 0) {
+ return;
+ }
+
+ Session parentSession = subsession.getParentSession();
+ if (parentSession != null) {
+ subsession.setParentSession(null);
+ parentSession.removeChild(subsession);
+ endParentSessions(parentSession);
+ } else {
+ // All of the subsessions have been completed and it is time to report on the full
+ // running time of the session.
+ long fullSessionTimeMs =
+ System.currentTimeMillis() - subsession.getExecutionStartTimeMilliseconds();
+ android.telecom.Log.v(LOGGING_TAG, Session.END_SESSION + " (dur: " + fullSessionTimeMs
+ + " ms): " + subsession.toString());
+ // TODO: Add analytics hook
+ for (ISessionListener l : mSessionListeners) {
+ l.sessionComplete(subsession.getShortMethodName(), fullSessionTimeMs);
+ }
+ }
+ }
+
+ public String getSessionId() {
+ Session currentSession = sSessionMapper.get(getCallingThreadId());
+ return currentSession != null ? currentSession.toString() : "";
+ }
+
+ public synchronized void registerSessionListener(ISessionListener l) {
+ if (l != null) {
+ mSessionListeners.add(l);
+ }
+ }
+
+ private synchronized String getNextSessionID() {
+ Integer nextId = sCodeEntryCounter++;
+ if (nextId >= SESSION_ID_ROLLOVER_THRESHOLD) {
+ restartSessionCounter();
+ nextId = sCodeEntryCounter++;
+ }
+ return getBase64Encoding(nextId);
+ }
+
+ @VisibleForTesting
+ public synchronized void restartSessionCounter() {
+ sCodeEntryCounter = 0;
+ }
+
+ @VisibleForTesting
+ public String getBase64Encoding(int number) {
+ byte[] idByteArray = ByteBuffer.allocate(4).putInt(number).array();
+ idByteArray = Arrays.copyOfRange(idByteArray, 2, 4);
+ return Base64.encodeToString(idByteArray, Base64.NO_WRAP | Base64.NO_PADDING);
+ }
+
+ public int getCallingThreadId() {
+ return android.os.Process.myTid();
+ }
+
+ @VisibleForTesting
+ private synchronized void cleanupStaleSessions(long timeoutMs) {
+ String logMessage = "Stale Sessions Cleaned:\n";
+ boolean isSessionsStale = false;
+ long currentTimeMs = System.currentTimeMillis();
+ // Remove references that are in the Session Mapper (causing GC to occur) on
+ // sessions that are lasting longer than LOGGING_SESSION_TIMEOUT_MS.
+ // If this occurs, then there is most likely a Session active that never had
+ // Log.endSession called on it.
+ for (Iterator<ConcurrentHashMap.Entry<Integer, Session>> it =
+ sSessionMapper.entrySet().iterator(); it.hasNext(); ) {
+ ConcurrentHashMap.Entry<Integer, Session> entry = it.next();
+ Session session = entry.getValue();
+ if (currentTimeMs - session.getExecutionStartTimeMilliseconds() > timeoutMs) {
+ it.remove();
+ logMessage += session.printFullSessionTree() + "\n";
+ isSessionsStale = true;
+ }
+ }
+ if (isSessionsStale) {
+ android.telecom.Log.w(LOGGING_TAG, logMessage);
+ } else {
+ android.telecom.Log.v(LOGGING_TAG, "No stale logging sessions needed to be cleaned...");
+ }
+ }
+
+ /**
+ * Returns the amount of time after a Logging session has been started that Telecom is set to
+ * perform a sweep to check and make sure that the session is still not incomplete (stale).
+ */
+ private long getCleanupTimeout(Context context) {
+ return Settings.Secure.getLong(context.getContentResolver(), TIMEOUTS_PREFIX +
+ "stale_session_cleanup_timeout_millis", DEFAULT_SESSION_TIMEOUT_MS);
+ }
+}
diff --git a/telecomm/java/android/telecom/Logging/TimedEvent.java b/telecomm/java/android/telecom/Logging/TimedEvent.java
new file mode 100644
index 0000000..6785e92
--- /dev/null
+++ b/telecomm/java/android/telecom/Logging/TimedEvent.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.telecom.Logging;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @hide
+ */
+public abstract class TimedEvent<T> {
+ public abstract long getTime();
+ public abstract T getKey();
+
+ public static <T> Map<T, Double> averageTimings(Collection<? extends TimedEvent<T>> events) {
+ HashMap<T, Integer> counts = new HashMap<>();
+ HashMap<T, Double> result = new HashMap<>();
+
+ for (TimedEvent<T> entry : events) {
+ if (counts.containsKey(entry.getKey())) {
+ counts.put(entry.getKey(), counts.get(entry.getKey()) + 1);
+ result.put(entry.getKey(), result.get(entry.getKey()) + entry.getTime());
+ } else {
+ counts.put(entry.getKey(), 1);
+ result.put(entry.getKey(), (double) entry.getTime());
+ }
+ }
+
+ for (Map.Entry<T, Double> entry : result.entrySet()) {
+ result.put(entry.getKey(), entry.getValue() / counts.get(entry.getKey()));
+ }
+
+ return result;
+ }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index deed6d4..edcec3c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -57,6 +57,13 @@
// system image, that can be added in packages/apps/CarrierConfig.
/**
+ * This flag specifies whether VoLTE availability is based on provisioning. By default this is
+ * false.
+ */
+ public static final String
+ KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool";
+
+ /**
* Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED
* events from the Sim.
* If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and
@@ -746,6 +753,16 @@
public static final String KEY_CARRIER_ADDITIONAL_CBS_CHANNELS_STRINGS =
"carrier_additional_cbs_channels_strings";
+ /**
+ * Indicates whether STK LAUNCH_BROWSER command is disabled.
+ * If {@code true}, then the browser will not be launched
+ * on UI for the LAUNCH_BROWSER STK command.
+ * @hide
+ */
+ public static final String KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL =
+ "stk_disable_launch_browser_bool";
+
+
// These variables are used by the MMS service and exposed through another API, {@link
// SmsManager}. The variable names and string values are copied from there.
public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
@@ -1081,6 +1098,8 @@
sDefaults.putBoolean(KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL, false);
sDefaults.putBoolean(KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false);
sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false);
+
+ sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONED_BOOL, false);
sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false);
sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true);
sDefaults.putBoolean(KEY_PREFER_2G_BOOL, true);
@@ -1221,6 +1240,7 @@
sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
sDefaults.putStringArray(FILTERED_CNAP_NAMES_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
+ sDefaults.putBoolean(KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL, false);
}
/**
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 05cb31e..d4104bd 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -176,13 +176,13 @@
// However, if there is any code that this Handler calls (such as in
// super.handleMessage) that DOES place unexpected messages on the
// queue, then we need pass these messages on.
- if (DBG) Rlog.d(LOG_TAG, "Unexpected command (CookieWrapper is null): " + msg.what +
+ Rlog.i(LOG_TAG, "Unexpected command (CookieWrapper is null): " + msg.what +
" ignored by CallerInfoWorkerHandler, passing onto parent.");
super.handleMessage(msg);
} else {
- if (DBG) Rlog.d(LOG_TAG, "Processing event: " + cw.event + " token (arg1): " + msg.arg1 +
+ Rlog.d(LOG_TAG, "Processing event: " + cw.event + " token (arg1): " + msg.arg1 +
" command: " + msg.what + " query URI: " + sanitizeUriToString(args.uri));
switch (cw.event) {
@@ -239,7 +239,7 @@
*/
@Override
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- if (DBG) Rlog.d(LOG_TAG, "##### onQueryComplete() ##### query complete for token: " + token);
+ Rlog.d(LOG_TAG, "##### onQueryComplete() ##### query complete for token: " + token);
//get the cookie and notify the listener.
CookieWrapper cw = (CookieWrapper) cookie;
@@ -248,7 +248,7 @@
// from within this code.
// However, if there is any code that calls this method, we should
// check the parameters to make sure they're viable.
- if (DBG) Rlog.d(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
+ Rlog.i(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
if (cursor != null) {
cursor.close();
}
@@ -333,9 +333,11 @@
//notify the listener that the query is complete.
if (cw.listener != null) {
- if (DBG) Rlog.d(LOG_TAG, "notifying listener: " + cw.listener.getClass().toString() +
+ Rlog.d(LOG_TAG, "notifying listener: " + cw.listener.getClass().toString() +
" for token: " + token + mCallerInfo);
cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
+ } else {
+ Rlog.w(LOG_TAG, "There is no listener to notify for this query.");
}
if (cursor != null) {
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index a91e9be..891b8a1a 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -462,4 +462,5 @@
int RIL_UNSOL_STK_CC_ALPHA_NOTIFY = 1044;
int RIL_UNSOL_LCEDATA_RECV = 1045;
int RIL_UNSOL_PCO_DATA = 1046;
+ int RIL_UNSOL_MODEM_RESTART = 1047;
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index a4aab7c..da27ea9 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -87,6 +87,11 @@
}
private Test[] mTests = new Test[] {
+ new Test("cancel all") {
+ public void run() {
+ mNM.cancelAll();
+ }
+ },
new Test("Phone call") {
public void run()
{
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
index f65d109..be9a541 100644
--- a/tests/UiBench/Android.mk
+++ b/tests/UiBench/Android.mk
@@ -2,6 +2,8 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := 24
+LOCAL_MIN_SDK_VERSION := 21
# omit gradle 'build' dir
LOCAL_SRC_FILES := $(call all-java-files-under,src)
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index cb5f6c7..29154aa 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -102,10 +102,18 @@
<activity
android:name=".SlowBindRecyclerViewActivity"
android:label="General/Slow Bind RecyclerView" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="com.android.test.uibench.TEST" />
- </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".SlowNestedRecyclerViewActivity"
+ android:label="General/Slow Nested RecyclerView" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
</activity>
<activity
android:name=".ActivityTransition"
@@ -141,6 +149,14 @@
<category android:name="com.android.test.uibench.TEST" />
</intent-filter>
</activity>
+ <activity
+ android:name=".RenderingJitter"
+ android:label="Rendering/Jitter" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
<!-- Inflation -->
<activity
diff --git a/tests/UiBench/res/layout/rendering_jitter.xml b/tests/UiBench/res/layout/rendering_jitter.xml
new file mode 100644
index 0000000..aaa7551
--- /dev/null
+++ b/tests/UiBench/res/layout/rendering_jitter.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <TextView android:id="@+id/jitter_mma"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true" />
+
+ <TextView android:id="@+id/totalish_mma"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true" />
+
+ <TextView android:id="@+id/ui_frametime_mma"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true" />
+
+ <TextView android:id="@+id/rt_frametime_mma"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true" />
+
+ <TextView android:id="@+id/total_mma"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true" />
+
+ <View android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1" />
+
+ <view class="com.android.test.uibench.RenderingJitter$PointGraphView"
+ android:id="@+id/graph"
+ android:layout_height="200dp"
+ android:layout_width="match_parent" />
+
+</LinearLayout>
diff --git a/tests/UiBench/src/com/android/test/uibench/RenderingJitter.java b/tests/UiBench/src/com/android/test/uibench/RenderingJitter.java
new file mode 100644
index 0000000..e2a9bcb
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/RenderingJitter.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.uibench;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.FrameMetrics;
+import android.view.View;
+import android.view.Window;
+import android.view.Window.OnFrameMetricsAvailableListener;
+import android.view.animation.AnimationUtils;
+import android.widget.TextView;
+
+public class RenderingJitter extends Activity {
+ private TextView mJitterReport;
+ private TextView mUiFrameTimeReport;
+ private TextView mRenderThreadTimeReport;
+ private TextView mTotalFrameTimeReport;
+ private TextView mMostlyTotalFrameTimeReport;
+ private PointGraphView mGraph;
+
+ private static Handler sMetricsHandler;
+ static {
+ HandlerThread thread = new HandlerThread("frameMetricsListener");
+ thread.start();
+ sMetricsHandler = new Handler(thread.getLooper());
+ }
+
+ private Handler mUpdateHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case R.id.jitter_mma:
+ mJitterReport.setText((CharSequence) msg.obj);
+ break;
+ case R.id.totalish_mma:
+ mMostlyTotalFrameTimeReport.setText((CharSequence) msg.obj);
+ break;
+ case R.id.ui_frametime_mma:
+ mUiFrameTimeReport.setText((CharSequence) msg.obj);
+ break;
+ case R.id.rt_frametime_mma:
+ mRenderThreadTimeReport.setText((CharSequence) msg.obj);
+ break;
+ case R.id.total_mma:
+ mTotalFrameTimeReport.setText((CharSequence) msg.obj);
+ break;
+ case R.id.graph:
+ mGraph.addJitterSample(msg.arg1, msg.arg2);
+ break;
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.rendering_jitter);
+ View content = findViewById(android.R.id.content);
+ content.setBackground(new AnimatedBackgroundDrawable());
+ content.setKeepScreenOn(true);
+ mJitterReport = (TextView) findViewById(R.id.jitter_mma);
+ mMostlyTotalFrameTimeReport = (TextView) findViewById(R.id.totalish_mma);
+ mUiFrameTimeReport = (TextView) findViewById(R.id.ui_frametime_mma);
+ mRenderThreadTimeReport = (TextView) findViewById(R.id.rt_frametime_mma);
+ mTotalFrameTimeReport = (TextView) findViewById(R.id.total_mma);
+ mGraph = (PointGraphView) findViewById(R.id.graph);
+ mJitterReport.setText("abcdefghijklmnopqrstuvwxyz");
+ mMostlyTotalFrameTimeReport.setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ mUiFrameTimeReport.setText("0123456789");
+ mRenderThreadTimeReport.setText(",.!()[]{};");
+ getWindow().addOnFrameMetricsAvailableListener(mMetricsListener, sMetricsHandler);
+ }
+
+ public static final class PointGraphView extends View {
+ private static final float[] JITTER_LINES_MS = {
+ .5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 5.0f
+ };
+ private static final String[] JITTER_LINES_LABELS = makeLabels(JITTER_LINES_MS);
+ private static final int[] JITTER_LINES_COLORS = new int[] {
+ 0xFF00E676, 0xFFFFF176, 0xFFFDD835, 0xFFFBC02D, 0xFFF9A825,
+ 0xFFF57F17, 0xFFDD2C00
+ };
+ private Paint mPaint = new Paint();
+ private float[] mJitterYs = new float[JITTER_LINES_MS.length];
+ private float mLabelWidth;
+ private float mLabelHeight;
+ private float mDensity;
+ private float mGraphScale;
+ private float mGraphMaxMs;
+
+ private float[] mJitterPoints;
+ private float[] mJitterAvgPoints;
+
+ public PointGraphView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setWillNotDraw(false);
+ mDensity = context.getResources().getDisplayMetrics().density;
+ mPaint.setTextSize(dp(10));
+ Rect textBounds = new Rect();
+ mPaint.getTextBounds("8.8", 0, 3, textBounds);
+ mLabelWidth = textBounds.width() + dp(2);
+ mLabelHeight = textBounds.height();
+ }
+
+ public void addJitterSample(int jitterUs, int jitterUsAvg) {
+ for (int i = 1; i < mJitterPoints.length - 2; i += 2) {
+ mJitterPoints[i] = mJitterPoints[i + 2];
+ mJitterAvgPoints[i] = mJitterAvgPoints[i + 2];
+ }
+ mJitterPoints[mJitterPoints.length - 1] =
+ getHeight() - mGraphScale * (jitterUs / 1000.0f);
+ mJitterAvgPoints[mJitterAvgPoints.length - 1] =
+ getHeight() - mGraphScale * (jitterUsAvg / 1000.0f);
+ invalidate();
+ }
+
+ private float dp(float dp) {
+ return mDensity * dp;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ canvas.drawColor(0x90000000);
+ int h = getHeight();
+ int w = getWidth();
+ mPaint.setColor(Color.WHITE);
+ mPaint.setStrokeWidth(dp(1));
+ canvas.drawLine(mLabelWidth, 0, mLabelWidth, h, mPaint);
+ for (int i = 0; i < JITTER_LINES_LABELS.length; i++) {
+ canvas.drawText(JITTER_LINES_LABELS[i],
+ 0, (float) Math.floor(mJitterYs[i] + mLabelHeight * .5f), mPaint);
+ }
+ for (int i = 0; i < JITTER_LINES_LABELS.length; i++) {
+ mPaint.setColor(JITTER_LINES_COLORS[i]);
+ canvas.drawLine(mLabelWidth, mJitterYs[i], w, mJitterYs[i], mPaint);
+ }
+ mPaint.setStrokeWidth(dp(2));
+ mPaint.setColor(Color.WHITE);
+ canvas.drawPoints(mJitterPoints, mPaint);
+ mPaint.setColor(0xFF2196F3);
+ canvas.drawPoints(mJitterAvgPoints, mPaint);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ int graphWidth = (int) ((w - mLabelWidth - dp(1)) / mDensity);
+ float[] oldJitterPoints = mJitterPoints;
+ float[] oldJitterAvgPoints = mJitterAvgPoints;
+ mJitterPoints = new float[graphWidth * 2];
+ mJitterAvgPoints = new float[graphWidth * 2];
+ for (int i = 0; i < mJitterPoints.length; i += 2) {
+ mJitterPoints[i] = mLabelWidth + (i / 2 + 1) * mDensity;
+ mJitterAvgPoints[i] = mJitterPoints[i];
+ }
+ if (oldJitterPoints != null) {
+ int newIndexShift = Math.max(mJitterPoints.length - oldJitterPoints.length, 0);
+ int oldIndexShift = oldJitterPoints.length - mJitterPoints.length;
+ for (int i = 1 + newIndexShift; i < mJitterPoints.length; i += 2) {
+ mJitterPoints[i] = oldJitterPoints[i + oldIndexShift];
+ mJitterAvgPoints[i] = oldJitterAvgPoints[i + oldIndexShift];
+ }
+ }
+ mGraphMaxMs = JITTER_LINES_MS[JITTER_LINES_MS.length - 1] + .5f;
+ mGraphScale = (h / mGraphMaxMs);
+ for (int i = 0; i < JITTER_LINES_MS.length; i++) {
+ mJitterYs[i] = (float) Math.floor(h - mGraphScale * JITTER_LINES_MS[i]);
+ }
+ }
+
+ private static String[] makeLabels(float[] divisions) {
+ String[] ret = new String[divisions.length];
+ for (int i = 0; i < divisions.length; i++) {
+ ret[i] = Float.toString(divisions[i]);
+ }
+ return ret;
+ }
+ }
+
+ private final OnFrameMetricsAvailableListener mMetricsListener = new OnFrameMetricsAvailableListener() {
+ private final static double WEIGHT = 40;
+ private long mPreviousFrameTotal;
+ private double mJitterMma;
+ private double mUiFrametimeMma;
+ private double mRtFrametimeMma;
+ private double mTotalFrametimeMma;
+ private double mMostlyTotalFrametimeMma;
+ private boolean mNeedsFirstValues = true;
+
+ @Override
+ public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics,
+ int dropCountSinceLastInvocation) {
+ if (frameMetrics.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1) {
+ return;
+ }
+
+ long uiDuration = frameMetrics.getMetric(FrameMetrics.INPUT_HANDLING_DURATION)
+ + frameMetrics.getMetric(FrameMetrics.ANIMATION_DURATION)
+ + frameMetrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION)
+ + frameMetrics.getMetric(FrameMetrics.DRAW_DURATION);
+ long rtDuration = frameMetrics.getMetric(FrameMetrics.SYNC_DURATION)
+ + frameMetrics.getMetric(FrameMetrics.COMMAND_ISSUE_DURATION);
+ long totalDuration = frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION);
+ long jitter = Math.abs(totalDuration - mPreviousFrameTotal);
+ if (mNeedsFirstValues) {
+ mJitterMma = 0;
+ mUiFrametimeMma = uiDuration;
+ mRtFrametimeMma = rtDuration;
+ mTotalFrametimeMma = totalDuration;
+ mMostlyTotalFrametimeMma = uiDuration + rtDuration;
+ mNeedsFirstValues = false;
+ } else {
+ mJitterMma = add(mJitterMma, jitter);
+ mUiFrametimeMma = add(mUiFrametimeMma, uiDuration);
+ mRtFrametimeMma = add(mRtFrametimeMma, rtDuration);
+ mTotalFrametimeMma = add(mTotalFrametimeMma, totalDuration);
+ mMostlyTotalFrametimeMma = add(mMostlyTotalFrametimeMma, uiDuration + rtDuration);
+ }
+ mPreviousFrameTotal = totalDuration;
+ mUpdateHandler.obtainMessage(R.id.jitter_mma,
+ String.format("Jitter: %.3fms", toMs(mJitterMma))).sendToTarget();
+ mUpdateHandler.obtainMessage(R.id.totalish_mma,
+ String.format("CPU-total duration: %.3fms", toMs(mMostlyTotalFrametimeMma))).sendToTarget();
+ mUpdateHandler.obtainMessage(R.id.ui_frametime_mma,
+ String.format("UI duration: %.3fms", toMs(mUiFrametimeMma))).sendToTarget();
+ mUpdateHandler.obtainMessage(R.id.rt_frametime_mma,
+ String.format("RT duration: %.3fms", toMs(mRtFrametimeMma))).sendToTarget();
+ mUpdateHandler.obtainMessage(R.id.total_mma,
+ String.format("Total duration: %.3fms", toMs(mTotalFrametimeMma))).sendToTarget();
+ mUpdateHandler.obtainMessage(R.id.graph, (int) (jitter / 1000),
+ (int) (mJitterMma / 1000)).sendToTarget();
+ }
+
+ double add(double previous, double today) {
+ return (((WEIGHT - 1) * previous) + today) / WEIGHT;
+ }
+
+ double toMs(double val) {
+ return val / 1000000;
+ }
+ };
+
+ private static final class AnimatedBackgroundDrawable extends Drawable {
+ private static final int FROM_COLOR = 0xFF18FFFF;
+ private static final int TO_COLOR = 0xFF40C4FF;
+ private static final int DURATION = 1400;
+
+ private final Paint mPaint;
+ private boolean mReverse;
+ private long mStartTime;
+ private int mColor;
+
+ private boolean mReverseX;
+ private boolean mReverseY;
+ private float mX;
+ private float mY;
+ private float mRadius;
+ private float mMoveStep = 10.0f;
+
+ public AnimatedBackgroundDrawable() {
+ mPaint = new Paint();
+ mPaint.setColor(0xFFFFFF00);
+ mPaint.setAntiAlias(true);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ stepColor();
+ canvas.drawColor(mColor);
+
+ mX += (mReverseX ? -mMoveStep : mMoveStep);
+ mY += (mReverseY ? -mMoveStep : mMoveStep);
+ clampXY();
+ canvas.drawCircle(mX, mY, mRadius, mPaint);
+
+ invalidateSelf();
+ }
+
+ private void clampXY() {
+ if (mX <= mRadius) {
+ mReverseX = false;
+ mX = mRadius;
+ }
+ if (mY <= mRadius) {
+ mReverseY = false;
+ mY = mRadius;
+ }
+ float maxX = getBounds().width() - mRadius;
+ if (mX >= maxX) {
+ mReverseX = true;
+ mX = maxX;
+ }
+ float maxY = getBounds().height() - mRadius;
+ if (mY >= maxY) {
+ mReverseY = true;
+ mY = maxY;
+ }
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ super.onBoundsChange(bounds);
+ mMoveStep = Math.min(bounds.width(), bounds.height()) / 130.0f;
+ mRadius = Math.min(bounds.width(), bounds.height()) / 20.0f;
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.OPAQUE;
+ }
+
+ private void stepColor() {
+ if (mStartTime == 0) {
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ }
+ float frac = (AnimationUtils.currentAnimationTimeMillis() - mStartTime)
+ / (float) DURATION;
+ if (frac > 1.0f) frac = 1.0f;
+ int dest = mReverse ? FROM_COLOR : TO_COLOR;
+ int src = mReverse ? TO_COLOR : FROM_COLOR;
+ int r = (int) (Color.red(src) + (Color.red(dest) - Color.red(src)) * frac);
+ int g = (int) (Color.green(src) + (Color.green(dest) - Color.green(src)) * frac);
+ int b = (int) (Color.blue(src) + (Color.blue(dest) - Color.blue(src)) * frac);
+ mColor = Color.rgb(r, g, b);
+ if (frac == 1.0f) {
+ mStartTime = 0;
+ mReverse = !mReverse;
+ }
+ }
+ }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/SlowNestedRecyclerViewActivity.java b/tests/UiBench/src/com/android/test/uibench/SlowNestedRecyclerViewActivity.java
new file mode 100644
index 0000000..305c051
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/SlowNestedRecyclerViewActivity.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.InsetDrawable;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.test.uibench.recyclerview.RvCompatListActivity;
+
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+
+public class SlowNestedRecyclerViewActivity extends RvCompatListActivity {
+ private static final int OUTER_ITEM_COUNT = 100;
+ private static final int INNER_ITEM_COUNT = 20;
+
+ private static final long INNER_ITEM_CREATE_NS = TimeUnit.MILLISECONDS.toNanos(6);
+ private static final long INNER_ITEM_BIND_NS = TimeUnit.MILLISECONDS.toNanos(1);
+ private static final long INNER_ITEM_ATTACH_NS = TimeUnit.MILLISECONDS.toNanos(1);
+
+ private static final long OUTER_ITEM_CREATE_NS = TimeUnit.MILLISECONDS.toNanos(3);
+ private static final long OUTER_ITEM_BIND_NS = TimeUnit.MILLISECONDS.toNanos(1);
+ private static final long OUTER_ITEM_ATTACH_NS = TimeUnit.MILLISECONDS.toNanos(1);
+
+ private SizeData mSizeData;
+
+ private static class SizeData {
+ final int innerItemWidth;
+ final int innerItemHeight;
+ final int headerHeight;
+
+ SizeData(Resources resources) {
+ innerItemWidth = (int) (resources.getDisplayMetrics().widthPixels / 3.3f);
+ innerItemHeight = (int) (innerItemWidth * 1.6f);
+ headerHeight = (int) (resources.getDisplayMetrics().heightPixels * 0.5f);
+ }
+ }
+
+ private SizeData getSizeData(Resources resources) {
+ if (mSizeData == null) {
+ mSizeData = new SizeData(resources);
+ }
+ return mSizeData;
+ }
+
+ @Override
+ protected RecyclerView.LayoutManager createLayoutManager(Context context) {
+ return new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
+ }
+
+ @Override
+ protected RecyclerView.Adapter createAdapter() {
+ return new OuterAdapter();
+ }
+
+ private class InnerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ final long start = System.nanoTime();
+
+ final float density = parent.getResources().getDisplayMetrics().density;
+ View view = new View(parent.getContext()) {
+ @Override
+ protected void onAttachedToWindow() {
+ final long start = System.nanoTime();
+ super.onAttachedToWindow();
+ while (System.nanoTime() - start < INNER_ITEM_ATTACH_NS);
+ }
+ };
+
+ SizeData sizeData = getSizeData(parent.getResources());
+ view.setMinimumWidth(sizeData.innerItemWidth);
+ view.setMinimumHeight(sizeData.innerItemHeight);
+
+ GradientDrawable bg = new GradientDrawable();
+ bg.setCornerRadius(10 * density);
+ bg.setColor(Color.BLACK);
+ final int pad = (int)(10 * density);
+ view.setPadding(pad, pad, pad, pad);
+ view.setBackgroundDrawable(new InsetDrawable(bg, pad));
+ RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(view) {};
+
+ while (System.nanoTime() - start < INNER_ITEM_CREATE_NS);
+ return holder;
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ final long start = System.nanoTime();
+ while (System.nanoTime() - start < INNER_ITEM_BIND_NS);
+ }
+
+ @Override
+ public int getItemCount() { return INNER_ITEM_COUNT; }
+ }
+
+ private class OuterAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+ static final int TYPE_HEADER = 0;
+ static final int TYPE_RECYCLER = 1;
+
+ ArrayList<InnerAdapter> mAdapters = new ArrayList<>();
+ RecyclerView.RecycledViewPool mSharedPool = new RecyclerView.RecycledViewPool();
+
+ OuterAdapter() {
+ for (int i = 0; i < OUTER_ITEM_COUNT; i++) {
+ mAdapters.add(new InnerAdapter());
+ }
+ }
+
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ SizeData sizeData = getSizeData(parent.getResources());
+ if (viewType == TYPE_HEADER) {
+ View view = new View(parent.getContext());
+ view.setMinimumHeight(sizeData.headerHeight);
+ return new RecyclerView.ViewHolder(view) {};
+ } else {
+ final long start = System.nanoTime();
+
+ RecyclerView rv = new RecyclerView(parent.getContext()) {
+ @Override
+ protected void onAttachedToWindow() {
+ final long start = System.nanoTime();
+ super.onAttachedToWindow();
+ while (System.nanoTime() - start < OUTER_ITEM_ATTACH_NS);
+
+ }
+ };
+
+ rv.setLayoutParams(new RecyclerView.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, sizeData.innerItemHeight));
+ rv.setLayoutManager(new LinearLayoutManager(parent.getContext(),
+ LinearLayoutManager.HORIZONTAL, false));
+ rv.setRecycledViewPool(mSharedPool);
+ RecyclerView.ViewHolder holder = new RecyclerView.ViewHolder(rv) {};
+
+ while (System.nanoTime() - start < OUTER_ITEM_CREATE_NS);
+ return holder;
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
+ if (getItemViewType(position) == TYPE_RECYCLER) {
+ final long start = System.nanoTime();
+ ((RecyclerView)holder.itemView).setAdapter(mAdapters.get(position));
+ while (System.nanoTime() - start < OUTER_ITEM_BIND_NS);
+ }
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return position == 0 ? TYPE_HEADER : TYPE_RECYCLER;
+ }
+
+ @Override
+ public int getItemCount() {
+ return mAdapters.size();
+ }
+ }
+}
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index fb1370e..9b62e14 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -1281,7 +1281,7 @@
const size_t NL = locales.size();
for (size_t i=0; i<NL; i++) {
const char* localeStr = locales[i].string();
- assets.setLocale(localeStr != NULL ? localeStr : "");
+ assets.setConfiguration(config, localeStr != NULL ? localeStr : "");
String8 llabel = AaptXml::getResolvedAttribute(res, tree, LABEL_ATTR,
&error);
if (llabel != "") {
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index aea16c7..5f586a1 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -833,6 +833,7 @@
bpp = 4;
} else {
printf("Unknown color type %d.\n", color_type);
+ return;
}
for (j = 0; j < h; j++) {
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 60114fb..6bfedf3 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -24,7 +24,10 @@
sources := \
compile/IdAssigner.cpp \
compile/InlineXmlFormatParser.cpp \
+ compile/NinePatch.cpp \
compile/Png.cpp \
+ compile/PngChunkFilter.cpp \
+ compile/PngCrunch.cpp \
compile/PseudolocaleGenerator.cpp \
compile/Pseudolocalizer.cpp \
compile/XmlIdCollector.cpp \
@@ -34,12 +37,14 @@
flatten/XmlFlattener.cpp \
io/File.cpp \
io/FileSystem.cpp \
+ io/Io.cpp \
io/ZipArchive.cpp \
link/AutoVersioner.cpp \
link/ManifestFixer.cpp \
link/ProductFilter.cpp \
link/PrivateAttributeMover.cpp \
link/ReferenceLinker.cpp \
+ link/ResourceDeduper.cpp \
link/TableMerger.cpp \
link/VersionCollapser.cpp \
link/XmlNamespaceRemover.cpp \
@@ -56,6 +61,7 @@
util/Util.cpp \
ConfigDescription.cpp \
Debug.cpp \
+ DominatorTree.cpp \
Flags.cpp \
java/AnnotationProcessor.cpp \
java/ClassDefinition.cpp \
@@ -82,6 +88,7 @@
testSources := \
compile/IdAssigner_test.cpp \
compile/InlineXmlFormatParser_test.cpp \
+ compile/NinePatch_test.cpp \
compile/PseudolocaleGenerator_test.cpp \
compile/Pseudolocalizer_test.cpp \
compile/XmlIdCollector_test.cpp \
@@ -93,6 +100,7 @@
link/PrivateAttributeMover_test.cpp \
link/ProductFilter_test.cpp \
link/ReferenceLinker_test.cpp \
+ link/ResourceDeduper_test.cpp \
link/TableMerger_test.cpp \
link/VersionCollapser_test.cpp \
link/XmlNamespaceRemover_test.cpp \
@@ -106,6 +114,7 @@
util/StringPiece_test.cpp \
util/Util_test.cpp \
ConfigDescription_test.cpp \
+ DominatorTree_test.cpp \
java/AnnotationProcessor_test.cpp \
java/JavaClassGenerator_test.cpp \
java/ManifestClassGenerator_test.cpp \
@@ -152,7 +161,7 @@
cFlags := -Wall -Werror -Wno-unused-parameter -UNDEBUG
cFlags_darwin := -D_DARWIN_UNLIMITED_STREAMS
cFlags_windows := -Wno-maybe-uninitialized # Incorrectly marking use of Maybe.value() as error.
-cppFlags := -std=c++11 -Wno-missing-field-initializers -fno-exceptions -fno-rtti
+cppFlags := -Wno-missing-field-initializers -fno-exceptions -fno-rtti
protoIncludes := $(call generated-sources-dir-for,STATIC_LIBRARIES,libaapt2,HOST)
# ==========================================================
diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp
index c1697e7..1812d96 100644
--- a/tools/aapt2/ConfigDescription.cpp
+++ b/tools/aapt2/ConfigDescription.cpp
@@ -789,4 +789,96 @@
return copy;
}
+bool ConfigDescription::dominates(const ConfigDescription& o) const {
+ if (*this == defaultConfig() || *this == o) {
+ return true;
+ }
+ return matchWithDensity(o)
+ && !o.matchWithDensity(*this)
+ && !isMoreSpecificThan(o)
+ && !o.hasHigherPrecedenceThan(*this);
+}
+
+bool ConfigDescription::hasHigherPrecedenceThan(const ConfigDescription& o) const {
+ // The order of the following tests defines the importance of one
+ // configuration parameter over another. Those tests first are more
+ // important, trumping any values in those following them.
+ // The ordering should be the same as ResTable_config#isBetterThan.
+ if (mcc || o.mcc) return (!o.mcc);
+ if (mnc || o.mnc) return (!o.mnc);
+ if (language[0] || o.language[0]) return (!o.language[0]);
+ if (country[0] || o.country[0]) return (!o.country[0]);
+ // Script and variant require either a language or country, both of which
+ // have higher precedence.
+ if ((screenLayout | o.screenLayout) & MASK_LAYOUTDIR) {
+ return !(o.screenLayout & MASK_LAYOUTDIR);
+ }
+ if (smallestScreenWidthDp || o.smallestScreenWidthDp) return (!o.smallestScreenWidthDp);
+ if (screenWidthDp || o.screenWidthDp) return (!o.screenWidthDp);
+ if (screenHeightDp || o.screenHeightDp) return (!o.screenHeightDp);
+ if ((screenLayout | o.screenLayout) & MASK_SCREENSIZE) {
+ return !(o.screenLayout & MASK_SCREENSIZE);
+ }
+ if ((screenLayout | o.screenLayout) & MASK_SCREENLONG) {
+ return !(o.screenLayout & MASK_SCREENLONG);
+ }
+ if ((screenLayout2 | o.screenLayout2) & MASK_SCREENROUND) {
+ return !(o.screenLayout2 & MASK_SCREENROUND);
+ }
+ if (orientation || o.orientation) return (!o.orientation);
+ if ((uiMode | o.uiMode) & MASK_UI_MODE_TYPE) {
+ return !(o.uiMode & MASK_UI_MODE_TYPE);
+ }
+ if ((uiMode | o.uiMode) & MASK_UI_MODE_NIGHT) {
+ return !(o.uiMode & MASK_UI_MODE_NIGHT);
+ }
+ if (density || o.density) return (!o.density);
+ if (touchscreen || o.touchscreen) return (!o.touchscreen);
+ if ((inputFlags | o.inputFlags) & MASK_KEYSHIDDEN) {
+ return !(o.inputFlags & MASK_KEYSHIDDEN);
+ }
+ if ((inputFlags | o.inputFlags) & MASK_NAVHIDDEN) {
+ return !(o.inputFlags & MASK_NAVHIDDEN);
+ }
+ if (keyboard || o.keyboard) return (!o.keyboard);
+ if (navigation || o.navigation) return (!o.navigation);
+ if (screenWidth || o.screenWidth) return (!o.screenWidth);
+ if (screenHeight || o.screenHeight) return (!o.screenHeight);
+ if (sdkVersion || o.sdkVersion) return (!o.sdkVersion);
+ if (minorVersion || o.minorVersion) return (!o.minorVersion);
+ // Both configurations have nothing defined except some possible future
+ // value. Returning the comparison of the two configurations is a
+ // "best effort" at this point to protect against incorrect dominations.
+ return *this != o;
+}
+
+bool ConfigDescription::conflictsWith(const ConfigDescription& o) const {
+ // This method should be updated as new configuration parameters are
+ // introduced (e.g. screenConfig2).
+ auto pred = [](const uint32_t a, const uint32_t b) -> bool {
+ return a == 0 || b == 0 || a == b;
+ };
+ // The values here can be found in ResTable_config#match. Density and range
+ // values can't lead to conflicts, and are ignored.
+ return !pred(mcc, o.mcc)
+ || !pred(mnc, o.mnc)
+ || !pred(locale, o.locale)
+ || !pred(screenLayout & MASK_LAYOUTDIR, o.screenLayout & MASK_LAYOUTDIR)
+ || !pred(screenLayout & MASK_SCREENLONG, o.screenLayout & MASK_SCREENLONG)
+ || !pred(screenLayout & MASK_UI_MODE_TYPE, o.screenLayout & MASK_UI_MODE_TYPE)
+ || !pred(uiMode & MASK_UI_MODE_TYPE, o.uiMode & MASK_UI_MODE_TYPE)
+ || !pred(uiMode & MASK_UI_MODE_NIGHT, o.uiMode & MASK_UI_MODE_NIGHT)
+ || !pred(screenLayout2 & MASK_SCREENROUND, o.screenLayout2 & MASK_SCREENROUND)
+ || !pred(orientation, o.orientation)
+ || !pred(touchscreen, o.touchscreen)
+ || !pred(inputFlags & MASK_KEYSHIDDEN, o.inputFlags & MASK_KEYSHIDDEN)
+ || !pred(inputFlags & MASK_NAVHIDDEN, o.inputFlags & MASK_NAVHIDDEN)
+ || !pred(keyboard, o.keyboard)
+ || !pred(navigation, o.navigation);
+}
+
+bool ConfigDescription::isCompatibleWith(const ConfigDescription& o) const {
+ return !conflictsWith(o) && !dominates(o) && !o.dominates(*this);
+}
+
} // namespace aapt
diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h
index 6858c62..d801621 100644
--- a/tools/aapt2/ConfigDescription.h
+++ b/tools/aapt2/ConfigDescription.h
@@ -59,14 +59,50 @@
ConfigDescription& operator=(const ConfigDescription& o);
ConfigDescription& operator=(ConfigDescription&& o);
+ ConfigDescription copyWithoutSdkVersion() const;
+
+ /**
+ * A configuration X dominates another configuration Y, if X has at least the
+ * precedence of Y and X is strictly more general than Y: for any type defined
+ * by X, the same type is defined by Y with a value equal to or, in the case
+ * of ranges, more specific than that of X.
+ *
+ * For example, the configuration 'en-w800dp' dominates 'en-rGB-w1024dp'. It
+ * does not dominate 'fr', 'en-w720dp', or 'mcc001-en-w800dp'.
+ */
+ bool dominates(const ConfigDescription& o) const;
+
+ /**
+ * Returns true if this configuration defines a more important configuration
+ * parameter than o. For example, "en" has higher precedence than "v23",
+ * whereas "en" has the same precedence as "en-v23".
+ */
+ bool hasHigherPrecedenceThan(const ConfigDescription& o) const;
+
+ /**
+ * A configuration conflicts with another configuration if both
+ * configurations define an incompatible configuration parameter. An
+ * incompatible configuration parameter is a non-range, non-density parameter
+ * that is defined in both configurations as a different, non-default value.
+ */
+ bool conflictsWith(const ConfigDescription& o) const;
+
+ /**
+ * A configuration is compatible with another configuration if both
+ * configurations can match a common concrete device configuration and are
+ * unrelated by domination. For example, land-v11 conflicts with port-v21
+ * but is compatible with v21 (both land-v11 and v21 would match en-land-v23).
+ */
+ bool isCompatibleWith(const ConfigDescription& o) const;
+
+ bool matchWithDensity(const ConfigDescription& o) const;
+
bool operator<(const ConfigDescription& o) const;
bool operator<=(const ConfigDescription& o) const;
bool operator==(const ConfigDescription& o) const;
bool operator!=(const ConfigDescription& o) const;
bool operator>=(const ConfigDescription& o) const;
bool operator>(const ConfigDescription& o) const;
-
- ConfigDescription copyWithoutSdkVersion() const;
};
inline ConfigDescription::ConfigDescription() {
@@ -103,6 +139,10 @@
return *this;
}
+inline bool ConfigDescription::matchWithDensity(const ConfigDescription& o) const {
+ return match(o) && (density == 0 || density == o.density);
+}
+
inline bool ConfigDescription::operator<(const ConfigDescription& o) const {
return compare(o) < 0;
}
diff --git a/tools/aapt2/DominatorTree.cpp b/tools/aapt2/DominatorTree.cpp
new file mode 100644
index 0000000..29587a8
--- /dev/null
+++ b/tools/aapt2/DominatorTree.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConfigDescription.h"
+#include "DominatorTree.h"
+
+#include <algorithm>
+
+namespace aapt {
+
+DominatorTree::DominatorTree(
+ const std::vector<std::unique_ptr<ResourceConfigValue>>& configs) {
+ for (const auto& config : configs) {
+ mProductRoots[config->product].tryAddChild(
+ util::make_unique<Node>(config.get(), nullptr));
+ }
+}
+
+void DominatorTree::accept(Visitor* visitor) {
+ for (auto& entry : mProductRoots) {
+ visitor->visitTree(entry.first, &entry.second);
+ }
+}
+
+bool DominatorTree::Node::tryAddChild(std::unique_ptr<Node> newChild) {
+ assert(newChild->mValue && "cannot add a root or empty node as a child");
+ if (mValue && !dominates(newChild.get())) {
+ // This is not the root and the child dominates us.
+ return false;
+ }
+ return addChild(std::move(newChild));
+}
+
+bool DominatorTree::Node::addChild(std::unique_ptr<Node> newChild) {
+ bool hasDominatedChildren = false;
+ // Demote children dominated by the new config.
+ for (auto& child : mChildren) {
+ if (newChild->dominates(child.get())) {
+ child->mParent = newChild.get();
+ newChild->mChildren.push_back(std::move(child));
+ child = {};
+ hasDominatedChildren = true;
+ }
+ }
+ // Remove dominated children.
+ if (hasDominatedChildren) {
+ mChildren.erase(std::remove_if(mChildren.begin(), mChildren.end(),
+ [](const std::unique_ptr<Node>& child) -> bool {
+ return child == nullptr;
+ }), mChildren.end());
+ }
+ // Add the new config to a child if a child dominates the new config.
+ for (auto& child : mChildren) {
+ if (child->dominates(newChild.get())) {
+ child->addChild(std::move(newChild));
+ return true;
+ }
+ }
+ // The new config is not dominated by a child, so add it here.
+ newChild->mParent = this;
+ mChildren.push_back(std::move(newChild));
+ return true;
+}
+
+bool DominatorTree::Node::dominates(const Node* other) const {
+ // Check root node dominations.
+ if (other->isRootNode()) {
+ return isRootNode();
+ } else if (isRootNode()) {
+ return true;
+ }
+ // Neither node is a root node; compare the configurations.
+ return mValue->config.dominates(other->mValue->config);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/DominatorTree.h b/tools/aapt2/DominatorTree.h
new file mode 100644
index 0000000..ad2df0e
--- /dev/null
+++ b/tools/aapt2/DominatorTree.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_DOMINATOR_TREE_H
+#define AAPT_DOMINATOR_TREE_H
+
+#include "ResourceTable.h"
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+/**
+ * A dominator tree of configurations as defined by resolution rules for Android
+ * resources.
+ *
+ * A node in the tree represents a resource configuration.
+ *
+ * The tree has the following property:
+ *
+ * Each child of a given configuration defines a strict superset of qualifiers
+ * and has a value that is at least as specific as that of its ancestors. A
+ * value is "at least as specific" if it is either identical or it represents a
+ * stronger requirement.
+ * For example, v21 is more specific than v11, and w1200dp is more specific than
+ * w800dp.
+ *
+ * The dominator tree relies on the underlying configurations passed to it. If
+ * the configurations passed to the dominator tree go out of scope, the tree
+ * will exhibit undefined behavior.
+ */
+class DominatorTree {
+public:
+ explicit DominatorTree(const std::vector<std::unique_ptr<ResourceConfigValue>>& configs);
+
+ class Node {
+ public:
+ explicit Node(ResourceConfigValue* value = nullptr, Node* parent = nullptr) :
+ mValue(value), mParent(parent) {
+ }
+
+ inline ResourceConfigValue* value() const {
+ return mValue;
+ }
+
+ inline Node* parent() const {
+ return mParent;
+ }
+
+ inline bool isRootNode() const {
+ return !mValue;
+ }
+
+ inline const std::vector<std::unique_ptr<Node>>& children() const {
+ return mChildren;
+ }
+
+ bool tryAddChild(std::unique_ptr<Node> newChild);
+
+ private:
+ bool addChild(std::unique_ptr<Node> newChild);
+ bool dominates(const Node* other) const;
+
+ ResourceConfigValue* mValue;
+ Node* mParent;
+ std::vector<std::unique_ptr<Node>> mChildren;
+
+ DISALLOW_COPY_AND_ASSIGN(Node);
+ };
+
+ struct Visitor {
+ virtual ~Visitor() = default;
+ virtual void visitTree(const std::string& product, Node* root) = 0;
+ };
+
+ class BottomUpVisitor : public Visitor {
+ public:
+ virtual ~BottomUpVisitor() = default;
+
+ void visitTree(const std::string& product, Node* root) override {
+ for (auto& child : root->children()) {
+ visitNode(child.get());
+ }
+ }
+
+ virtual void visitConfig(Node* node) = 0;
+
+ private:
+ void visitNode(Node* node) {
+ for (auto& child : node->children()) {
+ visitNode(child.get());
+ }
+ visitConfig(node);
+ }
+ };
+
+ void accept(Visitor* visitor);
+
+ inline const std::map<std::string, Node>& getProductRoots() const {
+ return mProductRoots;
+ }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(DominatorTree);
+
+ std::map<std::string, Node> mProductRoots;
+};
+
+} // namespace aapt
+
+#endif // AAPT_DOMINATOR_TREE_H
diff --git a/tools/aapt2/DominatorTree_test.cpp b/tools/aapt2/DominatorTree_test.cpp
new file mode 100644
index 0000000..fb850e4da
--- /dev/null
+++ b/tools/aapt2/DominatorTree_test.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DominatorTree.h"
+#include "test/Test.h"
+#include "util/Util.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+namespace {
+
+class PrettyPrinter : public DominatorTree::Visitor {
+public:
+ explicit PrettyPrinter(const int indent = 2) : mIndent(indent) {
+ }
+
+ void visitTree(const std::string& product, DominatorTree::Node* root) override {
+ for (auto& child : root->children()) {
+ visitNode(child.get(), 0);
+ }
+ }
+
+ std::string toString(DominatorTree* tree) {
+ mBuffer.str("");
+ mBuffer.clear();
+ tree->accept(this);
+ return mBuffer.str();
+ }
+
+private:
+ void visitConfig(const DominatorTree::Node* node, const int indent) {
+ auto configString = node->value()->config.toString();
+ mBuffer << std::string(indent, ' ')
+ << (configString.isEmpty() ? "<default>" : configString)
+ << std::endl;
+ }
+
+ void visitNode(const DominatorTree::Node* node, const int indent) {
+ visitConfig(node, indent);
+ for (const auto& child : node->children()) {
+ visitNode(child.get(), indent + mIndent);
+ }
+ }
+
+ std::stringstream mBuffer;
+ const int mIndent = 2;
+};
+
+} // namespace
+
+TEST(DominatorTreeTest, DefaultDominatesEverything) {
+ const ConfigDescription defaultConfig = {};
+ const ConfigDescription landConfig = test::parseConfigOrDie("land");
+ const ConfigDescription sw600dpLandConfig = test::parseConfigOrDie("sw600dp-land-v13");
+
+ std::vector<std::unique_ptr<ResourceConfigValue>> configs;
+ configs.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(landConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(sw600dpLandConfig, ""));
+
+ DominatorTree tree(configs);
+ PrettyPrinter printer;
+
+ std::string expected =
+ "<default>\n"
+ " land\n"
+ " sw600dp-land-v13\n";
+ EXPECT_EQ(expected, printer.toString(&tree));
+}
+
+TEST(DominatorTreeTest, ProductsAreDominatedSeparately) {
+ const ConfigDescription defaultConfig = {};
+ const ConfigDescription landConfig = test::parseConfigOrDie("land");
+ const ConfigDescription sw600dpLandConfig = test::parseConfigOrDie("sw600dp-land-v13");
+
+ std::vector<std::unique_ptr<ResourceConfigValue>> configs;
+ configs.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(landConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, "phablet"));
+ configs.push_back(util::make_unique<ResourceConfigValue>(sw600dpLandConfig, "phablet"));
+
+ DominatorTree tree(configs);
+ PrettyPrinter printer;
+
+ std::string expected =
+ "<default>\n"
+ " land\n"
+ "<default>\n"
+ " sw600dp-land-v13\n";
+ EXPECT_EQ(expected, printer.toString(&tree));
+}
+
+TEST(DominatorTreeTest, MoreSpecificConfigurationsAreDominated) {
+ const ConfigDescription defaultConfig = {};
+ const ConfigDescription enConfig = test::parseConfigOrDie("en");
+ const ConfigDescription enV21Config = test::parseConfigOrDie("en-v21");
+ const ConfigDescription ldrtlConfig = test::parseConfigOrDie("ldrtl-v4");
+ const ConfigDescription ldrtlXhdpiConfig = test::parseConfigOrDie("ldrtl-xhdpi-v4");
+ const ConfigDescription sw300dpConfig = test::parseConfigOrDie("sw300dp-v13");
+ const ConfigDescription sw540dpConfig = test::parseConfigOrDie("sw540dp-v14");
+ const ConfigDescription sw600dpConfig = test::parseConfigOrDie("sw600dp-v14");
+ const ConfigDescription sw720dpConfig = test::parseConfigOrDie("sw720dp-v13");
+ const ConfigDescription v20Config = test::parseConfigOrDie("v20");
+
+ std::vector<std::unique_ptr<ResourceConfigValue>> configs;
+ configs.push_back(util::make_unique<ResourceConfigValue>(defaultConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(enConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(enV21Config, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(ldrtlConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(ldrtlXhdpiConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(sw300dpConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(sw540dpConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(sw600dpConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(sw720dpConfig, ""));
+ configs.push_back(util::make_unique<ResourceConfigValue>(v20Config, ""));
+
+ DominatorTree tree(configs);
+ PrettyPrinter printer;
+
+ std::string expected =
+ "<default>\n"
+ " en\n"
+ " en-v21\n"
+ " ldrtl-v4\n"
+ " ldrtl-xhdpi-v4\n"
+ " sw300dp-v13\n"
+ " sw540dp-v14\n"
+ " sw600dp-v14\n"
+ " sw720dp-v13\n"
+ " v20\n";
+ EXPECT_EQ(expected, printer.toString(&tree));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp
index e0f37ec..dbd8062 100644
--- a/tools/aapt2/compile/Compile.cpp
+++ b/tools/aapt2/compile/Compile.cpp
@@ -36,6 +36,8 @@
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
#include <google/protobuf/io/coded_stream.h>
+#include <android-base/errors.h>
+#include <android-base/file.h>
#include <dirent.h>
#include <fstream>
#include <string>
@@ -359,6 +361,9 @@
static bool compileXml(IAaptContext* context, const CompileOptions& options,
const ResourcePathData& pathData, IArchiveWriter* writer,
const std::string& outputPath) {
+ if (context->verbose()) {
+ context->getDiagnostics()->note(DiagMessage(pathData.source) << "compiling XML");
+ }
std::unique_ptr<xml::XmlResource> xmlRes;
{
@@ -431,9 +436,43 @@
return true;
}
+class BigBufferOutputStream : public io::OutputStream {
+public:
+ explicit BigBufferOutputStream(BigBuffer* buffer) : mBuffer(buffer) {
+ }
+
+ bool Next(void** data, int* len) override {
+ size_t count;
+ *data = mBuffer->nextBlock(&count);
+ *len = static_cast<int>(count);
+ return true;
+ }
+
+ void BackUp(int count) override {
+ mBuffer->backUp(count);
+ }
+
+ int64_t ByteCount() const override {
+ return mBuffer->size();
+ }
+
+ bool HadError() const override {
+ return false;
+ }
+
+private:
+ BigBuffer* mBuffer;
+
+ DISALLOW_COPY_AND_ASSIGN(BigBufferOutputStream);
+};
+
static bool compilePng(IAaptContext* context, const CompileOptions& options,
const ResourcePathData& pathData, IArchiveWriter* writer,
const std::string& outputPath) {
+ if (context->verbose()) {
+ context->getDiagnostics()->note(DiagMessage(pathData.source) << "compiling PNG");
+ }
+
BigBuffer buffer(4096);
ResourceFile resFile;
resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name);
@@ -441,16 +480,90 @@
resFile.source = pathData.source;
{
- std::ifstream fin(pathData.source.path, std::ifstream::binary);
- if (!fin) {
- context->getDiagnostics()->error(DiagMessage(pathData.source) << strerror(errno));
+ std::string content;
+ if (!android::base::ReadFileToString(pathData.source.path, &content)) {
+ context->getDiagnostics()->error(DiagMessage(pathData.source)
+ << android::base::SystemErrorCodeToString(errno));
return false;
}
- Png png(context->getDiagnostics());
- if (!png.process(pathData.source, &fin, &buffer, {})) {
+ BigBuffer crunchedPngBuffer(4096);
+ BigBufferOutputStream crunchedPngBufferOut(&crunchedPngBuffer);
+
+ // Ensure that we only keep the chunks we care about if we end up
+ // using the original PNG instead of the crunched one.
+ PngChunkFilter pngChunkFilter(content);
+ std::unique_ptr<Image> image = readPng(context, &pngChunkFilter);
+ if (!image) {
return false;
}
+
+ std::unique_ptr<NinePatch> ninePatch;
+ if (pathData.extension == "9.png") {
+ std::string err;
+ ninePatch = NinePatch::create(image->rows.get(), image->width, image->height, &err);
+ if (!ninePatch) {
+ context->getDiagnostics()->error(DiagMessage() << err);
+ return false;
+ }
+
+ // Remove the 1px border around the NinePatch.
+ // Basically the row array is shifted up by 1, and the length is treated
+ // as height - 2.
+ // For each row, shift the array to the left by 1, and treat the length as width - 2.
+ image->width -= 2;
+ image->height -= 2;
+ memmove(image->rows.get(), image->rows.get() + 1, image->height * sizeof(uint8_t**));
+ for (int32_t h = 0; h < image->height; h++) {
+ memmove(image->rows[h], image->rows[h] + 4, image->width * 4);
+ }
+
+ if (context->verbose()) {
+ context->getDiagnostics()->note(DiagMessage(pathData.source)
+ << "9-patch: " << *ninePatch);
+ }
+ }
+
+ // Write the crunched PNG.
+ if (!writePng(context, image.get(), ninePatch.get(), &crunchedPngBufferOut, {})) {
+ return false;
+ }
+
+ if (ninePatch != nullptr
+ || crunchedPngBufferOut.ByteCount() <= pngChunkFilter.ByteCount()) {
+ // No matter what, we must use the re-encoded PNG, even if it is larger.
+ // 9-patch images must be re-encoded since their borders are stripped.
+ buffer.appendBuffer(std::move(crunchedPngBuffer));
+ } else {
+ // The re-encoded PNG is larger than the original, and there is
+ // no mandatory transformation. Use the original.
+ if (context->verbose()) {
+ context->getDiagnostics()->note(DiagMessage(pathData.source)
+ << "original PNG is smaller than crunched PNG"
+ << ", using original");
+ }
+
+ PngChunkFilter pngChunkFilterAgain(content);
+ BigBuffer filteredPngBuffer(4096);
+ BigBufferOutputStream filteredPngBufferOut(&filteredPngBuffer);
+ io::copy(&filteredPngBufferOut, &pngChunkFilterAgain);
+ buffer.appendBuffer(std::move(filteredPngBuffer));
+ }
+
+ if (context->verbose()) {
+ // For debugging only, use the legacy PNG cruncher and compare the resulting file sizes.
+ // This will help catch exotic cases where the new code may generate larger PNGs.
+ std::stringstream legacyStream(content);
+ BigBuffer legacyBuffer(4096);
+ Png png(context->getDiagnostics());
+ if (!png.process(pathData.source, &legacyStream, &legacyBuffer, {})) {
+ return false;
+ }
+
+ context->getDiagnostics()->note(DiagMessage(pathData.source)
+ << "legacy=" << legacyBuffer.size()
+ << " new=" << buffer.size());
+ }
}
if (!writeHeaderAndBufferToWriter(outputPath, resFile, buffer, writer,
@@ -463,6 +576,10 @@
static bool compileFile(IAaptContext* context, const CompileOptions& options,
const ResourcePathData& pathData, IArchiveWriter* writer,
const std::string& outputPath) {
+ if (context->verbose()) {
+ context->getDiagnostics()->note(DiagMessage(pathData.source) << "compiling file");
+ }
+
BigBuffer buffer(256);
ResourceFile resFile;
resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name);
diff --git a/tools/aapt2/compile/Image.h b/tools/aapt2/compile/Image.h
new file mode 100644
index 0000000..fda6a3a
--- /dev/null
+++ b/tools/aapt2/compile/Image.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_COMPILE_IMAGE_H
+#define AAPT_COMPILE_IMAGE_H
+
+#include <android-base/macros.h>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+/**
+ * An in-memory image, loaded from disk, with pixels in RGBA_8888 format.
+ */
+class Image {
+public:
+ explicit Image() = default;
+
+ /**
+ * A `height` sized array of pointers, where each element points to a
+ * `width` sized row of RGBA_8888 pixels.
+ */
+ std::unique_ptr<uint8_t*[]> rows;
+
+ /**
+ * The width of the image in RGBA_8888 pixels. This is int32_t because of 9-patch data
+ * format limitations.
+ */
+ int32_t width = 0;
+
+ /**
+ * The height of the image in RGBA_8888 pixels. This is int32_t because of 9-patch data
+ * format limitations.
+ */
+ int32_t height = 0;
+
+ /**
+ * Buffer to the raw image data stored sequentially.
+ * Use `rows` to access the data on a row-by-row basis.
+ */
+ std::unique_ptr<uint8_t[]> data;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(Image);
+};
+
+/**
+ * A range of pixel values, starting at 'start' and ending before 'end' exclusive. Or rather [a, b).
+ */
+struct Range {
+ int32_t start = 0;
+ int32_t end = 0;
+
+ explicit Range() = default;
+ inline explicit Range(int32_t s, int32_t e) : start(s), end(e) {
+ }
+};
+
+inline bool operator==(const Range& left, const Range& right) {
+ return left.start == right.start && left.end == right.end;
+}
+
+/**
+ * Inset lengths from all edges of a rectangle. `left` and `top` are measured from the left and top
+ * edges, while `right` and `bottom` are measured from the right and bottom edges, respectively.
+ */
+struct Bounds {
+ int32_t left = 0;
+ int32_t top = 0;
+ int32_t right = 0;
+ int32_t bottom = 0;
+
+ explicit Bounds() = default;
+ inline explicit Bounds(int32_t l, int32_t t, int32_t r, int32_t b) :
+ left(l), top(t), right(r), bottom(b) {
+ }
+
+ bool nonZero() const;
+};
+
+inline bool Bounds::nonZero() const {
+ return left != 0 || top != 0 || right != 0 || bottom != 0;
+}
+
+inline bool operator==(const Bounds& left, const Bounds& right) {
+ return left.left == right.left && left.top == right.top &&
+ left.right == right.right && left.bottom == right.bottom;
+}
+
+/**
+ * Contains 9-patch data from a source image. All measurements exclude the 1px border of the
+ * source 9-patch image.
+ */
+class NinePatch {
+public:
+ static std::unique_ptr<NinePatch> create(uint8_t** rows,
+ const int32_t width, const int32_t height,
+ std::string* errOut);
+
+ /**
+ * Packs the RGBA_8888 data pointed to by pixel into a uint32_t
+ * with format 0xAARRGGBB (the way 9-patch expects it).
+ */
+ static uint32_t packRGBA(const uint8_t* pixel);
+
+ /**
+ * 9-patch content padding/insets. All positions are relative to the 9-patch
+ * NOT including the 1px thick source border.
+ */
+ Bounds padding;
+
+ /**
+ * Optical layout bounds/insets. This overrides the padding for
+ * layout purposes. All positions are relative to the 9-patch
+ * NOT including the 1px thick source border.
+ * See https://developer.android.com/about/versions/android-4.3.html#OpticalBounds
+ */
+ Bounds layoutBounds;
+
+ /**
+ * Outline of the image, calculated based on opacity.
+ */
+ Bounds outline;
+
+ /**
+ * The computed radius of the outline. If non-zero, the outline is a rounded-rect.
+ */
+ float outlineRadius = 0.0f;
+
+ /**
+ * The largest alpha value within the outline.
+ */
+ uint32_t outlineAlpha = 0x000000ffu;
+
+ /**
+ * Horizontal regions of the image that are stretchable.
+ * All positions are relative to the 9-patch
+ * NOT including the 1px thick source border.
+ */
+ std::vector<Range> horizontalStretchRegions;
+
+ /**
+ * Vertical regions of the image that are stretchable.
+ * All positions are relative to the 9-patch
+ * NOT including the 1px thick source border.
+ */
+ std::vector<Range> verticalStretchRegions;
+
+ /**
+ * The colors within each region, fixed or stretchable.
+ * For w*h regions, the color of region (x,y) is addressable
+ * via index y*w + x.
+ */
+ std::vector<uint32_t> regionColors;
+
+ /**
+ * Returns serialized data containing the original basic 9-patch meta data.
+ * Optical layout bounds and round rect outline data must be serialized
+ * separately using serializeOpticalLayoutBounds() and serializeRoundedRectOutline().
+ */
+ std::unique_ptr<uint8_t[]> serializeBase(size_t* outLen) const;
+
+ /**
+ * Serializes the layout bounds.
+ */
+ std::unique_ptr<uint8_t[]> serializeLayoutBounds(size_t* outLen) const;
+
+ /**
+ * Serializes the rounded-rect outline.
+ */
+ std::unique_ptr<uint8_t[]> serializeRoundedRectOutline(size_t* outLen) const;
+
+private:
+ explicit NinePatch() = default;
+
+ DISALLOW_COPY_AND_ASSIGN(NinePatch);
+};
+
+::std::ostream& operator<<(::std::ostream& out, const Range& range);
+::std::ostream& operator<<(::std::ostream& out, const Bounds& bounds);
+::std::ostream& operator<<(::std::ostream& out, const NinePatch& ninePatch);
+
+} // namespace aapt
+
+#endif /* AAPT_COMPILE_IMAGE_H */
diff --git a/tools/aapt2/compile/NinePatch.cpp b/tools/aapt2/compile/NinePatch.cpp
new file mode 100644
index 0000000..0fc1c5d
--- /dev/null
+++ b/tools/aapt2/compile/NinePatch.cpp
@@ -0,0 +1,676 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compile/Image.h"
+#include "util/StringPiece.h"
+#include "util/Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+// Colors in the format 0xAARRGGBB (the way 9-patch expects it).
+constexpr static const uint32_t kColorOpaqueWhite = 0xffffffffu;
+constexpr static const uint32_t kColorOpaqueBlack = 0xff000000u;
+constexpr static const uint32_t kColorOpaqueRed = 0xffff0000u;
+
+constexpr static const uint32_t kPrimaryColor = kColorOpaqueBlack;
+constexpr static const uint32_t kSecondaryColor = kColorOpaqueRed;
+
+/**
+ * Returns the alpha value encoded in the 0xAARRGBB encoded pixel.
+ */
+static uint32_t getAlpha(uint32_t color);
+
+/**
+ * Determines whether a color on an ImageLine is valid.
+ * A 9patch image may use a transparent color as neutral,
+ * or a fully opaque white color as neutral, based on the
+ * pixel color at (0,0) of the image. One or the other is fine,
+ * but we need to ensure consistency throughout the image.
+ */
+class ColorValidator {
+public:
+ virtual ~ColorValidator() = default;
+
+ /**
+ * Returns true if the color specified is a neutral color
+ * (no padding, stretching, or optical bounds).
+ */
+ virtual bool isNeutralColor(uint32_t color) const = 0;
+
+ /**
+ * Returns true if the color is either a neutral color
+ * or one denoting padding, stretching, or optical bounds.
+ */
+ bool isValidColor(uint32_t color) const {
+ switch (color) {
+ case kPrimaryColor:
+ case kSecondaryColor:
+ return true;
+ }
+ return isNeutralColor(color);
+ }
+};
+
+// Walks an ImageLine and records Ranges of primary and secondary colors.
+// The primary color is black and is used to denote a padding or stretching range,
+// depending on which border we're iterating over.
+// The secondary color is red and is used to denote optical bounds.
+//
+// An ImageLine is a templated-interface that would look something like this if it
+// were polymorphic:
+//
+// class ImageLine {
+// public:
+// virtual int32_t getLength() const = 0;
+// virtual uint32_t getColor(int32_t idx) const = 0;
+// };
+//
+template <typename ImageLine>
+static bool fillRanges(const ImageLine* imageLine,
+ const ColorValidator* colorValidator,
+ std::vector<Range>* primaryRanges,
+ std::vector<Range>* secondaryRanges,
+ std::string* err) {
+ const int32_t length = imageLine->getLength();
+
+ uint32_t lastColor = 0xffffffffu;
+ for (int32_t idx = 1; idx < length - 1; idx++) {
+ const uint32_t color = imageLine->getColor(idx);
+ if (!colorValidator->isValidColor(color)) {
+ *err = "found an invalid color";
+ return false;
+ }
+
+ if (color != lastColor) {
+ // We are ending a range. Which range?
+ // note: encode the x offset without the final 1 pixel border.
+ if (lastColor == kPrimaryColor) {
+ primaryRanges->back().end = idx - 1;
+ } else if (lastColor == kSecondaryColor) {
+ secondaryRanges->back().end = idx - 1;
+ }
+
+ // We are starting a range. Which range?
+ // note: encode the x offset without the final 1 pixel border.
+ if (color == kPrimaryColor) {
+ primaryRanges->push_back(Range(idx - 1, length - 2));
+ } else if (color == kSecondaryColor) {
+ secondaryRanges->push_back(Range(idx - 1, length - 2));
+ }
+ lastColor = color;
+ }
+ }
+ return true;
+}
+
+/**
+ * Iterates over a row in an image. Implements the templated ImageLine interface.
+ */
+class HorizontalImageLine {
+public:
+ explicit HorizontalImageLine(uint8_t** rows, int32_t xOffset, int32_t yOffset,
+ int32_t length) :
+ mRows(rows), mXOffset(xOffset), mYOffset(yOffset), mLength(length) {
+ }
+
+ inline int32_t getLength() const {
+ return mLength;
+ }
+
+ inline uint32_t getColor(int32_t idx) const {
+ return NinePatch::packRGBA(mRows[mYOffset] + (idx + mXOffset) * 4);
+ }
+
+private:
+ uint8_t** mRows;
+ int32_t mXOffset, mYOffset, mLength;
+
+ DISALLOW_COPY_AND_ASSIGN(HorizontalImageLine);
+};
+
+/**
+ * Iterates over a column in an image. Implements the templated ImageLine interface.
+ */
+class VerticalImageLine {
+public:
+ explicit VerticalImageLine(uint8_t** rows, int32_t xOffset, int32_t yOffset,
+ int32_t length) :
+ mRows(rows), mXOffset(xOffset), mYOffset(yOffset), mLength(length) {
+ }
+
+ inline int32_t getLength() const {
+ return mLength;
+ }
+
+ inline uint32_t getColor(int32_t idx) const {
+ return NinePatch::packRGBA(mRows[mYOffset + idx] + (mXOffset * 4));
+ }
+
+private:
+ uint8_t** mRows;
+ int32_t mXOffset, mYOffset, mLength;
+
+ DISALLOW_COPY_AND_ASSIGN(VerticalImageLine);
+};
+
+class DiagonalImageLine {
+public:
+ explicit DiagonalImageLine(uint8_t** rows, int32_t xOffset, int32_t yOffset,
+ int32_t xStep, int32_t yStep, int32_t length) :
+ mRows(rows), mXOffset(xOffset), mYOffset(yOffset), mXStep(xStep), mYStep(yStep),
+ mLength(length) {
+ }
+
+ inline int32_t getLength() const {
+ return mLength;
+ }
+
+ inline uint32_t getColor(int32_t idx) const {
+ return NinePatch::packRGBA(
+ mRows[mYOffset + (idx * mYStep)] + ((idx + mXOffset) * mXStep) * 4);
+ }
+
+private:
+ uint8_t** mRows;
+ int32_t mXOffset, mYOffset, mXStep, mYStep, mLength;
+
+ DISALLOW_COPY_AND_ASSIGN(DiagonalImageLine);
+};
+
+class TransparentNeutralColorValidator : public ColorValidator {
+public:
+ bool isNeutralColor(uint32_t color) const override {
+ return getAlpha(color) == 0;
+ }
+};
+
+class WhiteNeutralColorValidator : public ColorValidator {
+public:
+ bool isNeutralColor(uint32_t color) const override {
+ return color == kColorOpaqueWhite;
+ }
+};
+
+inline static uint32_t getAlpha(uint32_t color) {
+ return (color & 0xff000000u) >> 24;
+}
+
+static bool populateBounds(const std::vector<Range>& padding,
+ const std::vector<Range>& layoutBounds,
+ const std::vector<Range>& stretchRegions,
+ const int32_t length,
+ int32_t* paddingStart, int32_t* paddingEnd,
+ int32_t* layoutStart, int32_t* layoutEnd,
+ const StringPiece& edgeName,
+ std::string* err) {
+ if (padding.size() > 1) {
+ std::stringstream errStream;
+ errStream << "too many padding sections on " << edgeName << " border";
+ *err = errStream.str();
+ return false;
+ }
+
+ *paddingStart = 0;
+ *paddingEnd = 0;
+ if (!padding.empty()) {
+ const Range& range = padding.front();
+ *paddingStart = range.start;
+ *paddingEnd = length - range.end;
+ } else if (!stretchRegions.empty()) {
+ // No padding was defined. Compute the padding from the first and last
+ // stretch regions.
+ *paddingStart = stretchRegions.front().start;
+ *paddingEnd = length - stretchRegions.back().end;
+ }
+
+ if (layoutBounds.size() > 2) {
+ std::stringstream errStream;
+ errStream << "too many layout bounds sections on " << edgeName << " border";
+ *err = errStream.str();
+ return false;
+ }
+
+ *layoutStart = 0;
+ *layoutEnd = 0;
+ if (layoutBounds.size() >= 1) {
+ const Range& range = layoutBounds.front();
+ // If there is only one layout bound segment, it might not start at 0, but then it should
+ // end at length.
+ if (range.start != 0 && range.end != length) {
+ std::stringstream errStream;
+ errStream << "layout bounds on " << edgeName << " border must start at edge";
+ *err = errStream.str();
+ return false;
+ }
+ *layoutStart = range.end;
+
+ if (layoutBounds.size() >= 2) {
+ const Range& range = layoutBounds.back();
+ if (range.end != length) {
+ std::stringstream errStream;
+ errStream << "layout bounds on " << edgeName << " border must start at edge";
+ *err = errStream.str();
+ return false;
+ }
+ *layoutEnd = length - range.start;
+ }
+ }
+ return true;
+}
+
+static int32_t calculateSegmentCount(const std::vector<Range>& stretchRegions, int32_t length) {
+ if (stretchRegions.size() == 0) {
+ return 0;
+ }
+
+ const bool startIsFixed = stretchRegions.front().start != 0;
+ const bool endIsFixed = stretchRegions.back().end != length;
+ int32_t modifier = 0;
+ if (startIsFixed && endIsFixed) {
+ modifier = 1;
+ } else if (!startIsFixed && !endIsFixed) {
+ modifier = -1;
+ }
+ return static_cast<int32_t>(stretchRegions.size()) * 2 + modifier;
+}
+
+static uint32_t getRegionColor(uint8_t** rows, const Bounds& region) {
+ // Sample the first pixel to compare against.
+ const uint32_t expectedColor = NinePatch::packRGBA(rows[region.top] + region.left * 4);
+ for (int32_t y = region.top; y < region.bottom; y++) {
+ const uint8_t* row = rows[y];
+ for (int32_t x = region.left; x < region.right; x++) {
+ const uint32_t color = NinePatch::packRGBA(row + x * 4);
+ if (getAlpha(color) == 0) {
+ // The color is transparent.
+ // If the expectedColor is not transparent, NO_COLOR.
+ if (getAlpha(expectedColor) != 0) {
+ return android::Res_png_9patch::NO_COLOR;
+ }
+ } else if (color != expectedColor) {
+ return android::Res_png_9patch::NO_COLOR;
+ }
+ }
+ }
+
+ if (getAlpha(expectedColor) == 0) {
+ return android::Res_png_9patch::TRANSPARENT_COLOR;
+ }
+ return expectedColor;
+}
+
+// Fills outColors with each 9-patch section's colour. If the whole section is transparent,
+// it gets the special TRANSPARENT colour. If the whole section is the same colour, it is assigned
+// that colour. Otherwise it gets the special NO_COLOR colour.
+//
+// Note that the rows contain the 9-patch 1px border, and the indices in the stretch regions are
+// already offset to exclude the border. This means that each time the rows are accessed,
+// the indices must be offset by 1.
+//
+// width and height also include the 9-patch 1px border.
+static void calculateRegionColors(uint8_t** rows,
+ const std::vector<Range>& horizontalStretchRegions,
+ const std::vector<Range>& verticalStretchRegions,
+ const int32_t width, const int32_t height,
+ std::vector<uint32_t>* outColors) {
+ int32_t nextTop = 0;
+ Bounds bounds;
+ auto rowIter = verticalStretchRegions.begin();
+ while (nextTop != height) {
+ if (rowIter != verticalStretchRegions.end()) {
+ if (nextTop != rowIter->start) {
+ // This is a fixed segment.
+ // Offset the bounds by 1 to accommodate the border.
+ bounds.top = nextTop + 1;
+ bounds.bottom = rowIter->start + 1;
+ nextTop = rowIter->start;
+ } else {
+ // This is a stretchy segment.
+ // Offset the bounds by 1 to accommodate the border.
+ bounds.top = rowIter->start + 1;
+ bounds.bottom = rowIter->end + 1;
+ nextTop = rowIter->end;
+ ++rowIter;
+ }
+ } else {
+ // This is the end, fixed section.
+ // Offset the bounds by 1 to accommodate the border.
+ bounds.top = nextTop + 1;
+ bounds.bottom = height + 1;
+ nextTop = height;
+ }
+
+ int32_t nextLeft = 0;
+ auto colIter = horizontalStretchRegions.begin();
+ while (nextLeft != width) {
+ if (colIter != horizontalStretchRegions.end()) {
+ if (nextLeft != colIter->start) {
+ // This is a fixed segment.
+ // Offset the bounds by 1 to accommodate the border.
+ bounds.left = nextLeft + 1;
+ bounds.right = colIter->start + 1;
+ nextLeft = colIter->start;
+ } else {
+ // This is a stretchy segment.
+ // Offset the bounds by 1 to accommodate the border.
+ bounds.left = colIter->start + 1;
+ bounds.right = colIter->end + 1;
+ nextLeft = colIter->end;
+ ++colIter;
+ }
+ } else {
+ // This is the end, fixed section.
+ // Offset the bounds by 1 to accommodate the border.
+ bounds.left = nextLeft + 1;
+ bounds.right = width + 1;
+ nextLeft = width;
+ }
+ outColors->push_back(getRegionColor(rows, bounds));
+ }
+ }
+}
+
+// Calculates the insets of a row/column of pixels based on where the largest alpha value begins
+// (on both sides).
+template <typename ImageLine>
+static void findOutlineInsets(const ImageLine* imageLine, int32_t* outStart, int32_t* outEnd) {
+ *outStart = 0;
+ *outEnd = 0;
+
+ const int32_t length = imageLine->getLength();
+ if (length < 3) {
+ return;
+ }
+
+ // If the length is odd, we want both sides to process the center pixel,
+ // so we use two different midpoints (to account for < and <= in the different loops).
+ const int32_t mid2 = length / 2;
+ const int32_t mid1 = mid2 + (length % 2);
+
+ uint32_t maxAlpha = 0;
+ for (int32_t i = 0; i < mid1 && maxAlpha != 0xff; i++) {
+ uint32_t alpha = getAlpha(imageLine->getColor(i));
+ if (alpha > maxAlpha) {
+ maxAlpha = alpha;
+ *outStart = i;
+ }
+ }
+
+ maxAlpha = 0;
+ for (int32_t i = length - 1; i >= mid2 && maxAlpha != 0xff; i--) {
+ uint32_t alpha = getAlpha(imageLine->getColor(i));
+ if (alpha > maxAlpha) {
+ maxAlpha = alpha;
+ *outEnd = length - (i + 1);
+ }
+ }
+ return;
+}
+
+template <typename ImageLine>
+static uint32_t findMaxAlpha(const ImageLine* imageLine) {
+ const int32_t length = imageLine->getLength();
+ uint32_t maxAlpha = 0;
+ for (int32_t idx = 0; idx < length && maxAlpha != 0xff; idx++) {
+ uint32_t alpha = getAlpha(imageLine->getColor(idx));
+ if (alpha > maxAlpha) {
+ maxAlpha = alpha;
+ }
+ }
+ return maxAlpha;
+}
+
+// Pack the pixels in as 0xAARRGGBB (as 9-patch expects it).
+uint32_t NinePatch::packRGBA(const uint8_t* pixel) {
+ return (pixel[3] << 24) | (pixel[0] << 16) | (pixel[1] << 8) | pixel[2];
+}
+
+std::unique_ptr<NinePatch> NinePatch::create(uint8_t** rows,
+ const int32_t width, const int32_t height,
+ std::string* err) {
+ if (width < 3 || height < 3) {
+ *err = "image must be at least 3x3 (1x1 image with 1 pixel border)";
+ return {};
+ }
+
+ std::vector<Range> horizontalPadding;
+ std::vector<Range> horizontalOpticalBounds;
+ std::vector<Range> verticalPadding;
+ std::vector<Range> verticalOpticalBounds;
+ std::vector<Range> unexpectedRanges;
+ std::unique_ptr<ColorValidator> colorValidator;
+
+ if (rows[0][3] == 0) {
+ colorValidator = util::make_unique<TransparentNeutralColorValidator>();
+ } else if (packRGBA(rows[0]) == kColorOpaqueWhite) {
+ colorValidator = util::make_unique<WhiteNeutralColorValidator>();
+ } else {
+ *err = "top-left corner pixel must be either opaque white or transparent";
+ return {};
+ }
+
+ // Private constructor, can't use make_unique.
+ auto ninePatch = std::unique_ptr<NinePatch>(new NinePatch());
+
+ HorizontalImageLine topRow(rows, 0, 0, width);
+ if (!fillRanges(&topRow, colorValidator.get(), &ninePatch->horizontalStretchRegions,
+ &unexpectedRanges, err)) {
+ return {};
+ }
+
+ if (!unexpectedRanges.empty()) {
+ const Range& range = unexpectedRanges[0];
+ std::stringstream errStream;
+ errStream << "found unexpected optical bounds (red pixel) on top border "
+ << "at x=" << range.start + 1;
+ *err = errStream.str();
+ return {};
+ }
+
+ VerticalImageLine leftCol(rows, 0, 0, height);
+ if (!fillRanges(&leftCol, colorValidator.get(), &ninePatch->verticalStretchRegions,
+ &unexpectedRanges, err)) {
+ return {};
+ }
+
+ if (!unexpectedRanges.empty()) {
+ const Range& range = unexpectedRanges[0];
+ std::stringstream errStream;
+ errStream << "found unexpected optical bounds (red pixel) on left border "
+ << "at y=" << range.start + 1;
+ return {};
+ }
+
+ HorizontalImageLine bottomRow(rows, 0, height - 1, width);
+ if (!fillRanges(&bottomRow, colorValidator.get(), &horizontalPadding,
+ &horizontalOpticalBounds, err)) {
+ return {};
+ }
+
+ if (!populateBounds(horizontalPadding, horizontalOpticalBounds,
+ ninePatch->horizontalStretchRegions, width - 2,
+ &ninePatch->padding.left, &ninePatch->padding.right,
+ &ninePatch->layoutBounds.left, &ninePatch->layoutBounds.right,
+ "bottom", err)) {
+ return {};
+ }
+
+ VerticalImageLine rightCol(rows, width - 1, 0, height);
+ if (!fillRanges(&rightCol, colorValidator.get(), &verticalPadding,
+ &verticalOpticalBounds, err)) {
+ return {};
+ }
+
+ if (!populateBounds(verticalPadding, verticalOpticalBounds,
+ ninePatch->verticalStretchRegions, height - 2,
+ &ninePatch->padding.top, &ninePatch->padding.bottom,
+ &ninePatch->layoutBounds.top, &ninePatch->layoutBounds.bottom,
+ "right", err)) {
+ return {};
+ }
+
+ // Fill the region colors of the 9-patch.
+ const int32_t numRows = calculateSegmentCount(ninePatch->horizontalStretchRegions, width - 2);
+ const int32_t numCols = calculateSegmentCount(ninePatch->verticalStretchRegions, height - 2);
+ if ((int64_t) numRows * (int64_t) numCols > 0x7f) {
+ *err = "too many regions in 9-patch";
+ return {};
+ }
+
+ ninePatch->regionColors.reserve(numRows * numCols);
+ calculateRegionColors(rows, ninePatch->horizontalStretchRegions,
+ ninePatch->verticalStretchRegions,
+ width - 2, height - 2,
+ &ninePatch->regionColors);
+
+ // Compute the outline based on opacity.
+
+ // Find left and right extent of 9-patch content on center row.
+ HorizontalImageLine midRow(rows, 1, height / 2, width - 2);
+ findOutlineInsets(&midRow, &ninePatch->outline.left, &ninePatch->outline.right);
+
+ // Find top and bottom extent of 9-patch content on center column.
+ VerticalImageLine midCol(rows, width / 2, 1, height - 2);
+ findOutlineInsets(&midCol, &ninePatch->outline.top, &ninePatch->outline.bottom);
+
+ const int32_t outlineWidth = (width - 2) - ninePatch->outline.left - ninePatch->outline.right;
+ const int32_t outlineHeight = (height - 2) - ninePatch->outline.top - ninePatch->outline.bottom;
+
+ // Find the largest alpha value within the outline area.
+ HorizontalImageLine outlineMidRow(rows,
+ 1 + ninePatch->outline.left,
+ 1 + ninePatch->outline.top + (outlineHeight / 2),
+ outlineWidth);
+ VerticalImageLine outlineMidCol(rows,
+ 1 + ninePatch->outline.left + (outlineWidth / 2),
+ 1 + ninePatch->outline.top,
+ outlineHeight);
+ ninePatch->outlineAlpha = std::max(findMaxAlpha(&outlineMidRow), findMaxAlpha(&outlineMidCol));
+
+ // Assuming the image is a round rect, compute the radius by marching
+ // diagonally from the top left corner towards the center.
+ DiagonalImageLine diagonal(rows, 1 + ninePatch->outline.left, 1 + ninePatch->outline.top,
+ 1, 1, std::min(outlineWidth, outlineHeight));
+ int32_t topLeft, bottomRight;
+ findOutlineInsets(&diagonal, &topLeft, &bottomRight);
+
+ /* Determine source radius based upon inset:
+ * sqrt(r^2 + r^2) = sqrt(i^2 + i^2) + r
+ * sqrt(2) * r = sqrt(2) * i + r
+ * (sqrt(2) - 1) * r = sqrt(2) * i
+ * r = sqrt(2) / (sqrt(2) - 1) * i
+ */
+ ninePatch->outlineRadius = 3.4142f * topLeft;
+ return ninePatch;
+}
+
+std::unique_ptr<uint8_t[]> NinePatch::serializeBase(size_t* outLen) const {
+ android::Res_png_9patch data;
+ data.numXDivs = static_cast<uint8_t>(horizontalStretchRegions.size()) * 2;
+ data.numYDivs = static_cast<uint8_t>(verticalStretchRegions.size()) * 2;
+ data.numColors = static_cast<uint8_t>(regionColors.size());
+ data.paddingLeft = padding.left;
+ data.paddingRight = padding.right;
+ data.paddingTop = padding.top;
+ data.paddingBottom = padding.bottom;
+
+ auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[data.serializedSize()]);
+ android::Res_png_9patch::serialize(data,
+ (const int32_t*) horizontalStretchRegions.data(),
+ (const int32_t*) verticalStretchRegions.data(),
+ regionColors.data(),
+ buffer.get());
+ // Convert to file endianness.
+ reinterpret_cast<android::Res_png_9patch*>(buffer.get())->deviceToFile();
+
+ *outLen = data.serializedSize();
+ return buffer;
+}
+
+std::unique_ptr<uint8_t[]> NinePatch::serializeLayoutBounds(size_t* outLen) const {
+ size_t chunkLen = sizeof(uint32_t) * 4;
+ auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[chunkLen]);
+ uint8_t* cursor = buffer.get();
+
+ memcpy(cursor, &layoutBounds.left, sizeof(layoutBounds.left));
+ cursor += sizeof(layoutBounds.left);
+
+ memcpy(cursor, &layoutBounds.top, sizeof(layoutBounds.top));
+ cursor += sizeof(layoutBounds.top);
+
+ memcpy(cursor, &layoutBounds.right, sizeof(layoutBounds.right));
+ cursor += sizeof(layoutBounds.right);
+
+ memcpy(cursor, &layoutBounds.bottom, sizeof(layoutBounds.bottom));
+ cursor += sizeof(layoutBounds.bottom);
+
+ *outLen = chunkLen;
+ return buffer;
+}
+
+std::unique_ptr<uint8_t[]> NinePatch::serializeRoundedRectOutline(size_t* outLen) const {
+ size_t chunkLen = sizeof(uint32_t) * 6;
+ auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[chunkLen]);
+ uint8_t* cursor = buffer.get();
+
+ memcpy(cursor, &outline.left, sizeof(outline.left));
+ cursor += sizeof(outline.left);
+
+ memcpy(cursor, &outline.top, sizeof(outline.top));
+ cursor += sizeof(outline.top);
+
+ memcpy(cursor, &outline.right, sizeof(outline.right));
+ cursor += sizeof(outline.right);
+
+ memcpy(cursor, &outline.bottom, sizeof(outline.bottom));
+ cursor += sizeof(outline.bottom);
+
+ *((float*) cursor) = outlineRadius;
+ cursor += sizeof(outlineRadius);
+
+ *((uint32_t*) cursor) = outlineAlpha;
+
+ *outLen = chunkLen;
+ return buffer;
+}
+
+::std::ostream& operator<<(::std::ostream& out, const Range& range) {
+ return out << "[" << range.start << ", " << range.end << ")";
+}
+
+::std::ostream& operator<<(::std::ostream& out, const Bounds& bounds) {
+ return out << "l=" << bounds.left
+ << " t=" << bounds.top
+ << " r=" << bounds.right
+ << " b=" << bounds.bottom;
+}
+
+::std::ostream& operator<<(::std::ostream& out, const NinePatch& ninePatch) {
+ return out << "horizontalStretch:" << util::joiner(ninePatch.horizontalStretchRegions, " ")
+ << " verticalStretch:" << util::joiner(ninePatch.verticalStretchRegions, " ")
+ << " padding: " << ninePatch.padding
+ << ", bounds: " << ninePatch.layoutBounds
+ << ", outline: " << ninePatch.outline
+ << " rad=" << ninePatch.outlineRadius
+ << " alpha=" << ninePatch.outlineAlpha;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/NinePatch_test.cpp b/tools/aapt2/compile/NinePatch_test.cpp
new file mode 100644
index 0000000..3106ff8
--- /dev/null
+++ b/tools/aapt2/compile/NinePatch_test.cpp
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compile/Image.h"
+#include "test/Test.h"
+
+namespace aapt {
+
+// Pixels are in RGBA_8888 packing.
+
+#define RED "\xff\x00\x00\xff"
+#define BLUE "\x00\x00\xff\xff"
+#define GREEN "\xff\x00\x00\xff"
+#define GR_70 "\xff\x00\x00\xb3"
+#define GR_50 "\xff\x00\x00\x80"
+#define GR_20 "\xff\x00\x00\x33"
+#define BLACK "\x00\x00\x00\xff"
+#define WHITE "\xff\xff\xff\xff"
+#define TRANS "\x00\x00\x00\x00"
+
+static uint8_t* k2x2[] = {
+ (uint8_t*) WHITE WHITE,
+ (uint8_t*) WHITE WHITE,
+};
+
+static uint8_t* kMixedNeutralColor3x3[] = {
+ (uint8_t*) WHITE BLACK TRANS,
+ (uint8_t*) TRANS RED TRANS,
+ (uint8_t*) WHITE WHITE WHITE,
+};
+
+static uint8_t* kTransparentNeutralColor3x3[] = {
+ (uint8_t*) TRANS BLACK TRANS,
+ (uint8_t*) BLACK RED BLACK,
+ (uint8_t*) TRANS BLACK TRANS,
+};
+
+static uint8_t* kSingleStretch7x6[] = {
+ (uint8_t*) WHITE WHITE BLACK BLACK BLACK WHITE WHITE,
+ (uint8_t*) WHITE RED RED RED RED RED WHITE,
+ (uint8_t*) BLACK RED RED RED RED RED WHITE,
+ (uint8_t*) BLACK RED RED RED RED RED WHITE,
+ (uint8_t*) WHITE RED RED RED RED RED WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kMultipleStretch10x7[] = {
+ (uint8_t*) WHITE WHITE BLACK WHITE BLACK BLACK WHITE BLACK WHITE WHITE,
+ (uint8_t*) BLACK RED BLUE RED BLUE BLUE RED BLUE RED WHITE,
+ (uint8_t*) BLACK RED BLUE RED BLUE BLUE RED BLUE RED WHITE,
+ (uint8_t*) WHITE RED BLUE RED BLUE BLUE RED BLUE RED WHITE,
+ (uint8_t*) BLACK RED BLUE RED BLUE BLUE RED BLUE RED WHITE,
+ (uint8_t*) BLACK RED BLUE RED BLUE BLUE RED BLUE RED WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kPadding6x5[] = {
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE BLACK,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE WHITE BLACK BLACK WHITE WHITE,
+};
+
+static uint8_t* kLayoutBoundsWrongEdge3x3[] = {
+ (uint8_t*) WHITE RED WHITE,
+ (uint8_t*) RED WHITE WHITE,
+ (uint8_t*) WHITE WHITE WHITE,
+};
+
+static uint8_t* kLayoutBoundsNotEdgeAligned5x5[] = {
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE RED,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE WHITE RED WHITE WHITE,
+};
+
+static uint8_t* kLayoutBounds5x5[] = {
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE RED,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE RED,
+ (uint8_t*) WHITE RED WHITE RED WHITE,
+};
+
+static uint8_t* kAsymmetricLayoutBounds5x5[] = {
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE RED,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE RED WHITE WHITE WHITE,
+};
+
+static uint8_t* kPaddingAndLayoutBounds5x5[] = {
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE RED,
+ (uint8_t*) WHITE WHITE WHITE WHITE BLACK,
+ (uint8_t*) WHITE WHITE WHITE WHITE RED,
+ (uint8_t*) WHITE RED BLACK RED WHITE,
+};
+
+static uint8_t* kColorfulImage5x5[] = {
+ (uint8_t*) WHITE BLACK WHITE BLACK WHITE,
+ (uint8_t*) BLACK RED BLUE GREEN WHITE,
+ (uint8_t*) BLACK RED GREEN GREEN WHITE,
+ (uint8_t*) WHITE TRANS BLUE GREEN WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kOutlineOpaque10x10[] = {
+ (uint8_t*) WHITE BLACK BLACK BLACK BLACK BLACK BLACK BLACK BLACK WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS GREEN GREEN GREEN GREEN TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kOutlineTranslucent10x10[] = {
+ (uint8_t*) WHITE BLACK BLACK BLACK BLACK BLACK BLACK BLACK BLACK WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
+ (uint8_t*) WHITE TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kOutlineOffsetTranslucent12x10[] = {
+ (uint8_t*) WHITE WHITE WHITE BLACK BLACK BLACK BLACK BLACK BLACK BLACK BLACK WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS GR_20 GR_50 GR_70 GR_70 GR_50 GR_20 TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS GR_50 GR_50 GR_50 GR_50 TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS GR_20 GR_20 GR_20 GR_20 TRANS TRANS WHITE,
+ (uint8_t*) WHITE TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS TRANS WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kOutlineRadius5x5[] = {
+ (uint8_t*) WHITE BLACK BLACK BLACK WHITE,
+ (uint8_t*) BLACK TRANS GREEN TRANS WHITE,
+ (uint8_t*) BLACK GREEN GREEN GREEN WHITE,
+ (uint8_t*) BLACK TRANS GREEN TRANS WHITE,
+ (uint8_t*) WHITE WHITE WHITE WHITE WHITE,
+};
+
+static uint8_t* kStretchAndPadding5x5[] = {
+ (uint8_t*) WHITE WHITE BLACK WHITE WHITE,
+ (uint8_t*) WHITE RED RED RED WHITE,
+ (uint8_t*) BLACK RED RED RED BLACK,
+ (uint8_t*) WHITE RED RED RED WHITE,
+ (uint8_t*) WHITE WHITE BLACK WHITE WHITE,
+};
+
+TEST(NinePatchTest, Minimum3x3) {
+ std::string err;
+ EXPECT_EQ(nullptr, NinePatch::create(k2x2, 2, 2, &err));
+ EXPECT_FALSE(err.empty());
+}
+
+TEST(NinePatchTest, MixedNeutralColors) {
+ std::string err;
+ EXPECT_EQ(nullptr, NinePatch::create(kMixedNeutralColor3x3, 3, 3, &err));
+ EXPECT_FALSE(err.empty());
+}
+
+TEST(NinePatchTest, TransparentNeutralColor) {
+ std::string err;
+ EXPECT_NE(nullptr, NinePatch::create(kTransparentNeutralColor3x3, 3, 3, &err));
+}
+
+TEST(NinePatchTest, SingleStretchRegion) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kSingleStretch7x6, 7, 6, &err);
+ ASSERT_NE(nullptr, ninePatch);
+
+ ASSERT_EQ(1u, ninePatch->horizontalStretchRegions.size());
+ ASSERT_EQ(1u, ninePatch->verticalStretchRegions.size());
+
+ EXPECT_EQ(Range(1, 4), ninePatch->horizontalStretchRegions.front());
+ EXPECT_EQ(Range(1, 3), ninePatch->verticalStretchRegions.front());
+}
+
+TEST(NinePatchTest, MultipleStretchRegions) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kMultipleStretch10x7, 10, 7, &err);
+ ASSERT_NE(nullptr, ninePatch);
+
+ ASSERT_EQ(3u, ninePatch->horizontalStretchRegions.size());
+ ASSERT_EQ(2u, ninePatch->verticalStretchRegions.size());
+
+ EXPECT_EQ(Range(1, 2), ninePatch->horizontalStretchRegions[0]);
+ EXPECT_EQ(Range(3, 5), ninePatch->horizontalStretchRegions[1]);
+ EXPECT_EQ(Range(6, 7), ninePatch->horizontalStretchRegions[2]);
+
+ EXPECT_EQ(Range(0, 2), ninePatch->verticalStretchRegions[0]);
+ EXPECT_EQ(Range(3, 5), ninePatch->verticalStretchRegions[1]);
+}
+
+TEST(NinePatchTest, InferPaddingFromStretchRegions) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kMultipleStretch10x7, 10, 7, &err);
+ ASSERT_NE(nullptr, ninePatch);
+ EXPECT_EQ(Bounds(1, 0, 1, 0), ninePatch->padding);
+}
+
+TEST(NinePatchTest, Padding) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kPadding6x5, 6, 5, &err);
+ ASSERT_NE(nullptr, ninePatch);
+ EXPECT_EQ(Bounds(1, 1, 1, 1), ninePatch->padding);
+}
+
+TEST(NinePatchTest, LayoutBoundsAreOnWrongEdge) {
+ std::string err;
+ EXPECT_EQ(nullptr, NinePatch::create(kLayoutBoundsWrongEdge3x3, 3, 3, &err));
+ EXPECT_FALSE(err.empty());
+}
+
+TEST(NinePatchTest, LayoutBoundsMustTouchEdges) {
+ std::string err;
+ EXPECT_EQ(nullptr, NinePatch::create(kLayoutBoundsNotEdgeAligned5x5, 5, 5, &err));
+ EXPECT_FALSE(err.empty());
+}
+
+TEST(NinePatchTest, LayoutBounds) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kLayoutBounds5x5, 5, 5, &err);
+ ASSERT_NE(nullptr, ninePatch);
+ EXPECT_EQ(Bounds(1, 1, 1, 1), ninePatch->layoutBounds);
+
+ ninePatch = NinePatch::create(kAsymmetricLayoutBounds5x5, 5, 5, &err);
+ ASSERT_NE(nullptr, ninePatch);
+ EXPECT_EQ(Bounds(1, 1, 0, 0), ninePatch->layoutBounds);
+}
+
+TEST(NinePatchTest, PaddingAndLayoutBounds) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kPaddingAndLayoutBounds5x5, 5, 5,
+ &err);
+ ASSERT_NE(nullptr, ninePatch);
+ EXPECT_EQ(Bounds(1, 1, 1, 1), ninePatch->padding);
+ EXPECT_EQ(Bounds(1, 1, 1, 1), ninePatch->layoutBounds);
+}
+
+TEST(NinePatchTest, RegionColorsAreCorrect) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kColorfulImage5x5, 5, 5, &err);
+ ASSERT_NE(nullptr, ninePatch);
+
+ std::vector<uint32_t> expectedColors = {
+ NinePatch::packRGBA((uint8_t*) RED),
+ (uint32_t) android::Res_png_9patch::NO_COLOR,
+ NinePatch::packRGBA((uint8_t*) GREEN),
+ (uint32_t) android::Res_png_9patch::TRANSPARENT_COLOR,
+ NinePatch::packRGBA((uint8_t*) BLUE),
+ NinePatch::packRGBA((uint8_t*) GREEN),
+ };
+ EXPECT_EQ(expectedColors, ninePatch->regionColors);
+}
+
+TEST(NinePatchTest, OutlineFromOpaqueImage) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kOutlineOpaque10x10, 10, 10, &err);
+ ASSERT_NE(nullptr, ninePatch);
+ EXPECT_EQ(Bounds(2, 2, 2, 2), ninePatch->outline);
+ EXPECT_EQ(0x000000ffu, ninePatch->outlineAlpha);
+ EXPECT_EQ(0.0f, ninePatch->outlineRadius);
+}
+
+TEST(NinePatchTest, OutlineFromTranslucentImage) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kOutlineTranslucent10x10, 10, 10,
+ &err);
+ ASSERT_NE(nullptr, ninePatch);
+ EXPECT_EQ(Bounds(3, 3, 3, 3), ninePatch->outline);
+ EXPECT_EQ(0x000000b3u, ninePatch->outlineAlpha);
+ EXPECT_EQ(0.0f, ninePatch->outlineRadius);
+}
+
+TEST(NinePatchTest, OutlineFromOffCenterImage) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kOutlineOffsetTranslucent12x10, 12, 10,
+ &err);
+ ASSERT_NE(nullptr, ninePatch);
+
+ // TODO(adamlesinski): The old AAPT algorithm searches from the outside to the middle
+ // for each inset. If the outline is shifted, the search may not find a closer bounds.
+ // This check should be:
+ // EXPECT_EQ(Bounds(5, 3, 3, 3), ninePatch->outline);
+ // but until I know what behaviour I'm breaking, I will leave it at the incorrect:
+ EXPECT_EQ(Bounds(4, 3, 3, 3), ninePatch->outline);
+
+ EXPECT_EQ(0x000000b3u, ninePatch->outlineAlpha);
+ EXPECT_EQ(0.0f, ninePatch->outlineRadius);
+}
+
+TEST(NinePatchTest, OutlineRadius) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kOutlineRadius5x5, 5, 5, &err);
+ ASSERT_NE(nullptr, ninePatch);
+ EXPECT_EQ(Bounds(0, 0, 0, 0), ninePatch->outline);
+ EXPECT_EQ(3.4142f, ninePatch->outlineRadius);
+}
+
+::testing::AssertionResult bigEndianOne(uint8_t* cursor) {
+ if (cursor[0] == 0 && cursor[1] == 0 && cursor[2] == 0 && cursor[3] == 1) {
+ return ::testing::AssertionSuccess();
+ }
+ return ::testing::AssertionFailure() << "Not BigEndian 1";
+}
+
+TEST(NinePatchTest, SerializePngEndianness) {
+ std::string err;
+ std::unique_ptr<NinePatch> ninePatch = NinePatch::create(kStretchAndPadding5x5, 5, 5, &err);
+ ASSERT_NE(nullptr, ninePatch);
+
+ size_t len;
+ std::unique_ptr<uint8_t[]> data = ninePatch->serializeBase(&len);
+ ASSERT_NE(nullptr, data);
+ ASSERT_NE(0u, len);
+
+ // Skip past wasDeserialized + numXDivs + numYDivs + numColors + xDivsOffset + yDivsOffset
+ // (12 bytes)
+ uint8_t* cursor = data.get() + 12;
+
+ // Check that padding is big-endian. Expecting value 1.
+ EXPECT_TRUE(bigEndianOne(cursor));
+ EXPECT_TRUE(bigEndianOne(cursor + 4));
+ EXPECT_TRUE(bigEndianOne(cursor + 8));
+ EXPECT_TRUE(bigEndianOne(cursor + 12));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/Png.h b/tools/aapt2/compile/Png.h
index f835b06e..4a15d95 100644
--- a/tools/aapt2/compile/Png.h
+++ b/tools/aapt2/compile/Png.h
@@ -17,10 +17,14 @@
#ifndef AAPT_PNG_H
#define AAPT_PNG_H
-#include "util/BigBuffer.h"
#include "Diagnostics.h"
#include "Source.h"
+#include "compile/Image.h"
+#include "io/Io.h"
+#include "process/IResourceTableConsumer.h"
+#include "util/BigBuffer.h"
+#include <android-base/macros.h>
#include <iostream>
#include <string>
@@ -40,8 +44,51 @@
private:
IDiagnostics* mDiag;
+
+ DISALLOW_COPY_AND_ASSIGN(Png);
};
+/**
+ * An InputStream that filters out unimportant PNG chunks.
+ */
+class PngChunkFilter : public io::InputStream {
+public:
+ explicit PngChunkFilter(const StringPiece& data);
+
+ bool Next(const void** buffer, int* len) override;
+ void BackUp(int count) override;
+ bool Skip(int count) override;
+
+ int64_t ByteCount() const override {
+ return static_cast<int64_t>(mWindowStart);
+ }
+
+ bool HadError() const override {
+ return mError;
+ }
+
+private:
+ bool consumeWindow(const void** buffer, int* len);
+
+ StringPiece mData;
+ size_t mWindowStart = 0;
+ size_t mWindowEnd = 0;
+ bool mError = false;
+
+ DISALLOW_COPY_AND_ASSIGN(PngChunkFilter);
+};
+
+/**
+ * Reads a PNG from the InputStream into memory as an RGBA Image.
+ */
+std::unique_ptr<Image> readPng(IAaptContext* context, io::InputStream* in);
+
+/**
+ * Writes the RGBA Image, with optional 9-patch meta-data, into the OutputStream as a PNG.
+ */
+bool writePng(IAaptContext* context, const Image* image, const NinePatch* ninePatch,
+ io::OutputStream* out, const PngOptions& options);
+
} // namespace aapt
#endif // AAPT_PNG_H
diff --git a/tools/aapt2/compile/PngChunkFilter.cpp b/tools/aapt2/compile/PngChunkFilter.cpp
new file mode 100644
index 0000000..70a881f
--- /dev/null
+++ b/tools/aapt2/compile/PngChunkFilter.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compile/Png.h"
+#include "io/Io.h"
+#include "util/StringPiece.h"
+
+namespace aapt {
+
+static constexpr const char* kPngSignature = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a";
+
+// Useful helper function that encodes individual bytes into a uint32
+// at compile time.
+constexpr uint32_t u32(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
+ return (((uint32_t) a) << 24)
+ | (((uint32_t) b) << 16)
+ | (((uint32_t) c) << 8)
+ | ((uint32_t) d);
+}
+
+// Whitelist of PNG chunk types that we want to keep in the resulting PNG.
+enum PngChunkTypes {
+ kPngChunkIHDR = u32(73, 72, 68, 82),
+ kPngChunkIDAT = u32(73, 68, 65, 84),
+ kPngChunkIEND = u32(73, 69, 78, 68),
+ kPngChunkPLTE = u32(80, 76, 84, 69),
+ kPngChunktRNS = u32(116, 82, 78, 83),
+ kPngChunksRGB = u32(115, 82, 71, 66),
+};
+
+static uint32_t peek32LE(const char* data) {
+ uint32_t word = ((uint32_t) data[0]) & 0x000000ff;
+ word <<= 8;
+ word |= ((uint32_t) data[1]) & 0x000000ff;
+ word <<= 8;
+ word |= ((uint32_t) data[2]) & 0x000000ff;
+ word <<= 8;
+ word |= ((uint32_t) data[3]) & 0x000000ff;
+ return word;
+}
+
+static bool isPngChunkWhitelisted(uint32_t type) {
+ switch (type) {
+ case kPngChunkIHDR:
+ case kPngChunkIDAT:
+ case kPngChunkIEND:
+ case kPngChunkPLTE:
+ case kPngChunktRNS:
+ case kPngChunksRGB:
+ return true;
+ default:
+ return false;
+ }
+}
+
+PngChunkFilter::PngChunkFilter(const StringPiece& data) : mData(data) {
+ if (util::stringStartsWith(mData, kPngSignature)) {
+ mWindowStart = 0;
+ mWindowEnd = strlen(kPngSignature);
+ } else {
+ mError = true;
+ }
+}
+
+bool PngChunkFilter::consumeWindow(const void** buffer, int* len) {
+ if (mWindowStart != mWindowEnd) {
+ // We have bytes to give from our window.
+ const int bytesRead = (int) (mWindowEnd - mWindowStart);
+ *buffer = mData.data() + mWindowStart;
+ *len = bytesRead;
+ mWindowStart = mWindowEnd;
+ return true;
+ }
+ return false;
+}
+
+bool PngChunkFilter::Next(const void** buffer, int* len) {
+ if (mError) {
+ return false;
+ }
+
+ // In case BackUp was called, we must consume the window.
+ if (consumeWindow(buffer, len)) {
+ return true;
+ }
+
+ // Advance the window as far as possible (until we meet a chunk that
+ // we want to strip).
+ while (mWindowEnd < mData.size()) {
+ // Chunk length (4 bytes) + type (4 bytes) + crc32 (4 bytes) = 12 bytes.
+ const size_t kMinChunkHeaderSize = 3 * sizeof(uint32_t);
+
+ // Is there enough room for a chunk header?
+ if (mData.size() - mWindowStart < kMinChunkHeaderSize) {
+ mError = true;
+ return false;
+ }
+
+ // Verify the chunk length.
+ const uint32_t chunkLen = peek32LE(mData.data() + mWindowEnd);
+ if (((uint64_t) chunkLen) + ((uint64_t) mWindowEnd) + sizeof(uint32_t) > mData.size()) {
+ // Overflow.
+ mError = true;
+ return false;
+ }
+
+ // Do we strip this chunk?
+ const uint32_t chunkType = peek32LE(mData.data() + mWindowEnd + sizeof(uint32_t));
+ if (isPngChunkWhitelisted(chunkType)) {
+ // Advance the window to include this chunk.
+ mWindowEnd += kMinChunkHeaderSize + chunkLen;
+ } else {
+ // We want to strip this chunk. If we accumulated a window,
+ // we must return the window now.
+ if (mWindowStart != mWindowEnd) {
+ break;
+ }
+
+ // The window is empty, so we can advance past this chunk
+ // and keep looking for the next good chunk,
+ mWindowEnd += kMinChunkHeaderSize + chunkLen;
+ mWindowStart = mWindowEnd;
+ }
+ }
+
+ if (consumeWindow(buffer, len)) {
+ return true;
+ }
+ return false;
+}
+
+void PngChunkFilter::BackUp(int count) {
+ if (mError) {
+ return;
+ }
+ mWindowStart -= count;
+}
+
+bool PngChunkFilter::Skip(int count) {
+ if (mError) {
+ return false;
+ }
+
+ const void* buffer;
+ int len;
+ while (count > 0) {
+ if (!Next(&buffer, &len)) {
+ return false;
+ }
+ if (len > count) {
+ BackUp(len - count);
+ count = 0;
+ } else {
+ count -= len;
+ }
+ }
+ return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/compile/PngCrunch.cpp b/tools/aapt2/compile/PngCrunch.cpp
new file mode 100644
index 0000000..a2e3f4f
--- /dev/null
+++ b/tools/aapt2/compile/PngCrunch.cpp
@@ -0,0 +1,724 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compile/Png.h"
+
+#include <algorithm>
+#include <android-base/errors.h>
+#include <android-base/macros.h>
+#include <png.h>
+#include <unordered_map>
+#include <unordered_set>
+#include <zlib.h>
+
+namespace aapt {
+
+// Size in bytes of the PNG signature.
+constexpr size_t kPngSignatureSize = 8u;
+
+/**
+ * Custom deleter that destroys libpng read and info structs.
+ */
+class PngReadStructDeleter {
+public:
+ explicit PngReadStructDeleter(png_structp readPtr, png_infop infoPtr) :
+ mReadPtr(readPtr), mInfoPtr(infoPtr) {
+ }
+
+ ~PngReadStructDeleter() {
+ png_destroy_read_struct(&mReadPtr, &mInfoPtr, nullptr);
+ }
+
+private:
+ png_structp mReadPtr;
+ png_infop mInfoPtr;
+
+ DISALLOW_COPY_AND_ASSIGN(PngReadStructDeleter);
+};
+
+/**
+ * Custom deleter that destroys libpng write and info structs.
+ */
+class PngWriteStructDeleter {
+public:
+ explicit PngWriteStructDeleter(png_structp writePtr, png_infop infoPtr) :
+ mWritePtr(writePtr), mInfoPtr(infoPtr) {
+ }
+
+ ~PngWriteStructDeleter() {
+ png_destroy_write_struct(&mWritePtr, &mInfoPtr);
+ }
+
+private:
+ png_structp mWritePtr;
+ png_infop mInfoPtr;
+
+ DISALLOW_COPY_AND_ASSIGN(PngWriteStructDeleter);
+};
+
+// Custom warning logging method that uses IDiagnostics.
+static void logWarning(png_structp pngPtr, png_const_charp warningMsg) {
+ IDiagnostics* diag = (IDiagnostics*) png_get_error_ptr(pngPtr);
+ diag->warn(DiagMessage() << warningMsg);
+}
+
+// Custom error logging method that uses IDiagnostics.
+static void logError(png_structp pngPtr, png_const_charp errorMsg) {
+ IDiagnostics* diag = (IDiagnostics*) png_get_error_ptr(pngPtr);
+ diag->error(DiagMessage() << errorMsg);
+}
+
+static void readDataFromStream(png_structp pngPtr, png_bytep buffer, png_size_t len) {
+ io::InputStream* in = (io::InputStream*) png_get_io_ptr(pngPtr);
+
+ const void* inBuffer;
+ int inLen;
+ if (!in->Next(&inBuffer, &inLen)) {
+ if (in->HadError()) {
+ std::string err = in->GetError();
+ png_error(pngPtr, err.c_str());
+ }
+ return;
+ }
+
+ const size_t bytesRead = std::min(static_cast<size_t>(inLen), len);
+ memcpy(buffer, inBuffer, bytesRead);
+ if (bytesRead != static_cast<size_t>(inLen)) {
+ in->BackUp(inLen - static_cast<int>(bytesRead));
+ }
+}
+
+static void writeDataToStream(png_structp pngPtr, png_bytep buffer, png_size_t len) {
+ io::OutputStream* out = (io::OutputStream*) png_get_io_ptr(pngPtr);
+
+ void* outBuffer;
+ int outLen;
+ while (len > 0) {
+ if (!out->Next(&outBuffer, &outLen)) {
+ if (out->HadError()) {
+ std::string err = out->GetError();
+ png_error(pngPtr, err.c_str());
+ }
+ return;
+ }
+
+ const size_t bytesWritten = std::min(static_cast<size_t>(outLen), len);
+ memcpy(outBuffer, buffer, bytesWritten);
+
+ // Advance the input buffer.
+ buffer += bytesWritten;
+ len -= bytesWritten;
+
+ // Advance the output buffer.
+ outLen -= static_cast<int>(bytesWritten);
+ }
+
+ // If the entire output buffer wasn't used, backup.
+ if (outLen > 0) {
+ out->BackUp(outLen);
+ }
+}
+
+std::unique_ptr<Image> readPng(IAaptContext* context, io::InputStream* in) {
+ // Read the first 8 bytes of the file looking for the PNG signature.
+ // Bail early if it does not match.
+ const png_byte* signature;
+ int bufferSize;
+ if (!in->Next((const void**) &signature, &bufferSize)) {
+ context->getDiagnostics()->error(DiagMessage()
+ << android::base::SystemErrorCodeToString(errno));
+ return {};
+ }
+
+ if (static_cast<size_t>(bufferSize) < kPngSignatureSize
+ || png_sig_cmp(signature, 0, kPngSignatureSize) != 0) {
+ context->getDiagnostics()->error(DiagMessage()
+ << "file signature does not match PNG signature");
+ return {};
+ }
+
+ // Start at the beginning of the first chunk.
+ in->BackUp(bufferSize - static_cast<int>(kPngSignatureSize));
+
+ // Create and initialize the png_struct with the default error and warning handlers.
+ // The header version is also passed in to ensure that this was built against the same
+ // version of libpng.
+ png_structp readPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
+ if (readPtr == nullptr) {
+ context->getDiagnostics()->error(DiagMessage()
+ << "failed to create libpng read png_struct");
+ return {};
+ }
+
+ // Create and initialize the memory for image header and data.
+ png_infop infoPtr = png_create_info_struct(readPtr);
+ if (infoPtr == nullptr) {
+ context->getDiagnostics()->error(DiagMessage() << "failed to create libpng read png_info");
+ png_destroy_read_struct(&readPtr, nullptr, nullptr);
+ return {};
+ }
+
+ // Automatically release PNG resources at end of scope.
+ PngReadStructDeleter pngReadDeleter(readPtr, infoPtr);
+
+ // libpng uses longjmp to jump to an error handling routine.
+ // setjmp will only return true if it was jumped to, aka there was
+ // an error.
+ if (setjmp(png_jmpbuf(readPtr))) {
+ return {};
+ }
+
+ // Handle warnings ourselves via IDiagnostics.
+ png_set_error_fn(readPtr, (png_voidp) context->getDiagnostics(), logError, logWarning);
+
+ // Set up the read functions which read from our custom data sources.
+ png_set_read_fn(readPtr, (png_voidp) in, readDataFromStream);
+
+ // Skip the signature that we already read.
+ png_set_sig_bytes(readPtr, kPngSignatureSize);
+
+ // Read the chunk headers.
+ png_read_info(readPtr, infoPtr);
+
+ // Extract image meta-data from the various chunk headers.
+ uint32_t width, height;
+ int bitDepth, colorType, interlaceMethod, compressionMethod, filterMethod;
+ png_get_IHDR(readPtr, infoPtr, &width, &height, &bitDepth, &colorType, &interlaceMethod,
+ &compressionMethod, &filterMethod);
+
+ // When the image is read, expand it so that it is in RGBA 8888 format
+ // so that image handling is uniform.
+
+ if (colorType == PNG_COLOR_TYPE_PALETTE) {
+ png_set_palette_to_rgb(readPtr);
+ }
+
+ if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
+ png_set_expand_gray_1_2_4_to_8(readPtr);
+ }
+
+ if (png_get_valid(readPtr, infoPtr, PNG_INFO_tRNS)) {
+ png_set_tRNS_to_alpha(readPtr);
+ }
+
+ if (bitDepth == 16) {
+ png_set_strip_16(readPtr);
+ }
+
+ if (!(colorType & PNG_COLOR_MASK_ALPHA)) {
+ png_set_add_alpha(readPtr, 0xFF, PNG_FILLER_AFTER);
+ }
+
+ if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
+ png_set_gray_to_rgb(readPtr);
+ }
+
+ if (interlaceMethod != PNG_INTERLACE_NONE) {
+ png_set_interlace_handling(readPtr);
+ }
+
+ // Once all the options for reading have been set, we need to flush
+ // them to libpng.
+ png_read_update_info(readPtr, infoPtr);
+
+ // 9-patch uses int32_t to index images, so we cap the image dimensions to something
+ // that can always be represented by 9-patch.
+ if (width > std::numeric_limits<int32_t>::max() ||
+ height > std::numeric_limits<int32_t>::max()) {
+ context->getDiagnostics()->error(DiagMessage() << "PNG image dimensions are too large: "
+ << width << "x" << height);
+ return {};
+ }
+
+ std::unique_ptr<Image> outputImage = util::make_unique<Image>();
+ outputImage->width = static_cast<int32_t>(width);
+ outputImage->height = static_cast<int32_t>(height);
+
+ const size_t rowBytes = png_get_rowbytes(readPtr, infoPtr);
+ assert(rowBytes == 4 * width); // RGBA
+
+ // Allocate one large block to hold the image.
+ outputImage->data = std::unique_ptr<uint8_t[]>(new uint8_t[height * rowBytes]);
+
+ // Create an array of rows that index into the data block.
+ outputImage->rows = std::unique_ptr<uint8_t*[]>(new uint8_t*[height]);
+ for (uint32_t h = 0; h < height; h++) {
+ outputImage->rows[h] = outputImage->data.get() + (h * rowBytes);
+ }
+
+ // Actually read the image pixels.
+ png_read_image(readPtr, outputImage->rows.get());
+
+ // Finish reading. This will read any other chunks after the image data.
+ png_read_end(readPtr, infoPtr);
+
+ return outputImage;
+}
+
+/**
+ * Experimentally chosen constant to be added to the overhead of using color type
+ * PNG_COLOR_TYPE_PALETTE to account for the uncompressability of the palette chunk.
+ * Without this, many small PNGs encoded with palettes are larger after compression than
+ * the same PNGs encoded as RGBA.
+ */
+constexpr static const size_t kPaletteOverheadConstant = 1024u * 10u;
+
+// Pick a color type by which to encode the image, based on which color type will take
+// the least amount of disk space.
+//
+// 9-patch images traditionally have not been encoded with palettes.
+// The original rationale was to avoid dithering until after scaling,
+// but I don't think this would be an issue with palettes. Either way,
+// our naive size estimation tends to be wrong for small images like 9-patches
+// and using palettes balloons the size of the resulting 9-patch.
+// In order to not regress in size, restrict 9-patch to not use palettes.
+
+// The options are:
+//
+// - RGB
+// - RGBA
+// - RGB + cheap alpha
+// - Color palette
+// - Color palette + cheap alpha
+// - Color palette + alpha palette
+// - Grayscale
+// - Grayscale + cheap alpha
+// - Grayscale + alpha
+//
+static int pickColorType(int32_t width, int32_t height,
+ bool grayScale, bool convertibleToGrayScale, bool hasNinePatch,
+ size_t colorPaletteSize, size_t alphaPaletteSize) {
+ const size_t paletteChunkSize = 16 + colorPaletteSize * 3;
+ const size_t alphaChunkSize = 16 + alphaPaletteSize;
+ const size_t colorAlphaDataChunkSize = 16 + 4 * width * height;
+ const size_t colorDataChunkSize = 16 + 3 * width * height;
+ const size_t grayScaleAlphaDataChunkSize = 16 + 2 * width * height;
+ const size_t paletteDataChunkSize = 16 + width * height;
+
+ if (grayScale) {
+ if (alphaPaletteSize == 0) {
+ // This is the smallest the data can be.
+ return PNG_COLOR_TYPE_GRAY;
+ } else if (colorPaletteSize <= 256 && !hasNinePatch) {
+ // This grayscale has alpha and can fit within a palette.
+ // See if it is worth fitting into a palette.
+ const size_t paletteThreshold = paletteChunkSize + alphaChunkSize +
+ paletteDataChunkSize + kPaletteOverheadConstant;
+ if (grayScaleAlphaDataChunkSize > paletteThreshold) {
+ return PNG_COLOR_TYPE_PALETTE;
+ }
+ }
+ return PNG_COLOR_TYPE_GRAY_ALPHA;
+ }
+
+
+ if (colorPaletteSize <= 256 && !hasNinePatch) {
+ // This image can fit inside a palette. Let's see if it is worth it.
+ size_t totalSizeWithPalette = paletteDataChunkSize + paletteChunkSize;
+ size_t totalSizeWithoutPalette = colorDataChunkSize;
+ if (alphaPaletteSize > 0) {
+ totalSizeWithPalette += alphaPaletteSize;
+ totalSizeWithoutPalette = colorAlphaDataChunkSize;
+ }
+
+ if (totalSizeWithoutPalette > totalSizeWithPalette + kPaletteOverheadConstant) {
+ return PNG_COLOR_TYPE_PALETTE;
+ }
+ }
+
+ if (convertibleToGrayScale) {
+ if (alphaPaletteSize == 0) {
+ return PNG_COLOR_TYPE_GRAY;
+ } else {
+ return PNG_COLOR_TYPE_GRAY_ALPHA;
+ }
+ }
+
+ if (alphaPaletteSize == 0) {
+ return PNG_COLOR_TYPE_RGB;
+ }
+ return PNG_COLOR_TYPE_RGBA;
+}
+
+// Assigns indices to the color and alpha palettes, encodes them, and then invokes
+// png_set_PLTE/png_set_tRNS.
+// This must be done before writing image data.
+// Image data must be transformed to use the indices assigned within the palette.
+static void writePalette(png_structp writePtr, png_infop writeInfoPtr,
+ std::unordered_map<uint32_t, int>* colorPalette,
+ std::unordered_set<uint32_t>* alphaPalette) {
+ assert(colorPalette->size() <= 256);
+ assert(alphaPalette->size() <= 256);
+
+ // Populate the PNG palette struct and assign indices to the color
+ // palette.
+
+ // Colors in the alpha palette should have smaller indices.
+ // This will ensure that we can truncate the alpha palette if it is
+ // smaller than the color palette.
+ int index = 0;
+ for (uint32_t color : *alphaPalette) {
+ (*colorPalette)[color] = index++;
+ }
+
+ // Assign the rest of the entries.
+ for (auto& entry : *colorPalette) {
+ if (entry.second == -1) {
+ entry.second = index++;
+ }
+ }
+
+ // Create the PNG color palette struct.
+ auto colorPaletteBytes = std::unique_ptr<png_color[]>(new png_color[colorPalette->size()]);
+
+ std::unique_ptr<png_byte[]> alphaPaletteBytes;
+ if (!alphaPalette->empty()) {
+ alphaPaletteBytes = std::unique_ptr<png_byte[]>(new png_byte[alphaPalette->size()]);
+ }
+
+ for (const auto& entry : *colorPalette) {
+ const uint32_t color = entry.first;
+ const int index = entry.second;
+ assert(index >= 0);
+ assert(static_cast<size_t>(index) < colorPalette->size());
+
+ png_colorp slot = colorPaletteBytes.get() + index;
+ slot->red = color >> 24;
+ slot->green = color >> 16;
+ slot->blue = color >> 8;
+
+ const png_byte alpha = color & 0x000000ff;
+ if (alpha != 0xff && alphaPaletteBytes) {
+ assert(static_cast<size_t>(index) < alphaPalette->size());
+ alphaPaletteBytes[index] = alpha;
+ }
+ }
+
+ // The bytes get copied here, so it is safe to release colorPaletteBytes at the end of function
+ // scope.
+ png_set_PLTE(writePtr, writeInfoPtr, colorPaletteBytes.get(), colorPalette->size());
+
+ if (alphaPaletteBytes) {
+ png_set_tRNS(writePtr, writeInfoPtr, alphaPaletteBytes.get(), alphaPalette->size(),
+ nullptr);
+ }
+}
+
+// Write the 9-patch custom PNG chunks to writeInfoPtr. This must be done before
+// writing image data.
+static void writeNinePatch(png_structp writePtr, png_infop writeInfoPtr,
+ const NinePatch* ninePatch) {
+ // The order of the chunks is important.
+ // 9-patch code in older platforms expects the 9-patch chunk to
+ // be last.
+
+ png_unknown_chunk unknownChunks[3];
+ memset(unknownChunks, 0, sizeof(unknownChunks));
+
+ size_t index = 0;
+ size_t chunkLen = 0;
+
+ std::unique_ptr<uint8_t[]> serializedOutline =
+ ninePatch->serializeRoundedRectOutline(&chunkLen);
+ strcpy((char*) unknownChunks[index].name, "npOl");
+ unknownChunks[index].size = chunkLen;
+ unknownChunks[index].data = (png_bytep) serializedOutline.get();
+ unknownChunks[index].location = PNG_HAVE_PLTE;
+ index++;
+
+ std::unique_ptr<uint8_t[]> serializedLayoutBounds;
+ if (ninePatch->layoutBounds.nonZero()) {
+ serializedLayoutBounds = ninePatch->serializeLayoutBounds(&chunkLen);
+ strcpy((char*) unknownChunks[index].name, "npLb");
+ unknownChunks[index].size = chunkLen;
+ unknownChunks[index].data = (png_bytep) serializedLayoutBounds.get();
+ unknownChunks[index].location = PNG_HAVE_PLTE;
+ index++;
+ }
+
+ std::unique_ptr<uint8_t[]> serializedNinePatch = ninePatch->serializeBase(&chunkLen);
+ strcpy((char*) unknownChunks[index].name, "npTc");
+ unknownChunks[index].size = chunkLen;
+ unknownChunks[index].data = (png_bytep) serializedNinePatch.get();
+ unknownChunks[index].location = PNG_HAVE_PLTE;
+ index++;
+
+ // Handle all unknown chunks. We are manually setting the chunks here,
+ // so we will only ever handle our custom chunks.
+ png_set_keep_unknown_chunks(writePtr, PNG_HANDLE_CHUNK_ALWAYS, nullptr, 0);
+
+ // Set the actual chunks here. The data gets copied, so our buffers can
+ // safely go out of scope.
+ png_set_unknown_chunks(writePtr, writeInfoPtr, unknownChunks, index);
+}
+
+bool writePng(IAaptContext* context, const Image* image, const NinePatch* ninePatch,
+ io::OutputStream* out, const PngOptions& options) {
+ // Create and initialize the write png_struct with the default error and warning handlers.
+ // The header version is also passed in to ensure that this was built against the same
+ // version of libpng.
+ png_structp writePtr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+ nullptr, nullptr, nullptr);
+ if (writePtr == nullptr) {
+ context->getDiagnostics()->error(DiagMessage()
+ << "failed to create libpng write png_struct");
+ return false;
+ }
+
+ // Allocate memory to store image header data.
+ png_infop writeInfoPtr = png_create_info_struct(writePtr);
+ if (writeInfoPtr == nullptr) {
+ context->getDiagnostics()->error(DiagMessage() << "failed to create libpng write png_info");
+ png_destroy_write_struct(&writePtr, nullptr);
+ return false;
+ }
+
+ // Automatically release PNG resources at end of scope.
+ PngWriteStructDeleter pngWriteDeleter(writePtr, writeInfoPtr);
+
+ // libpng uses longjmp to jump to error handling routines.
+ // setjmp will return true only if it was jumped to, aka, there was an error.
+ if (setjmp(png_jmpbuf(writePtr))) {
+ return false;
+ }
+
+ // Handle warnings with our IDiagnostics.
+ png_set_error_fn(writePtr, (png_voidp) context->getDiagnostics(), logError, logWarning);
+
+ // Set up the write functions which write to our custom data sources.
+ png_set_write_fn(writePtr, (png_voidp) out, writeDataToStream, nullptr);
+
+ // We want small files and can take the performance hit to achieve this goal.
+ png_set_compression_level(writePtr, Z_BEST_COMPRESSION);
+
+ // Begin analysis of the image data.
+ // Scan the entire image and determine if:
+ // 1. Every pixel has R == G == B (grayscale)
+ // 2. Every pixel has A == 255 (opaque)
+ // 3. There are no more than 256 distinct RGBA colors (palette).
+ std::unordered_map<uint32_t, int> colorPalette;
+ std::unordered_set<uint32_t> alphaPalette;
+ bool needsToZeroRGBChannelsOfTransparentPixels = false;
+ bool grayScale = true;
+ int maxGrayDeviation = 0;
+
+ for (int32_t y = 0; y < image->height; y++) {
+ const uint8_t* row = image->rows[y];
+ for (int32_t x = 0; x < image->width; x++) {
+ int red = *row++;
+ int green = *row++;
+ int blue = *row++;
+ int alpha = *row++;
+
+ if (alpha == 0) {
+ // The color is completely transparent.
+ // For purposes of palettes and grayscale optimization,
+ // treat all channels as 0x00.
+ needsToZeroRGBChannelsOfTransparentPixels =
+ needsToZeroRGBChannelsOfTransparentPixels ||
+ (red != 0 || green != 0 || blue != 0);
+ red = green = blue = 0;
+ }
+
+ // Insert the color into the color palette.
+ const uint32_t color = red << 24 | green << 16 | blue << 8 | alpha;
+ colorPalette[color] = -1;
+
+ // If the pixel has non-opaque alpha, insert it into the
+ // alpha palette.
+ if (alpha != 0xff) {
+ alphaPalette.insert(color);
+ }
+
+ // Check if the image is indeed grayscale.
+ if (grayScale) {
+ if (red != green || red != blue) {
+ grayScale = false;
+ }
+ }
+
+ // Calculate the gray scale deviation so that it can be compared
+ // with the threshold.
+ maxGrayDeviation = std::max(std::abs(red - green), maxGrayDeviation);
+ maxGrayDeviation = std::max(std::abs(green - blue), maxGrayDeviation);
+ maxGrayDeviation = std::max(std::abs(blue - red), maxGrayDeviation);
+ }
+ }
+
+ if (context->verbose()) {
+ DiagMessage msg;
+ msg << " paletteSize=" << colorPalette.size()
+ << " alphaPaletteSize=" << alphaPalette.size()
+ << " maxGrayDeviation=" << maxGrayDeviation
+ << " grayScale=" << (grayScale ? "true" : "false");
+ context->getDiagnostics()->note(msg);
+ }
+
+ const bool convertibleToGrayScale = maxGrayDeviation <= options.grayScaleTolerance;
+
+ const int newColorType = pickColorType(image->width, image->height, grayScale,
+ convertibleToGrayScale, ninePatch != nullptr,
+ colorPalette.size(), alphaPalette.size());
+
+ if (context->verbose()) {
+ DiagMessage msg;
+ msg << "encoding PNG ";
+ if (ninePatch) {
+ msg << "(with 9-patch) as ";
+ }
+ switch (newColorType) {
+ case PNG_COLOR_TYPE_GRAY:
+ msg << "GRAY";
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ msg << "GRAY + ALPHA";
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ msg << "RGB";
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ msg << "RGBA";
+ break;
+ case PNG_COLOR_TYPE_PALETTE:
+ msg << "PALETTE";
+ break;
+ default:
+ msg << "unknown type " << newColorType;
+ break;
+ }
+ context->getDiagnostics()->note(msg);
+ }
+
+ png_set_IHDR(writePtr, writeInfoPtr, image->width, image->height, 8, newColorType,
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+ if (newColorType & PNG_COLOR_MASK_PALETTE) {
+ // Assigns indices to the palette, and writes the encoded palette to the libpng writePtr.
+ writePalette(writePtr, writeInfoPtr, &colorPalette, &alphaPalette);
+ png_set_filter(writePtr, 0, PNG_NO_FILTERS);
+ } else {
+ png_set_filter(writePtr, 0, PNG_ALL_FILTERS);
+ }
+
+ if (ninePatch) {
+ writeNinePatch(writePtr, writeInfoPtr, ninePatch);
+ }
+
+ // Flush our updates to the header.
+ png_write_info(writePtr, writeInfoPtr);
+
+ // Write out each row of image data according to its encoding.
+ if (newColorType == PNG_COLOR_TYPE_PALETTE) {
+ // 1 byte/pixel.
+ auto outRow = std::unique_ptr<png_byte[]>(new png_byte[image->width]);
+
+ for (int32_t y = 0; y < image->height; y++) {
+ png_const_bytep inRow = image->rows[y];
+ for (int32_t x = 0; x < image->width; x++) {
+ int rr = *inRow++;
+ int gg = *inRow++;
+ int bb = *inRow++;
+ int aa = *inRow++;
+ if (aa == 0) {
+ // Zero out color channels when transparent.
+ rr = gg = bb = 0;
+ }
+
+ const uint32_t color = rr << 24 | gg << 16 | bb << 8 | aa;
+ const int idx = colorPalette[color];
+ assert(idx != -1);
+ outRow[x] = static_cast<png_byte>(idx);
+ }
+ png_write_row(writePtr, outRow.get());
+ }
+ } else if (newColorType == PNG_COLOR_TYPE_GRAY || newColorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
+ const size_t bpp = newColorType == PNG_COLOR_TYPE_GRAY ? 1 : 2;
+ auto outRow = std::unique_ptr<png_byte[]>(new png_byte[image->width * bpp]);
+
+ for (int32_t y = 0; y < image->height; y++) {
+ png_const_bytep inRow = image->rows[y];
+ for (int32_t x = 0; x < image->width; x++) {
+ int rr = inRow[x * 4];
+ int gg = inRow[x * 4 + 1];
+ int bb = inRow[x * 4 + 2];
+ int aa = inRow[x * 4 + 3];
+ if (aa == 0) {
+ // Zero out the gray channel when transparent.
+ rr = gg = bb = 0;
+ }
+
+ if (grayScale) {
+ // The image was already grayscale, red == green == blue.
+ outRow[x * bpp] = inRow[x * 4];
+ } else {
+ // The image is convertible to grayscale, use linear-luminance of
+ // sRGB colorspace: https://en.wikipedia.org/wiki/Grayscale#Colorimetric_.28luminance-preserving.29_conversion_to_grayscale
+ outRow[x * bpp] = (png_byte) (rr * 0.2126f + gg * 0.7152f + bb * 0.0722f);
+ }
+
+ if (bpp == 2) {
+ // Write out alpha if we have it.
+ outRow[x * bpp + 1] = aa;
+ }
+ }
+ png_write_row(writePtr, outRow.get());
+ }
+ } else if (newColorType == PNG_COLOR_TYPE_RGB || newColorType == PNG_COLOR_TYPE_RGBA) {
+ const size_t bpp = newColorType == PNG_COLOR_TYPE_RGB ? 3 : 4;
+ if (needsToZeroRGBChannelsOfTransparentPixels) {
+ // The source RGBA data can't be used as-is, because we need to zero out the RGB
+ // values of transparent pixels.
+ auto outRow = std::unique_ptr<png_byte[]>(new png_byte[image->width * bpp]);
+
+ for (int32_t y = 0; y < image->height; y++) {
+ png_const_bytep inRow = image->rows[y];
+ for (int32_t x = 0; x < image->width; x++) {
+ int rr = *inRow++;
+ int gg = *inRow++;
+ int bb = *inRow++;
+ int aa = *inRow++;
+ if (aa == 0) {
+ // Zero out the RGB channels when transparent.
+ rr = gg = bb = 0;
+ }
+ outRow[x * bpp] = rr;
+ outRow[x * bpp + 1] = gg;
+ outRow[x * bpp + 2] = bb;
+ if (bpp == 4) {
+ outRow[x * bpp + 3] = aa;
+ }
+ }
+ png_write_row(writePtr, outRow.get());
+ }
+ } else {
+ // The source image can be used as-is, just tell libpng whether or not to ignore
+ // the alpha channel.
+ if (newColorType == PNG_COLOR_TYPE_RGB) {
+ // Delete the extraneous alpha values that we appended to our buffer
+ // when reading the original values.
+ png_set_filler(writePtr, 0, PNG_FILLER_AFTER);
+ }
+ png_write_image(writePtr, image->rows.get());
+ }
+ } else {
+ assert(false && "unreachable");
+ }
+
+ png_write_end(writePtr, writeInfoPtr);
+ return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/cheap_transparency.png b/tools/aapt2/integration-tests/AppOne/res/drawable/cheap_transparency.png
new file mode 100644
index 0000000..0522a99
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/cheap_transparency.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/complex.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/complex.9.png
new file mode 100644
index 0000000..baf9fff
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/complex.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/outline_8x8.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/outline_8x8.9.png
new file mode 100644
index 0000000..7b331e1
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/outline_8x8.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_off_center_outline_32x16.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_off_center_outline_32x16.9.png
new file mode 100644
index 0000000..0ec6c70
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_off_center_outline_32x16.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_outline_32x16.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_outline_32x16.9.png
new file mode 100644
index 0000000..e05708a
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/round_rect_outline_32x16.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_3x3.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_3x3.9.png
new file mode 100644
index 0000000..a11377a
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_optical_bounds_3x3.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_optical_bounds_3x3.9.png
new file mode 100644
index 0000000..6803e42
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/transparent_optical_bounds_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/white_3x3.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/white_3x3.9.png
new file mode 100644
index 0000000..1a3731b
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/white_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/white_optical_bounds_3x3.9.png b/tools/aapt2/integration-tests/AppOne/res/drawable/white_optical_bounds_3x3.9.png
new file mode 100644
index 0000000..489ace2
--- /dev/null
+++ b/tools/aapt2/integration-tests/AppOne/res/drawable/white_optical_bounds_3x3.9.png
Binary files differ
diff --git a/tools/aapt2/io/Io.cpp b/tools/aapt2/io/Io.cpp
new file mode 100644
index 0000000..963c21c
--- /dev/null
+++ b/tools/aapt2/io/Io.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "io/Io.h"
+
+#include <algorithm>
+#include <cstring>
+
+namespace aapt {
+namespace io {
+
+bool copy(OutputStream* out, InputStream* in) {
+ const void* inBuffer;
+ int inLen;
+ while (in->Next(&inBuffer, &inLen)) {
+ void* outBuffer;
+ int outLen;
+ if (!out->Next(&outBuffer, &outLen)) {
+ return !out->HadError();
+ }
+
+ const int bytesToCopy = std::min(inLen, outLen);
+ memcpy(outBuffer, inBuffer, bytesToCopy);
+ out->BackUp(outLen - bytesToCopy);
+ in->BackUp(inLen - bytesToCopy);
+ }
+ return !in->HadError();
+}
+
+} // namespace io
+} // namespace aapt
diff --git a/tools/aapt2/io/Io.h b/tools/aapt2/io/Io.h
new file mode 100644
index 0000000..e1e9107
--- /dev/null
+++ b/tools/aapt2/io/Io.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_IO_IO_H
+#define AAPT_IO_IO_H
+
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <string>
+
+namespace aapt {
+namespace io {
+
+/**
+ * InputStream interface that inherits from protobuf's ZeroCopyInputStream,
+ * but adds error handling methods to better report issues.
+ *
+ * The code style here matches the protobuf style.
+ */
+class InputStream : public google::protobuf::io::ZeroCopyInputStream {
+public:
+ virtual std::string GetError() const {
+ return {};
+ }
+
+ virtual bool HadError() const = 0;
+};
+
+/**
+ * OutputStream interface that inherits from protobuf's ZeroCopyOutputStream,
+ * but adds error handling methods to better report issues.
+ *
+ * The code style here matches the protobuf style.
+ */
+class OutputStream : public google::protobuf::io::ZeroCopyOutputStream {
+public:
+ virtual std::string GetError() const {
+ return {};
+ }
+
+ virtual bool HadError() const = 0;
+};
+
+/**
+ * Copies the data from in to out. Returns true if there was no error.
+ * If there was an error, check the individual streams' HadError/GetError
+ * methods.
+ */
+bool copy(OutputStream* out, InputStream* in);
+
+} // namespace io
+} // namespace aapt
+
+#endif /* AAPT_IO_IO_H */
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index c236394..b6b4b473 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -72,6 +72,7 @@
bool noAutoVersion = false;
bool noVersionVectors = false;
+ bool noResourceDeduping = false;
bool staticLib = false;
bool noStaticLibPackages = false;
bool generateNonFinalIds = false;
@@ -1505,6 +1506,14 @@
}
}
+ if (!mOptions.noResourceDeduping) {
+ ResourceDeduper deduper;
+ if (!deduper.consume(mContext, &mFinalTable)) {
+ mContext->getDiagnostics()->error(DiagMessage() << "failed deduping resources");
+ return 1;
+ }
+ }
+
proguard::KeepSet proguardKeepSet;
proguard::KeepSet proguardMainDexKeepSet;
@@ -1743,6 +1752,9 @@
"Disables automatic versioning of vector drawables. Use this only\n"
"when building with vector drawable support library",
&options.noVersionVectors)
+ .optionalSwitch("--no-resource-deduping", "Disables automatic deduping of resources with\n"
+ "identical values across compatible configurations.",
+ &options.noResourceDeduping)
.optionalSwitch("-x", "Legacy flag that specifies to use the package identifier 0x01",
&legacyXFlag)
.optionalSwitch("-z", "Require localization of strings marked 'suggested'",
diff --git a/tools/aapt2/link/Linkers.h b/tools/aapt2/link/Linkers.h
index 82e2868..ce455da 100644
--- a/tools/aapt2/link/Linkers.h
+++ b/tools/aapt2/link/Linkers.h
@@ -60,6 +60,14 @@
};
/**
+ * Removes duplicated key-value entries from dominated resources.
+ */
+class ResourceDeduper : public IResourceTableConsumer {
+public:
+ bool consume(IAaptContext* context, ResourceTable* table) override;
+};
+
+/**
* If any attribute resource values are defined as public, this consumer will move all private
* attribute resource values to a private ^private-attr type, avoiding backwards compatibility
* issues with new apps running on old platforms.
diff --git a/tools/aapt2/link/ResourceDeduper.cpp b/tools/aapt2/link/ResourceDeduper.cpp
new file mode 100644
index 0000000..0276261
--- /dev/null
+++ b/tools/aapt2/link/ResourceDeduper.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DominatorTree.h"
+#include "ResourceTable.h"
+#include "link/Linkers.h"
+
+#include <algorithm>
+
+namespace aapt {
+
+namespace {
+
+/**
+ * Remove duplicated key-value entries from dominated resources.
+ *
+ * Based on the dominator tree, we can remove a value of an entry if:
+ *
+ * 1. The configuration for the entry's value is dominated by a configuration
+ * with an equivalent entry value.
+ * 2. All compatible configurations for the entry (those not in conflict and
+ * unrelated by domination with the configuration for the entry's value) have
+ * an equivalent entry value.
+ */
+class DominatedKeyValueRemover : public DominatorTree::BottomUpVisitor {
+public:
+ using Node = DominatorTree::Node;
+
+ explicit DominatedKeyValueRemover(IAaptContext* context, ResourceEntry* entry) :
+ mContext(context), mEntry(entry) {
+ }
+
+ void visitConfig(Node* node) {
+ Node* parent = node->parent();
+ if (!parent) {
+ return;
+ }
+ ResourceConfigValue* nodeValue = node->value();
+ ResourceConfigValue* parentValue = parent->value();
+ if (!nodeValue || !parentValue) {
+ return;
+ }
+ if (!nodeValue->value->equals(parentValue->value.get())) {
+ return;
+ }
+
+ // Compare compatible configs for this entry and ensure the values are
+ // equivalent.
+ const ConfigDescription& nodeConfiguration = nodeValue->config;
+ for (const auto& sibling : mEntry->values) {
+ if (!sibling->value) {
+ // Sibling was already removed.
+ continue;
+ }
+ if (nodeConfiguration.isCompatibleWith(sibling->config)
+ && !nodeValue->value->equals(sibling->value.get())) {
+ // The configurations are compatible, but the value is
+ // different, so we can't remove this value.
+ return;
+ }
+ }
+ if (mContext->verbose()) {
+ mContext->getDiagnostics()->note(
+ DiagMessage(nodeValue->value->getSource())
+ << "removing dominated duplicate resource with name \""
+ << mEntry->name << "\"");
+ }
+ nodeValue->value = {};
+ }
+
+private:
+ IAaptContext* mContext;
+ ResourceEntry* mEntry;
+};
+
+static void dedupeEntry(IAaptContext* context, ResourceEntry* entry) {
+ DominatorTree tree(entry->values);
+ DominatedKeyValueRemover remover(context, entry);
+ tree.accept(&remover);
+
+ // Erase the values that were removed.
+ entry->values.erase(std::remove_if(entry->values.begin(), entry->values.end(),
+ [](const std::unique_ptr<ResourceConfigValue>& val) -> bool {
+ return val == nullptr || val->value == nullptr;
+ }), entry->values.end());
+}
+
+} // namespace
+
+bool ResourceDeduper::consume(IAaptContext* context, ResourceTable* table) {
+ for (auto& package : table->packages) {
+ for (auto& type : package->types) {
+ for (auto& entry : type->entries) {
+ dedupeEntry(context, entry.get());
+ }
+ }
+ }
+ return true;
+}
+
+} // aapt
diff --git a/tools/aapt2/link/ResourceDeduper_test.cpp b/tools/aapt2/link/ResourceDeduper_test.cpp
new file mode 100644
index 0000000..47071a51
--- /dev/null
+++ b/tools/aapt2/link/ResourceDeduper_test.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ResourceTable.h"
+#include "link/Linkers.h"
+#include "test/Test.h"
+
+namespace aapt {
+
+TEST(ResourceDeduperTest, SameValuesAreDeduped) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+ const ConfigDescription defaultConfig = {};
+ const ConfigDescription enConfig = test::parseConfigOrDie("en");
+ const ConfigDescription enV21Config = test::parseConfigOrDie("en-v21");
+ // Chosen because this configuration is compatible with en.
+ const ConfigDescription landConfig = test::parseConfigOrDie("land");
+
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+ .addString("android:string/dedupe", ResourceId{}, defaultConfig, "dedupe")
+ .addString("android:string/dedupe", ResourceId{}, enConfig, "dedupe")
+ .addString("android:string/dedupe", ResourceId{}, landConfig, "dedupe")
+ .addString("android:string/dedupe2", ResourceId{}, defaultConfig, "dedupe")
+ .addString("android:string/dedupe2", ResourceId{}, enConfig, "dedupe")
+ .addString("android:string/dedupe2", ResourceId{}, enV21Config, "keep")
+ .addString("android:string/dedupe2", ResourceId{}, landConfig, "dedupe")
+ .build();
+
+ ASSERT_TRUE(ResourceDeduper().consume(context.get(), table.get()));
+ EXPECT_EQ(
+ nullptr,
+ test::getValueForConfig<String>(table.get(), "android:string/dedupe", enConfig));
+ EXPECT_EQ(
+ nullptr,
+ test::getValueForConfig<String>(table.get(), "android:string/dedupe", landConfig));
+ EXPECT_EQ(
+ nullptr,
+ test::getValueForConfig<String>(table.get(), "android:string/dedupe2", enConfig));
+ EXPECT_NE(
+ nullptr,
+ test::getValueForConfig<String>(table.get(), "android:string/dedupe2", enV21Config));
+}
+
+TEST(ResourceDeduperTest, DifferentValuesAreKept) {
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder().build();
+ const ConfigDescription defaultConfig = {};
+ const ConfigDescription enConfig = test::parseConfigOrDie("en");
+ const ConfigDescription enV21Config = test::parseConfigOrDie("en-v21");
+ // Chosen because this configuration is compatible with en.
+ const ConfigDescription landConfig = test::parseConfigOrDie("land");
+
+ std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
+ .addString("android:string/keep", ResourceId{}, defaultConfig, "keep")
+ .addString("android:string/keep", ResourceId{}, enConfig, "keep")
+ .addString("android:string/keep", ResourceId{}, enV21Config, "keep2")
+ .addString("android:string/keep", ResourceId{}, landConfig, "keep2")
+ .build();
+
+ ASSERT_TRUE(ResourceDeduper().consume(context.get(), table.get()));
+ EXPECT_NE(
+ nullptr,
+ test::getValueForConfig<String>(table.get(), "android:string/keep", enConfig));
+ EXPECT_NE(
+ nullptr,
+ test::getValueForConfig<String>(table.get(), "android:string/keep", enV21Config));
+ EXPECT_NE(
+ nullptr,
+ test::getValueForConfig<String>(table.get(), "android:string/keep", landConfig));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/readme.md b/tools/aapt2/readme.md
index 267200d..93c790d 100644
--- a/tools/aapt2/readme.md
+++ b/tools/aapt2/readme.md
@@ -4,6 +4,10 @@
### `aapt2 compile ...`
- Added support for inline complex XML resources. See
https://developer.android.com/guide/topics/resources/complex-xml-resources.html
+### `aapt link ...`
+- Duplicate resource filtering: removes duplicate resources in dominated configurations
+ that are always identical when selected at runtime. This can be disabled with
+ `--no-resource-deduping`.
## Version 2.1
### `aapt2 link ...`
diff --git a/tools/aapt2/util/BigBuffer.cpp b/tools/aapt2/util/BigBuffer.cpp
index c88e3c1..de4ecd2 100644
--- a/tools/aapt2/util/BigBuffer.cpp
+++ b/tools/aapt2/util/BigBuffer.cpp
@@ -49,4 +49,29 @@
return mBlocks.back().buffer.get();
}
+void* BigBuffer::nextBlock(size_t* outSize) {
+ if (!mBlocks.empty()) {
+ Block& block = mBlocks.back();
+ if (block.size != block.mBlockSize) {
+ void* outBuffer = block.buffer.get() + block.size;
+ size_t size = block.mBlockSize - block.size;
+ block.size = block.mBlockSize;
+ mSize += size;
+ *outSize = size;
+ return outBuffer;
+ }
+ }
+
+ // Zero-allocate the block's buffer.
+ Block block = {};
+ block.buffer = std::unique_ptr<uint8_t[]>(new uint8_t[mBlockSize]());
+ assert(block.buffer);
+ block.size = mBlockSize;
+ block.mBlockSize = mBlockSize;
+ mBlocks.push_back(std::move(block));
+ mSize += mBlockSize;
+ *outSize = mBlockSize;
+ return mBlocks.back().buffer.get();
+}
+
} // namespace aapt
diff --git a/tools/aapt2/util/BigBuffer.h b/tools/aapt2/util/BigBuffer.h
index ba8532f..685614f 100644
--- a/tools/aapt2/util/BigBuffer.h
+++ b/tools/aapt2/util/BigBuffer.h
@@ -82,6 +82,20 @@
T* nextBlock(size_t count = 1);
/**
+ * Returns the next block available and puts the size in outCount.
+ * This is useful for grabbing blocks where the size doesn't matter.
+ * Use backUp() to give back any bytes that were not used.
+ */
+ void* nextBlock(size_t* outCount);
+
+ /**
+ * Backs up count bytes. This must only be called after nextBlock()
+ * and can not be larger than sizeof(T) * count of the last nextBlock()
+ * call.
+ */
+ void backUp(size_t count);
+
+ /**
* Moves the specified BigBuffer into this one. When this method
* returns, buffer is empty.
*/
@@ -97,6 +111,8 @@
*/
void align4();
+ size_t getBlockSize() const;
+
const_iterator begin() const;
const_iterator end() const;
@@ -123,6 +139,10 @@
return mSize;
}
+inline size_t BigBuffer::getBlockSize() const {
+ return mBlockSize;
+}
+
template <typename T>
inline T* BigBuffer::nextBlock(size_t count) {
static_assert(std::is_standard_layout<T>::value, "T must be standard_layout type");
@@ -130,6 +150,12 @@
return reinterpret_cast<T*>(nextBlockImpl(sizeof(T) * count));
}
+inline void BigBuffer::backUp(size_t count) {
+ Block& block = mBlocks.back();
+ block.size -= count;
+ mSize -= count;
+}
+
inline void BigBuffer::appendBuffer(BigBuffer&& buffer) {
std::move(buffer.mBlocks.begin(), buffer.mBlocks.end(), std::back_inserter(mBlocks));
mSize += buffer.mSize;
diff --git a/tools/aapt2/util/StringPiece.h b/tools/aapt2/util/StringPiece.h
index 4300a67..266c003 100644
--- a/tools/aapt2/util/StringPiece.h
+++ b/tools/aapt2/util/StringPiece.h
@@ -39,6 +39,9 @@
using const_iterator = const TChar*;
using difference_type = size_t;
+ // End of string marker.
+ constexpr static const size_t npos = static_cast<size_t>(-1);
+
BasicStringPiece();
BasicStringPiece(const BasicStringPiece<TChar>& str);
BasicStringPiece(const std::basic_string<TChar>& str); // NOLINT(implicit)
@@ -48,7 +51,7 @@
BasicStringPiece<TChar>& operator=(const BasicStringPiece<TChar>& rhs);
BasicStringPiece<TChar>& assign(const TChar* str, size_t len);
- BasicStringPiece<TChar> substr(size_t start, size_t len) const;
+ BasicStringPiece<TChar> substr(size_t start, size_t len = npos) const;
BasicStringPiece<TChar> substr(BasicStringPiece<TChar>::const_iterator begin,
BasicStringPiece<TChar>::const_iterator end) const;
@@ -81,6 +84,9 @@
//
template <typename TChar>
+constexpr const size_t BasicStringPiece<TChar>::npos;
+
+template <typename TChar>
inline BasicStringPiece<TChar>::BasicStringPiece() : mData(nullptr) , mLength(0) {
}
@@ -127,7 +133,11 @@
template <typename TChar>
inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(size_t start, size_t len) const {
- if (start + len > mLength) {
+ if (len == npos) {
+ len = mLength - start;
+ }
+
+ if (start > mLength || start + len > mLength) {
return BasicStringPiece<TChar>();
}
return BasicStringPiece<TChar>(mData + start, len);
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index f1da3a2..090cee8 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -601,14 +601,6 @@
return Arrays.equals(argb1, argb2);
}
- // Only used by AssetAtlasService, which we don't care about.
- @LayoutlibDelegate
- /*package*/ static long nativeRefPixelRef(long nativeBitmap) {
- // Hack: This is called by Bitmap.refSkPixelRef() and LayoutLib uses that method to get
- // the native pointer from a Bitmap. So, we return nativeBitmap here.
- return nativeBitmap;
- }
-
// ---- Private delegate/helper methods ----
private Bitmap_Delegate(BufferedImage image, Config config) {
@@ -627,7 +619,7 @@
boolean isPremultiplied = createFlags.contains(BitmapCreateFlags.PREMULTIPLIED);
// and create/return a new Bitmap with it
- return new Bitmap(nativeInt, null /* buffer */, width, height, density, isMutable,
+ return new Bitmap(nativeInt, width, height, density, isMutable,
isPremultiplied, null /*ninePatchChunk*/, null /* layoutBounds */);
}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index f4f92ec..09ab657 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -612,10 +612,13 @@
throws RemoteException {}
@Override
- public void createWallpaperInputConsumer(InputChannel inputChannel) throws RemoteException {}
+ public void createInputConsumer(String name, InputChannel inputChannel)
+ throws RemoteException {}
@Override
- public void removeWallpaperInputConsumer() throws RemoteException {}
+ public boolean destroyInputConsumer(String name) throws RemoteException {
+ return false;
+ }
@Override
public Bitmap screenshotWallpaper() throws RemoteException {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index feed045..91a783a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -358,7 +358,8 @@
mMeasuredScreenWidth, MeasureSpec.EXACTLY,
mMeasuredScreenHeight, MeasureSpec.EXACTLY);
mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
- mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
+ mSystemViewInfoList =
+ visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(),
false);
return SUCCESS.createResult();
@@ -521,7 +522,8 @@
mMeasuredScreenHeight);
}
- mSystemViewInfoList = visitAllChildren(mViewRoot, 0, params.getExtendedViewInfoMode(),
+ mSystemViewInfoList =
+ visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(),
false);
// success!
@@ -1242,20 +1244,22 @@
* bounds of all the views.
*
* @param view the root View
- * @param offset an offset for the view bounds.
+ * @param hOffset horizontal offset for the view bounds.
+ * @param vOffset vertical offset for the view bounds.
* @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
* @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
* content frame.
*
* @return {@code ViewInfo} containing the bounds of the view and it children otherwise.
*/
- private ViewInfo visit(View view, int offset, boolean setExtendedInfo,
+ private ViewInfo visit(View view, int hOffset, int vOffset, boolean setExtendedInfo,
boolean isContentFrame) {
- ViewInfo result = createViewInfo(view, offset, setExtendedInfo, isContentFrame);
+ ViewInfo result = createViewInfo(view, hOffset, vOffset, setExtendedInfo, isContentFrame);
if (view instanceof ViewGroup) {
ViewGroup group = ((ViewGroup) view);
- result.setChildren(visitAllChildren(group, isContentFrame ? 0 : offset,
+ result.setChildren(visitAllChildren(group, isContentFrame ? 0 : hOffset,
+ isContentFrame ? 0 : vOffset,
setExtendedInfo, isContentFrame));
}
return result;
@@ -1267,20 +1271,22 @@
* the children of the {@code mContentRoot}.
*
* @param viewGroup the root View
- * @param offset an offset from the top for the content view frame.
+ * @param hOffset horizontal offset from the top for the content view frame.
+ * @param vOffset vertical offset from the top for the content view frame.
* @param setExtendedInfo whether to set the extended view info in the {@link ViewInfo} object.
* @param isContentFrame {@code true} if the {@code ViewInfo} to be created is part of the
* content frame. {@code false} if the {@code ViewInfo} to be created is
* part of the system decor.
*/
- private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset,
+ private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int hOffset, int vOffset,
boolean setExtendedInfo, boolean isContentFrame) {
if (viewGroup == null) {
return null;
}
if (!isContentFrame) {
- offset += viewGroup.getTop();
+ vOffset += viewGroup.getTop();
+ hOffset += viewGroup.getLeft();
}
int childCount = viewGroup.getChildCount();
@@ -1288,7 +1294,8 @@
List<ViewInfo> childrenWithoutOffset = new ArrayList<ViewInfo>(childCount);
List<ViewInfo> childrenWithOffset = new ArrayList<ViewInfo>(childCount);
for (int i = 0; i < childCount; i++) {
- ViewInfo[] childViewInfo = visitContentRoot(viewGroup.getChildAt(i), offset,
+ ViewInfo[] childViewInfo =
+ visitContentRoot(viewGroup.getChildAt(i), hOffset, vOffset,
setExtendedInfo);
childrenWithoutOffset.add(childViewInfo[0]);
childrenWithOffset.add(childViewInfo[1]);
@@ -1298,7 +1305,7 @@
} else {
List<ViewInfo> children = new ArrayList<ViewInfo>(childCount);
for (int i = 0; i < childCount; i++) {
- children.add(visit(viewGroup.getChildAt(i), offset, setExtendedInfo,
+ children.add(visit(viewGroup.getChildAt(i), hOffset, vOffset, setExtendedInfo,
isContentFrame));
}
return children;
@@ -1317,16 +1324,18 @@
* index 1 is with the offset.
*/
@NonNull
- private ViewInfo[] visitContentRoot(View view, int offset, boolean setExtendedInfo) {
+ private ViewInfo[] visitContentRoot(View view, int hOffset, int vOffset,
+ boolean setExtendedInfo) {
ViewInfo[] result = new ViewInfo[2];
if (view == null) {
return result;
}
- result[0] = createViewInfo(view, 0, setExtendedInfo, true);
- result[1] = createViewInfo(view, offset, setExtendedInfo, true);
+ result[0] = createViewInfo(view, 0, 0, setExtendedInfo, true);
+ result[1] = createViewInfo(view, hOffset, vOffset, setExtendedInfo, true);
if (view instanceof ViewGroup) {
- List<ViewInfo> children = visitAllChildren((ViewGroup) view, 0, setExtendedInfo, true);
+ List<ViewInfo> children =
+ visitAllChildren((ViewGroup) view, 0, 0, setExtendedInfo, true);
result[0].setChildren(children);
result[1].setChildren(children);
}
@@ -1337,9 +1346,12 @@
* Creates a {@link ViewInfo} for the view. The {@code ViewInfo} corresponding to the children
* of the {@code view} are not created. Consequently, the children of {@code ViewInfo} is not
* set.
- * @param offset an offset for the view bounds. Used only if view is part of the content frame.
+ * @param hOffset horizontal offset for the view bounds. Used only if view is part of the
+ * content frame.
+ * @param vOffset vertial an offset for the view bounds. Used only if view is part of the
+ * content frame.
*/
- private ViewInfo createViewInfo(View view, int offset, boolean setExtendedInfo,
+ private ViewInfo createViewInfo(View view, int hOffset, int vOffset, boolean setExtendedInfo,
boolean isContentFrame) {
if (view == null) {
return null;
@@ -1355,9 +1367,9 @@
// The view is part of the layout added by the user. Hence,
// the ViewCookie may be obtained only through the Context.
result = new ViewInfo(view.getClass().getName(),
- getContext().getViewKey(view),
- -scrollX + view.getLeft(), -scrollY + view.getTop() + offset,
- -scrollX + view.getRight(), -scrollY + view.getBottom() + offset,
+ getContext().getViewKey(view), -scrollX + view.getLeft() + hOffset,
+ -scrollY + view.getTop() + vOffset, -scrollX + view.getRight() + hOffset,
+ -scrollY + view.getBottom() + vOffset,
view, view.getLayoutParams());
} else {
// We are part of the system decor.
diff --git a/tools/streaming_proto/Android.mk b/tools/streaming_proto/Android.mk
new file mode 100644
index 0000000..5a54fd1
--- /dev/null
+++ b/tools/streaming_proto/Android.mk
@@ -0,0 +1,41 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+
+# ==========================================================
+# Build the host executable: protoc-gen-javastream
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := protoc-gen-javastream
+LOCAL_SRC_FILES := \
+ Errors.cpp \
+ string_utils.cpp \
+ main.cpp
+LOCAL_SHARED_LIBRARIES := \
+ libprotoc
+include $(BUILD_HOST_EXECUTABLE)
+
+# ==========================================================
+# Build the java test
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, test) \
+ $(call all-proto-files-under, test)
+LOCAL_MODULE := StreamingProtoTest
+LOCAL_PROTOC_OPTIMIZE_TYPE := stream
+include $(BUILD_JAVA_LIBRARY)
+
diff --git a/tools/streaming_proto/Errors.cpp b/tools/streaming_proto/Errors.cpp
new file mode 100644
index 0000000..91c6b92
--- /dev/null
+++ b/tools/streaming_proto/Errors.cpp
@@ -0,0 +1,87 @@
+#include "Errors.h"
+
+#include <stdlib.h>
+
+namespace android {
+namespace javastream_proto {
+
+Errors ERRORS;
+
+const string UNKNOWN_FILE;
+const int UNKNOWN_LINE = 0;
+
+Error::Error()
+{
+}
+
+Error::Error(const Error& that)
+ :filename(that.filename),
+ lineno(that.lineno),
+ message(that.message)
+{
+}
+
+Error::Error(const string& f, int l, const char* m)
+ :filename(f),
+ lineno(l),
+ message(m)
+{
+}
+
+Errors::Errors()
+ :m_errors()
+{
+}
+
+Errors::~Errors()
+{
+}
+
+void
+Errors::Add(const string& filename, int lineno, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ AddImpl(filename, lineno, format, args);
+ va_end(args);
+}
+
+void
+Errors::AddImpl(const string& filename, int lineno, const char* format, va_list args)
+{
+ va_list args2;
+ va_copy(args2, args);
+ int message_size = vsnprintf((char*)NULL, 0, format, args2);
+ va_end(args2);
+
+ char* buffer = new char[message_size+1];
+ vsnprintf(buffer, message_size, format, args);
+ Error error(filename, lineno, buffer);
+ delete[] buffer;
+
+ m_errors.push_back(error);
+}
+
+void
+Errors::Print() const
+{
+ for (vector<Error>::const_iterator it = m_errors.begin(); it != m_errors.end(); it++) {
+ if (it->filename == UNKNOWN_FILE) {
+ fprintf(stderr, "%s", it->message.c_str());
+ } else if (it->lineno == UNKNOWN_LINE) {
+ fprintf(stderr, "%s:%s", it->filename.c_str(), it->message.c_str());
+ } else {
+ fprintf(stderr, "%s:%d:%s", it->filename.c_str(), it->lineno, it->message.c_str());
+ }
+ }
+}
+
+bool
+Errors::HasErrors() const
+{
+ return m_errors.size() > 0;
+}
+
+} // namespace javastream_proto
+} // namespace android
+
diff --git a/tools/streaming_proto/Errors.h b/tools/streaming_proto/Errors.h
new file mode 100644
index 0000000..109195a
--- /dev/null
+++ b/tools/streaming_proto/Errors.h
@@ -0,0 +1,48 @@
+#include <stdio.h>
+
+#include <string>
+#include <vector>
+
+namespace android {
+namespace javastream_proto {
+
+using namespace std;
+
+struct Error
+{
+ Error();
+ explicit Error(const Error& that);
+ Error(const string& filename, int lineno, const char* message);
+
+ string filename;
+ int lineno;
+ string message;
+};
+
+class Errors
+{
+public:
+ Errors();
+ ~Errors();
+
+ // Add an error
+ void Add(const string& filename, int lineno, const char* format, ...);
+
+ // Print the errors to stderr if there are any.
+ void Print() const;
+
+ bool HasErrors() const;
+
+private:
+ // The errors that have been added
+ vector<Error> m_errors;
+ void AddImpl(const string& filename, int lineno, const char* format, va_list ap);
+};
+
+extern Errors ERRORS;
+extern const string UNKNOWN_FILE;
+extern const int UNKNOWN_LINE;
+
+
+} // namespace javastream_proto
+} // namespace android
diff --git a/tools/streaming_proto/main.cpp b/tools/streaming_proto/main.cpp
new file mode 100644
index 0000000..d286213
--- /dev/null
+++ b/tools/streaming_proto/main.cpp
@@ -0,0 +1,391 @@
+#include "Errors.h"
+
+#include "string_utils.h"
+
+#include "google/protobuf/compiler/plugin.pb.h"
+#include "google/protobuf/io/zero_copy_stream_impl.h"
+#include "google/protobuf/text_format.h"
+
+#include <stdio.h>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <map>
+
+using namespace android::javastream_proto;
+using namespace google::protobuf;
+using namespace google::protobuf::compiler;
+using namespace google::protobuf::io;
+using namespace std;
+
+const int FIELD_TYPE_SHIFT = 32;
+const uint64_t FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_INT32 = 3L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_INT64 = 4L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_UINT32 = 5L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_UINT64 = 6L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_SINT32 = 7L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_SINT64 = 8L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_FIXED32 = 9L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_FIXED64 = 10L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_SFIXED32 = 11L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_SFIXED64 = 12L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_BOOL = 13L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_STRING = 14L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_BYTES = 15L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_ENUM = 16L << FIELD_TYPE_SHIFT;
+const uint64_t FIELD_TYPE_OBJECT = 17L << FIELD_TYPE_SHIFT;
+
+const int FIELD_COUNT_SHIFT = 40;
+const uint64_t FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
+
+
+/**
+ * See if this is the file for this request, and not one of the imported ones.
+ */
+static bool
+should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
+{
+ const int N = request.file_to_generate_size();
+ for (int i=0; i<N; i++) {
+ if (request.file_to_generate(i) == file) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * If the descriptor gives us a class name, use that. Otherwise make one up from
+ * the filename of the .proto file.
+ */
+static string
+make_outer_class_name(const FileDescriptorProto& file_descriptor)
+{
+ string name = file_descriptor.options().java_outer_classname();
+ if (name.size() == 0) {
+ name = to_camel_case(file_base_name(file_descriptor.name()));
+ if (name.size() == 0) {
+ ERRORS.Add(UNKNOWN_FILE, UNKNOWN_LINE,
+ "Unable to make an outer class name for file: %s",
+ file_descriptor.name().c_str());
+ name = "Unknown";
+ }
+ }
+ return name;
+}
+
+/**
+ * Figure out the package name that we are generating.
+ */
+static string
+make_java_package(const FileDescriptorProto& file_descriptor) {
+ if (file_descriptor.options().has_java_package()) {
+ return file_descriptor.options().java_package();
+ } else {
+ return file_descriptor.package();
+ }
+}
+
+/**
+ * Figure out the name of the file we are generating.
+ */
+static string
+make_file_name(const FileDescriptorProto& file_descriptor)
+{
+ string const package = make_java_package(file_descriptor);
+ string result;
+ if (package.size() > 0) {
+ result = replace_string(package, '.', '/');
+ result += '/';
+ }
+
+ result += make_outer_class_name(file_descriptor);
+ result += ".java";
+
+ return result;
+}
+
+static string
+indent_more(const string& indent)
+{
+ return indent + " ";
+}
+
+/**
+ * Write the constants for an enum.
+ */
+static void
+write_enum(stringstream& text, const EnumDescriptorProto& enu, const string& indent)
+{
+ const int N = enu.value_size();
+ text << indent << "// enum " << enu.name() << endl;
+ for (int i=0; i<N; i++) {
+ const EnumValueDescriptorProto& value = enu.value(i);
+ text << indent << "public static final int "
+ << make_constant_name(value.name())
+ << " = " << value.number() << ";" << endl;
+ }
+ text << endl;
+}
+
+/**
+ * Get the string name for a field.
+ */
+static string
+get_proto_type(const FieldDescriptorProto& field)
+{
+ switch (field.type()) {
+ case FieldDescriptorProto::TYPE_DOUBLE:
+ return "double";
+ case FieldDescriptorProto::TYPE_FLOAT:
+ return "float";
+ case FieldDescriptorProto::TYPE_INT64:
+ return "int64";
+ case FieldDescriptorProto::TYPE_UINT64:
+ return "uint64";
+ case FieldDescriptorProto::TYPE_INT32:
+ return "int32";
+ case FieldDescriptorProto::TYPE_FIXED64:
+ return "fixed64";
+ case FieldDescriptorProto::TYPE_FIXED32:
+ return "fixed32";
+ case FieldDescriptorProto::TYPE_BOOL:
+ return "bool";
+ case FieldDescriptorProto::TYPE_STRING:
+ return "string";
+ case FieldDescriptorProto::TYPE_GROUP:
+ return "group<unsupported!>";
+ case FieldDescriptorProto::TYPE_MESSAGE:
+ return field.type_name();
+ case FieldDescriptorProto::TYPE_BYTES:
+ return "bytes";
+ case FieldDescriptorProto::TYPE_UINT32:
+ return "uint32";
+ case FieldDescriptorProto::TYPE_ENUM:
+ return field.type_name();
+ case FieldDescriptorProto::TYPE_SFIXED32:
+ return "sfixed32";
+ case FieldDescriptorProto::TYPE_SFIXED64:
+ return "sfixed64";
+ case FieldDescriptorProto::TYPE_SINT32:
+ return "sint32";
+ case FieldDescriptorProto::TYPE_SINT64:
+ return "sint64";
+ default:
+ // won't happen
+ return "void";
+ }
+}
+
+static uint64_t
+get_field_id(const FieldDescriptorProto& field)
+{
+ // Number
+ uint64_t result = (uint32_t)field.number();
+
+ // Type
+ switch (field.type()) {
+ case FieldDescriptorProto::TYPE_DOUBLE:
+ result |= FIELD_TYPE_DOUBLE;
+ case FieldDescriptorProto::TYPE_FLOAT:
+ result |= FIELD_TYPE_FLOAT;
+ case FieldDescriptorProto::TYPE_INT64:
+ result |= FIELD_TYPE_INT64;
+ case FieldDescriptorProto::TYPE_UINT64:
+ result |= FIELD_TYPE_UINT64;
+ case FieldDescriptorProto::TYPE_INT32:
+ result |= FIELD_TYPE_INT32;
+ case FieldDescriptorProto::TYPE_FIXED64:
+ result |= FIELD_TYPE_FIXED64;
+ case FieldDescriptorProto::TYPE_FIXED32:
+ result |= FIELD_TYPE_FIXED32;
+ case FieldDescriptorProto::TYPE_BOOL:
+ result |= FIELD_TYPE_BOOL;
+ case FieldDescriptorProto::TYPE_STRING:
+ result |= FIELD_TYPE_STRING;
+ case FieldDescriptorProto::TYPE_MESSAGE:
+ result |= FIELD_TYPE_OBJECT;
+ case FieldDescriptorProto::TYPE_BYTES:
+ result |= FIELD_TYPE_BYTES;
+ case FieldDescriptorProto::TYPE_UINT32:
+ result |= FIELD_TYPE_UINT32;
+ case FieldDescriptorProto::TYPE_ENUM:
+ result |= FIELD_TYPE_ENUM;
+ case FieldDescriptorProto::TYPE_SFIXED32:
+ result |= FIELD_TYPE_SFIXED32;
+ case FieldDescriptorProto::TYPE_SFIXED64:
+ result |= FIELD_TYPE_SFIXED64;
+ case FieldDescriptorProto::TYPE_SINT32:
+ result |= FIELD_TYPE_SINT32;
+ case FieldDescriptorProto::TYPE_SINT64:
+ result |= FIELD_TYPE_SINT64;
+ default:
+ ;
+ }
+
+ // Count
+ if (field.options().packed()) {
+ result |= FIELD_COUNT_PACKED;
+ } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
+ result |= FIELD_COUNT_REPEATED;
+ } else {
+ result |= FIELD_COUNT_SINGLE;
+ }
+
+ return result;
+}
+
+/**
+ * Write a field.
+ */
+static void
+write_field(stringstream& text, const FieldDescriptorProto& field, const string& indent)
+{
+ string optional_comment = field.label() == FieldDescriptorProto::LABEL_OPTIONAL
+ ? "optional " : "";
+ string repeated_comment = field.label() == FieldDescriptorProto::LABEL_REPEATED
+ ? "repeated " : "";
+ string proto_type = get_proto_type(field);
+ string packed_comment = field.options().packed()
+ ? " [packed=true]" : "";
+ text << indent << "// " << optional_comment << repeated_comment << proto_type << ' '
+ << field.name() << " = " << field.number() << packed_comment << ';' << endl;
+
+ text << indent << "public static final long " << make_constant_name(field.name()) << " = 0x";
+
+ ios::fmtflags fmt(text.flags());
+ text << setfill('0') << setw(16) << hex << get_field_id(field);
+ text.flags(fmt);
+
+ text << "L;" << endl;
+
+ text << endl;
+}
+
+/**
+ * Write a Message constants class.
+ */
+static void
+write_message(stringstream& text, const DescriptorProto& message, const string& indent)
+{
+ int N;
+ const string indented = indent_more(indent);
+
+ text << indent << "// message " << message.name() << endl;
+ text << indent << "public final class " << message.name() << " {" << endl;
+ text << endl;
+
+ // Enums
+ N = message.enum_type_size();
+ for (int i=0; i<N; i++) {
+ write_enum(text, message.enum_type(i), indented);
+ }
+
+ // Nested classes
+ N = message.nested_type_size();
+ for (int i=0; i<N; i++) {
+ write_message(text, message.nested_type(i), indented);
+ }
+
+ // Fields
+ N = message.field_size();
+ for (int i=0; i<N; i++) {
+ write_field(text, message.field(i), indented);
+ }
+
+ text << indent << "}" << endl;
+ text << endl;
+}
+
+/**
+ * Write the contents of a file.
+ */
+static void
+write_file(stringstream& text, const FileDescriptorProto& file_descriptor)
+{
+ string const package_name = make_java_package(file_descriptor);
+ string const outer_class_name = make_outer_class_name(file_descriptor);
+
+ text << "// Generated by protoc-gen-javastream. DO NOT MODIFY." << endl;
+ text << "// source: " << file_descriptor.name() << endl << endl;
+
+ if (package_name.size() > 0) {
+ if (package_name.size() > 0) {
+ text << "package " << package_name << ";" << endl;
+ text << endl;
+ }
+ }
+
+ // This bit of policy is android api rules specific: Raw proto classes
+ // must never be in the API, but they should all be available for testing.
+ text << "/** @hide */" << endl;
+ text << "@android.annotation.TestApi" << endl;
+
+ text << "public final class " << outer_class_name << " {" << endl;
+ text << endl;
+
+ int N;
+ const string indented = indent_more("");
+
+ N = file_descriptor.enum_type_size();
+ for (int i=0; i<N; i++) {
+ write_enum(text, file_descriptor.enum_type(i), indented);
+ }
+
+ N = file_descriptor.message_type_size();
+ for (int i=0; i<N; i++) {
+ write_message(text, file_descriptor.message_type(i), indented);
+ }
+
+ text << "}" << endl;
+}
+
+/**
+ * Main.
+ */
+int
+main(int argc, char const*const* argv)
+{
+ (void)argc;
+ (void)argv;
+
+ GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+ CodeGeneratorRequest request;
+ CodeGeneratorResponse response;
+
+ // Read the request
+ request.ParseFromIstream(&cin);
+
+ // Build the files we need.
+ const int N = request.proto_file_size();
+ for (int i=0; i<N; i++) {
+ const FileDescriptorProto& file_descriptor = request.proto_file(i);
+ if (should_generate_for_file(request, file_descriptor.name())) {
+ // Generate the text
+ stringstream text;
+ write_file(text, file_descriptor);
+
+ // Put the text in the response
+ CodeGeneratorResponse::File* file_response = response.add_file();
+ file_response->set_name(make_file_name(file_descriptor));
+ file_response->set_content(text.str());
+
+ cerr << "writing file: " << file_response->name() << endl;
+ }
+ }
+
+ // If we had errors, don't write the response. Print the errors and exit.
+ if (ERRORS.HasErrors()) {
+ ERRORS.Print();
+ return 1;
+ }
+
+ // If we didn't have errors, write the response and exit happily.
+ response.SerializeToOstream(&cout);
+ return 0;
+}
diff --git a/tools/streaming_proto/string_utils.cpp b/tools/streaming_proto/string_utils.cpp
new file mode 100644
index 0000000..cc738c4
--- /dev/null
+++ b/tools/streaming_proto/string_utils.cpp
@@ -0,0 +1,95 @@
+
+#include "string_utils.h"
+#include <iostream>
+
+namespace android {
+namespace javastream_proto {
+
+using namespace std;
+
+string
+to_camel_case(const string& str)
+{
+ string result;
+ const int N = str.size();
+ result.reserve(N);
+ bool capitalize_next = true;
+ for (int i=0; i<N; i++) {
+ char c = str[i];
+ if (c == '_') {
+ capitalize_next = true;
+ } else {
+ if (capitalize_next && c >= 'a' && c <= 'z') {
+ c = 'A' + c - 'a';
+ capitalize_next = false;
+ } else if (c >= 'A' && c <= 'Z') {
+ capitalize_next = false;
+ } else if (c >= '0' && c <= '9') {
+ capitalize_next = true;
+ } else {
+ // All other characters (e.g. non-latin) count as capital.
+ capitalize_next = false;
+ }
+ result += c;
+ }
+ }
+ return result;
+}
+
+string
+make_constant_name(const string& str)
+{
+ string result;
+ const int N = str.size();
+ bool underscore_next = false;
+ for (int i=0; i<N; i++) {
+ char c = str[i];
+ if (c >= 'A' && c <= 'Z') {
+ if (underscore_next) {
+ result += '_';
+ underscore_next = false;
+ }
+ } else if (c >= 'a' && c <= 'z') {
+ c = 'A' + c - 'a';
+ underscore_next = true;
+ } else if (c == '_') {
+ underscore_next = false;
+ }
+ result += c;
+ }
+ return result;
+}
+
+string
+file_base_name(const string& str)
+{
+ size_t start = str.rfind('/');
+ if (start == string::npos) {
+ start = 0;
+ } else {
+ start++;
+ }
+ size_t end = str.find('.', start);
+ if (end == string::npos) {
+ end = str.size();
+ }
+ return str.substr(start, end-start);
+}
+
+string
+replace_string(const string& str, const char replace, const char with)
+{
+ string result(str);
+ const int N = result.size();
+ for (int i=0; i<N; i++) {
+ if (result[i] == replace) {
+ result[i] = with;
+ }
+ }
+ return result;
+}
+
+} // namespace javastream_proto
+} // namespace android
+
+
diff --git a/tools/streaming_proto/string_utils.h b/tools/streaming_proto/string_utils.h
new file mode 100644
index 0000000..ffe83ca
--- /dev/null
+++ b/tools/streaming_proto/string_utils.h
@@ -0,0 +1,32 @@
+#include <string>
+
+namespace android {
+namespace javastream_proto {
+
+using namespace std;
+
+/**
+ * Capitalizes the string, removes underscores and makes the next letter
+ * capitalized, and makes the letter following numbers capitalized.
+ */
+string to_camel_case(const string& str);
+
+/**
+ * Capitalize and insert underscores for CamelCase.
+ */
+string make_constant_name(const string& str);
+
+/**
+ * Returns the part of a file name that isn't a path and isn't a type suffix.
+ */
+string file_base_name(const string& str);
+
+/**
+ * Replace all occurances of 'replace' with 'with'.
+ */
+string replace_string(const string& str, const char replace, const char with);
+
+
+} // namespace javastream_proto
+} // namespace android
+
diff --git a/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java b/tools/streaming_proto/test/imported.proto
similarity index 69%
rename from core/tests/coretests/src/android/print/mockservice/SettingsActivity.java
rename to tools/streaming_proto/test/imported.proto
index fb76e67..05c8f0c 100644
--- a/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java
+++ b/tools/streaming_proto/test/imported.proto
@@ -14,15 +14,13 @@
* limitations under the License.
*/
-package android.print.mockservice;
+syntax = "proto2";
-import android.app.Activity;
-import android.os.Bundle;
+package com.android.streaming_proto_test;
-public class SettingsActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-}
+/**
+ * Message that is used from the other file.
+ */
+message ImportedMessage {
+ optional int32 data = 1;
+};
diff --git a/tools/streaming_proto/test/src/com/android/streaming_proto_test/Main.java b/tools/streaming_proto/test/src/com/android/streaming_proto_test/Main.java
new file mode 100644
index 0000000..1246f53
--- /dev/null
+++ b/tools/streaming_proto/test/src/com/android/streaming_proto_test/Main.java
@@ -0,0 +1,7 @@
+package com.android.streaming_proto_test;
+
+public class Main {
+ public void main(String[] argv) {
+ System.out.println("hello world");
+ }
+}
diff --git a/tools/streaming_proto/test/test.proto b/tools/streaming_proto/test/test.proto
new file mode 100644
index 0000000..de80ed6
--- /dev/null
+++ b/tools/streaming_proto/test/test.proto
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/tools/streaming_proto/test/imported.proto";
+
+package com.android.streaming_proto_test;
+
+/**
+ * Enum that outside the scope of any classes.
+ */
+enum Outside {
+ OUTSIDE_0 = 0;
+ OUTSIDE_1 = 1;
+};
+
+message Sibling {
+ optional int32 int32_field = 1;
+}
+
+/**
+ * Message with all of the field types.
+ */
+message All {
+ /**
+ * Enum that is inside the scope of a class.
+ */
+ enum Inside {
+ option allow_alias = true;
+ INSIDE_0 = 0;
+ INSIDE_1 = 1;
+ INSIDE_1A = 1;
+ };
+
+ /**
+ * Message that is recursive.
+ */
+ message Nested {
+ optional int32 data = 10001;
+ optional Nested nested = 10002;
+ };
+
+ optional double double_field = 10;
+ repeated double double_field_repeated = 11;
+ repeated double double_field_packed = 12 [packed=true];
+
+ optional float float_field = 20;
+ repeated float float_field_repeated = 21;
+ repeated float float_field_packed = 22 [packed=true];
+
+ optional int32 int32_field = 30;
+ repeated int32 int32_field_repeated = 31;
+ repeated int32 int32_field_packed = 32 [packed=true];
+
+ optional int64 int64_field = 40;
+ repeated int64 int64_field_repeated = 41;
+ repeated int64 int64_field_packed = 42 [packed=true];
+
+ optional uint32 uint32_field = 50;
+ repeated uint32 uint32_field_repeated = 51;
+ repeated uint32 uint32_field_packed = 52 [packed=true];
+
+ optional uint64 uint64_field = 60;
+ repeated uint64 uint64_field_repeated = 61;
+ repeated uint64 uint64_field_packed = 62 [packed=true];
+
+ optional sint32 sint32_field = 70;
+ repeated sint32 sint32_field_repeated = 71;
+ repeated sint32 sint32_field_packed = 72 [packed=true];
+
+ optional sint64 sint64_field = 80;
+ repeated sint64 sint64_field_repeated = 81;
+ repeated sint64 sint64_field_packed = 82 [packed=true];
+
+ optional fixed32 fixed32_field = 90;
+ repeated fixed32 fixed32_field_repeated = 91;
+ repeated fixed32 fixed32_field_packed = 92 [packed=true];
+
+ optional fixed64 fixed64_field = 100;
+ repeated fixed64 fixed64_field_repeated = 101;
+ repeated fixed64 fixed64_field_packed = 102 [packed=true];
+
+ optional sfixed32 sfixed32_field = 110;
+ repeated sfixed32 sfixed32_field_repeated = 111;
+ repeated sfixed32 sfixed32_field_packed = 112 [packed=true];
+
+ optional sfixed64 sfixed64_field = 120;
+ repeated sfixed64 sfixed64_field_repeated = 121;
+ repeated sfixed64 sfixed64_field_packed = 122 [packed=true];
+
+ optional bool bool_field = 130;
+ repeated bool bool_field_repeated = 131;
+ repeated bool bool_field_packed = 132 [packed=true];
+
+ optional string string_field = 140;
+ repeated string string_field_repeated = 141;
+
+ optional bytes bytes_field = 150;
+ repeated bytes bytes_field_repeated = 151;
+
+ optional Outside outside_field = 160;
+ repeated Outside outside_field_repeated = 161;
+ repeated Outside outside_field_packed = 162 [packed=true];
+
+ optional Nested nested_field = 170;
+ repeated Nested nested_field_repeated = 171;
+
+ optional ImportedMessage imported_field = 180;
+ repeated ImportedMessage imported_field_repeated = 181;
+};
diff --git a/wifi/java/android/net/wifi/ParcelUtil.java b/wifi/java/android/net/wifi/ParcelUtil.java
new file mode 100644
index 0000000..a26877d
--- /dev/null
+++ b/wifi/java/android/net/wifi/ParcelUtil.java
@@ -0,0 +1,165 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.os.Parcel;
+
+import java.io.ByteArrayInputStream;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+/**
+ * Provides utilities for writing/reading a non-Parcelable objects to/from
+ * a Parcel object.
+ *
+ * @hide
+ */
+public class ParcelUtil {
+ /**
+ * Write a PrivateKey object |key| to the specified Parcel |dest|.
+ *
+ * Below is the data format:
+ * |algorithm| -> String of algorithm name
+ * |endcodedKey| -> byte[] of key data
+ *
+ * For a null PrivateKey object, a null string will be written to |algorithm| and
+ * |encodedKey| will be skipped. Since a PrivateKey can only be constructed with
+ * a valid algorithm String.
+ *
+ * @param dest Parcel object to write to
+ * @param key PrivateKey object to read from.
+ */
+ public static void writePrivateKey(Parcel dest, PrivateKey key) {
+ if (key == null) {
+ dest.writeString(null);
+ return;
+ }
+
+ dest.writeString(key.getAlgorithm());
+ dest.writeByteArray(key.getEncoded());
+ }
+
+ /**
+ * Read/create a PrivateKey object from a specified Parcel object |in|.
+ *
+ * Refer to the function above for the expected data format.
+ *
+ * @param in Parcel object to read from
+ * @return a PrivateKey object or null
+ */
+ public static PrivateKey readPrivateKey(Parcel in) {
+ String algorithm = in.readString();
+ if (algorithm == null) {
+ return null;
+ }
+
+ byte[] userKeyBytes = in.createByteArray();
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
+ return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(userKeyBytes));
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Write a X509Certificate object |cert| to a Parcel object |dest|.
+ * The data being written to the Parcel is just a byte[] of the encoded certificate data.
+ *
+ * @param dest Parcel object to write to
+ * @param cert X509Certificate object to read from
+ */
+ public static void writeCertificate(Parcel dest, X509Certificate cert) {
+ byte[] certBytes = null;
+ if (cert != null) {
+ try {
+ certBytes = cert.getEncoded();
+ } catch (CertificateEncodingException e) {
+ /* empty, write null. */
+ }
+ }
+ dest.writeByteArray(certBytes);
+ }
+
+ /**
+ * Read/create a X509Certificate object from a specified Parcel object |in|.
+ *
+ * @param in Parcel object to read from
+ * @return a X509Certficate object or null
+ */
+ public static X509Certificate readCertificate(Parcel in) {
+ byte[] certBytes = in.createByteArray();
+ if (certBytes == null) {
+ return null;
+ }
+
+ try {
+ CertificateFactory cFactory = CertificateFactory.getInstance("X.509");
+ return (X509Certificate) cFactory
+ .generateCertificate(new ByteArrayInputStream(certBytes));
+ } catch (CertificateException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Write an array of X509Certificate objects |certs| to a Parcel object |dest|.
+ * The data being written to the Parcel are consist of an integer indicating
+ * the size of the array and the certificates data. Certificates data will be
+ * skipped for a null array or size of 0 array.
+ *
+ * @param dest Parcel object to write to
+ * @param certs array of X509Certificate objects to read from
+ */
+ public static void writeCertificates(Parcel dest, X509Certificate[] certs) {
+ if (certs == null || certs.length == 0) {
+ dest.writeInt(0);
+ return;
+ }
+
+ dest.writeInt(certs.length);
+ for (int i = 0; i < certs.length; i++) {
+ writeCertificate(dest, certs[i]);
+ }
+ }
+
+ /**
+ * Read/create an array of X509Certificate objects from a specified Parcel object |in|.
+ *
+ * @param in Parcel object to read from
+ * @return X509Certficate[] or null
+ */
+ public static X509Certificate[] readCertificates(Parcel in) {
+ int length = in.readInt();
+ if (length == 0) {
+ return null;
+ }
+
+ X509Certificate[] certs = new X509Certificate[length];
+ for (int i = 0; i < length; i++) {
+ certs[i] = readCertificate(in);
+ }
+ return certs;
+ }
+}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 67cf107..465addf 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -139,12 +139,6 @@
public long seen;
/**
- * If the scan result is a valid autojoin candidate
- * {@hide}
- */
- public int isAutoJoinCandidate;
-
- /**
* @hide
* Update RSSI of the scan result
* @param previousRssi
@@ -452,7 +446,6 @@
numConnection = source.numConnection;
numUsage = source.numUsage;
numIpConfigFailures = source.numIpConfigFailures;
- isAutoJoinCandidate = source.isAutoJoinCandidate;
venueName = source.venueName;
operatorFriendlyName = source.operatorFriendlyName;
flags = source.flags;
@@ -530,7 +523,6 @@
dest.writeInt(numConnection);
dest.writeInt(numUsage);
dest.writeInt(numIpConfigFailures);
- dest.writeInt(isAutoJoinCandidate);
dest.writeString((venueName != null) ? venueName.toString() : "");
dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : "");
dest.writeLong(this.flags);
@@ -600,7 +592,6 @@
sr.numConnection = in.readInt();
sr.numUsage = in.readInt();
sr.numIpConfigFailures = in.readInt();
- sr.isAutoJoinCandidate = in.readInt();
sr.venueName = in.readString();
sr.operatorFriendlyName = in.readString();
sr.flags = in.readLong();
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index c0e8bc2..e410a9c 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -183,48 +183,14 @@
dest.writeInt(mEapMethod);
dest.writeInt(mPhase2Method);
- writeCertificates(dest, mCaCerts);
-
- if (mClientPrivateKey != null) {
- String algorithm = mClientPrivateKey.getAlgorithm();
- byte[] userKeyBytes = mClientPrivateKey.getEncoded();
- dest.writeInt(userKeyBytes.length);
- dest.writeByteArray(userKeyBytes);
- dest.writeString(algorithm);
- } else {
- dest.writeInt(0);
- }
-
- writeCertificate(dest, mClientCertificate);
- }
-
- private void writeCertificates(Parcel dest, X509Certificate[] cert) {
- if (cert != null && cert.length != 0) {
- dest.writeInt(cert.length);
- for (int i = 0; i < cert.length; i++) {
- writeCertificate(dest, cert[i]);
- }
- } else {
- dest.writeInt(0);
- }
- }
-
- private void writeCertificate(Parcel dest, X509Certificate cert) {
- if (cert != null) {
- try {
- byte[] certBytes = cert.getEncoded();
- dest.writeInt(certBytes.length);
- dest.writeByteArray(certBytes);
- } catch (CertificateEncodingException e) {
- dest.writeInt(0);
- }
- } else {
- dest.writeInt(0);
- }
+ ParcelUtil.writeCertificates(dest, mCaCerts);
+ ParcelUtil.writePrivateKey(dest, mClientPrivateKey);
+ ParcelUtil.writeCertificate(dest, mClientCertificate);
}
public static final Creator<WifiEnterpriseConfig> CREATOR =
new Creator<WifiEnterpriseConfig>() {
+ @Override
public WifiEnterpriseConfig createFromParcel(Parcel in) {
WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
int count = in.readInt();
@@ -236,58 +202,13 @@
enterpriseConfig.mEapMethod = in.readInt();
enterpriseConfig.mPhase2Method = in.readInt();
- enterpriseConfig.mCaCerts = readCertificates(in);
-
- PrivateKey userKey = null;
- int len = in.readInt();
- if (len > 0) {
- try {
- byte[] bytes = new byte[len];
- in.readByteArray(bytes);
- String algorithm = in.readString();
- KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
- userKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));
- } catch (NoSuchAlgorithmException e) {
- userKey = null;
- } catch (InvalidKeySpecException e) {
- userKey = null;
- }
- }
-
- enterpriseConfig.mClientPrivateKey = userKey;
- enterpriseConfig.mClientCertificate = readCertificate(in);
+ enterpriseConfig.mCaCerts = ParcelUtil.readCertificates(in);
+ enterpriseConfig.mClientPrivateKey = ParcelUtil.readPrivateKey(in);
+ enterpriseConfig.mClientCertificate = ParcelUtil.readCertificate(in);
return enterpriseConfig;
}
- private X509Certificate[] readCertificates(Parcel in) {
- X509Certificate[] certs = null;
- int len = in.readInt();
- if (len > 0) {
- certs = new X509Certificate[len];
- for (int i = 0; i < len; i++) {
- certs[i] = readCertificate(in);
- }
- }
- return certs;
- }
-
- private X509Certificate readCertificate(Parcel in) {
- X509Certificate cert = null;
- int len = in.readInt();
- if (len > 0) {
- try {
- byte[] bytes = new byte[len];
- in.readByteArray(bytes);
- CertificateFactory cFactory = CertificateFactory.getInstance("X.509");
- cert = (X509Certificate) cFactory
- .generateCertificate(new ByteArrayInputStream(bytes));
- } catch (CertificateException e) {
- cert = null;
- }
- }
- return cert;
- }
-
+ @Override
public WifiEnterpriseConfig[] newArray(int size) {
return new WifiEnterpriseConfig[size];
}
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
index 56baba9..5485824 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -23,6 +23,7 @@
import android.net.wifi.nan.IWifiNanEventCallback;
import android.net.wifi.nan.PublishConfig;
import android.net.wifi.nan.SubscribeConfig;
+import android.net.wifi.nan.WifiNanCharacteristics;
import android.net.wifi.RttManager;
/**
@@ -36,6 +37,7 @@
void enableUsage();
void disableUsage();
boolean isUsageEnabled();
+ WifiNanCharacteristics getCharacteristics();
// client API
void connect(in IBinder binder, in String callingPackage, in IWifiNanEventCallback callback,
diff --git a/wifi/java/android/net/wifi/nan/PublishConfig.java b/wifi/java/android/net/wifi/nan/PublishConfig.java
index 4b67f9a..30c5bc0 100644
--- a/wifi/java/android/net/wifi/nan/PublishConfig.java
+++ b/wifi/java/android/net/wifi/nan/PublishConfig.java
@@ -182,7 +182,7 @@
*
* @hide
*/
- public void validate() throws IllegalArgumentException {
+ public void assertValid(WifiNanCharacteristics characteristics) throws IllegalArgumentException {
WifiNanUtils.validateServiceName(mServiceName);
if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
@@ -198,6 +198,26 @@
if (mTtlSec < 0) {
throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
}
+
+ if (characteristics != null) {
+ int maxServiceNameLength = characteristics.getMaxServiceNameLength();
+ if (maxServiceNameLength != 0 && mServiceName.length > maxServiceNameLength) {
+ throw new IllegalArgumentException(
+ "Service name longer than supported by device characteristics");
+ }
+ int maxServiceSpecificInfoLength = characteristics.getMaxServiceSpecificInfoLength();
+ if (maxServiceSpecificInfoLength != 0 && mServiceSpecificInfo != null
+ && mServiceSpecificInfo.length > maxServiceSpecificInfoLength) {
+ throw new IllegalArgumentException(
+ "Service specific info longer than supported by device characteristics");
+ }
+ int maxMatchFilterLength = characteristics.getMaxMatchFilterLength();
+ if (maxMatchFilterLength != 0 && mMatchFilter != null
+ && mMatchFilter.length > maxMatchFilterLength) {
+ throw new IllegalArgumentException(
+ "Match filter longer than supported by device characteristics");
+ }
+ }
}
/**
diff --git a/wifi/java/android/net/wifi/nan/SubscribeConfig.java b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
index 4352fcf..ea7b8e4 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
@@ -209,7 +209,7 @@
*
* @hide
*/
- public void validate() throws IllegalArgumentException {
+ public void assertValid(WifiNanCharacteristics characteristics) throws IllegalArgumentException {
WifiNanUtils.validateServiceName(mServiceName);
if (!LvBufferUtils.isValid(mMatchFilter, 1)) {
@@ -229,6 +229,26 @@
throw new IllegalArgumentException(
"Invalid matchType - must be MATCH_FIRST_ONLY or MATCH_ALL");
}
+
+ if (characteristics != null) {
+ int maxServiceNameLength = characteristics.getMaxServiceNameLength();
+ if (maxServiceNameLength != 0 && mServiceName.length > maxServiceNameLength) {
+ throw new IllegalArgumentException(
+ "Service name longer than supported by device characteristics");
+ }
+ int maxServiceSpecificInfoLength = characteristics.getMaxServiceSpecificInfoLength();
+ if (maxServiceSpecificInfoLength != 0 && mServiceSpecificInfo != null
+ && mServiceSpecificInfo.length > maxServiceSpecificInfoLength) {
+ throw new IllegalArgumentException(
+ "Service specific info longer than supported by device characteristics");
+ }
+ int maxMatchFilterLength = characteristics.getMaxMatchFilterLength();
+ if (maxMatchFilterLength != 0 && mMatchFilter != null
+ && mMatchFilter.length > maxMatchFilterLength) {
+ throw new IllegalArgumentException(
+ "Match filter longer than supported by device characteristics");
+ }
+ }
}
/**
diff --git a/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.aidl
similarity index 69%
copy from core/tests/coretests/src/android/print/mockservice/SettingsActivity.java
copy to wifi/java/android/net/wifi/nan/WifiNanCharacteristics.aidl
index fb76e67..e562a00 100644
--- a/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.aidl
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-package android.print.mockservice;
+package android.net.wifi.nan;
-import android.app.Activity;
-import android.os.Bundle;
-
-public class SettingsActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-}
+parcelable WifiNanCharacteristics;
diff --git a/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java
new file mode 100644
index 0000000..f43ed4d
--- /dev/null
+++ b/wifi/java/android/net/wifi/nan/WifiNanCharacteristics.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.nan;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * The characteristics of the Wi-Fi NAN implementation.
+ *
+ * @hide PROPOSED_NAN_API
+ */
+public class WifiNanCharacteristics implements Parcelable {
+ /** @hide */
+ public static final String KEY_MAX_SERVICE_NAME_LENGTH = "key_max_service_name_length";
+ /** @hide */
+ public static final String KEY_MAX_SERVICE_SPECIFIC_INFO_LENGTH =
+ "key_max_service_specific_info_length";
+ /** @hide */
+ public static final String KEY_MAX_MATCH_FILTER_LENGTH = "key_max_match_filter_length";
+
+ private Bundle mCharacteristics = new Bundle();
+
+ /** @hide : should not be created by apps */
+ public WifiNanCharacteristics(Bundle characteristics) {
+ mCharacteristics = characteristics;
+ }
+
+ /**
+ * Returns the maximum string length that can be used to specify a NAN service name. Restricts
+ * the parameters of the {@link PublishConfig.Builder#setServiceName(String)} and
+ * {@link SubscribeConfig.Builder#setServiceName(String)}.
+ *
+ * @return A positive integer, maximum string length of NAN service name.
+ */
+ public int getMaxServiceNameLength() {
+ return mCharacteristics.getInt(KEY_MAX_SERVICE_NAME_LENGTH);
+ }
+
+ /**
+ * Returns the maximum length of byte array that can be used to specify a NAN service specific
+ * information field: the arbitrary load used in discovery or the message length of NAN
+ * message exchange. Restricts the parameters of the
+ * {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])},
+ * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[])}, and
+ * {@link WifiNanDiscoveryBaseSession#sendMessage(Object, int, byte[])} variants.
+ *
+ * @return A positive integer, maximum length of byte array for NAN messaging.
+ */
+ public int getMaxServiceSpecificInfoLength() {
+ return mCharacteristics.getInt(KEY_MAX_SERVICE_SPECIFIC_INFO_LENGTH);
+ }
+
+ /**
+ * Returns the maximum length of byte array that can be used to specify a NAN match filter.
+ * Restricts the parameters of the {@link PublishConfig.Builder#setMatchFilter(byte[])} and
+ * {@link SubscribeConfig.Builder#setMatchFilter(byte[])}.
+ *
+ * @return A positive integer, maximum legngth of byte array for NAN discovery match filter.
+ */
+ public int getMaxMatchFilterLength() {
+ return mCharacteristics.getInt(KEY_MAX_MATCH_FILTER_LENGTH);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBundle(mCharacteristics);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator<WifiNanCharacteristics> CREATOR =
+ new Creator<WifiNanCharacteristics>() {
+ @Override
+ public WifiNanCharacteristics createFromParcel(Parcel in) {
+ WifiNanCharacteristics c = new WifiNanCharacteristics(in.readBundle());
+ return c;
+ }
+
+ @Override
+ public WifiNanCharacteristics[] newArray(int size) {
+ return new WifiNanCharacteristics[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index 705ba4a..002b953 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -201,6 +201,8 @@
* Use the {@link #isAvailable()} to query the current status.
* This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering
* the broadcast to check the current state of Wi-Fi NAN.
+ * <p>Note: The broadcast is only delivered to registered receivers - no manifest registered
+ * components will be launched.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_WIFI_NAN_STATE_CHANGED =
@@ -291,6 +293,20 @@
}
/**
+ * Returns the characteristics of the Wi-Fi NAN interface: a set of parameters which specify
+ * limitations on configurations, e.g. the maximum service name length.
+ *
+ * @return An object specifying configuration limitations of NAN.
+ */
+ public WifiNanCharacteristics getCharacteristics() {
+ try {
+ return mService.getCharacteristics();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Attach to the Wi-Fi NAN service - enabling the application to create discovery sessions or
* create connections to peers. The device will attach to an existing cluster if it can find
* one or create a new cluster (if it is the first to enable NAN in its vicinity). Results
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index 5fb2c06..df5e3c1 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -113,6 +113,8 @@
* An application must use the {@link WifiNanDiscoveryBaseSession#destroy()} to
* terminate the publish discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
+ * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
+ * permission to start a publish discovery session.
*
* @param handler The Handler on whose thread to execute the callbacks of the {@code
* callback} object. If a null is provided then the application's main thread will be used.
@@ -156,6 +158,8 @@
* An application must use the {@link WifiNanDiscoveryBaseSession#destroy()} to
* terminate the subscribe discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
+ * <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
+ * permission to start a subscribe discovery session.
*
* @param handler The Handler on whose thread to execute the callbacks of the {@code
* callback} object. If a null is provided then the application's main thread will be used.
diff --git a/wifi/tests/src/android/net/wifi/FakeKeys.java b/wifi/tests/src/android/net/wifi/FakeKeys.java
index 0c73070..c0d60c3 100644
--- a/wifi/tests/src/android/net/wifi/FakeKeys.java
+++ b/wifi/tests/src/android/net/wifi/FakeKeys.java
@@ -19,11 +19,16 @@
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
/**
- * A class containing test certificates.
+ * A class containing test certificates and private keys.
*/
public class FakeKeys {
private static final String CA_CERT0_STRING = "-----BEGIN CERTIFICATE-----\n" +
@@ -68,6 +73,146 @@
"-----END CERTIFICATE-----\n";
public static final X509Certificate CA_CERT1 = loadCertificate(CA_CERT1_STRING);
+ private static final String CLIENT_CERT_STR = "-----BEGIN CERTIFICATE-----\n" +
+ "MIIE/DCCAuQCAQEwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UEBhMCVVMxCzAJBgNV\n" +
+ "BAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdUZXN0aW5n\n" +
+ "MB4XDTE2MDkzMDIwNTQyOFoXDTE3MDkzMDIwNTQyOFowRDELMAkGA1UEBhMCVVMx\n" +
+ "CzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdU\n" +
+ "ZXN0aW5nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnpmcbuaeHfnJ\n" +
+ "k+2QNvxmdVFTawyFMNk0USCq5sexscwmxbewG/Rb8YnixwJWS44v2XkSujB67z5C\n" +
+ "s2qudFEhRXKdEuC6idbAuA97KjipHh0AAniWMsyv61fvbgsUC0b0canx3LiDq81p\n" +
+ "y28NNGmAvoazLZUZ4AhBRiwYZY6FKk723gmZoGbEIeG7J1dlXPusc1662rIjz4eU\n" +
+ "zlmmlvqyHfNqnNk8L14Vug6Xh+lOEGN85xhu1YHAEKGrS89kZxs5rum/cZU8KH2V\n" +
+ "v6eKnY03kxjiVLQtnLpm/7VUEoCMGHyruRj+p3my4+DgqMsmsH52RZCBsjyGlpbU\n" +
+ "NOwOTIX6xh+Rqloduz4AnrMYYIiIw2s8g+2zJM7VbcVKx0fGS26BKdrxgrXWfmNE\n" +
+ "nR0/REQ5AxDGw0jfTUvtdTkXAf+K4MDjcNLEZ+MA4rHfAfQWZtUR5BkHCQYxNpJk\n" +
+ "pA0gyk+BpKdC4WdzI14NSWsu5sRCmBCFqH6BTOSEq/V1cNorBxNwLSSTwFFqUDqx\n" +
+ "Y5nQLXygkJf9WHZWtSKeSjtOYgilz7UKzC2s3CsjmIyGFe+SwpuHJnuE4Uc8Z5Cb\n" +
+ "bjNGHPzqL6XnmzZHJp7RF8kBdKdjGC7dCUltzOfICZeKlzOOq+Kw42T/nXjuXvpb\n" +
+ "nkXNxg741Nwd6RecykXJbseFwm3EYxkCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEA\n" +
+ "Ga1mGwI9aXkL2fTPXO9YkAPzoGeX8aeuVYSQaSkNq+5vnogYCyAt3YDHjRG+ewTT\n" +
+ "WbnPA991xRAPac+biJeXWmwvgGj0YuT7e79phAiGkTTnbAjFHGfYnBy/tI/v7btO\n" +
+ "hRNElA5yTJ1m2fVbBEKXzMR83jrT9iyI+YLRN86zUZIaC86xxSbqnrdWN2jOK6MX\n" +
+ "dS8Arp9tPQjC/4gW+2Ilxv68jiYh+5auWHQZVjppWVY//iu4mAbkq1pTwQEhZ8F8\n" +
+ "Zrmh9DHh60hLFcfSuhIAwf/NMzppwdkjy1ruKVrpijhGKGp4OWu8nvOUgHSzxc7F\n" +
+ "PwpVZ5N2Ku4L8MLO6BG2VasRJK7l17TzDXlfLZHJjkuryOFxVaQKt8ZNFgTOaCXS\n" +
+ "E+gpTLksKU7riYckoiP4+H1sn9qcis0e8s4o/uf1UVc8GSdDw61ReGM5oZEDm1u8\n" +
+ "H9x20QU6igLqzyBpqvCKv7JNgU1uB2PAODHH78zJiUfnKd1y+o+J1iWzaGj3EFji\n" +
+ "T8AXksbTP733FeFXfggXju2dyBH+Z1S5BBTEOd1brWgXlHSAZGm97MKZ94r6/tkX\n" +
+ "qfv3fCos0DKz0oV7qBxYS8wiYhzrRVxG6ITAoH8uuUVVQaZF+G4nJ2jEqNbfuKyX\n" +
+ "ATQsVNjNNlDA0J33GobPMjT326wa4YAWMx8PI5PJZ3g=\n" +
+ "-----END CERTIFICATE-----\n";
+ public static final X509Certificate CLIENT_CERT = loadCertificate(CLIENT_CERT_STR);
+
+ private static final byte[] FAKE_RSA_KEY_1 = new byte[] {
+ (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01,
+ (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a,
+ (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01,
+ (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82,
+ (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e,
+ (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81,
+ (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b,
+ (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66,
+ (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a,
+ (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02,
+ (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3,
+ (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d,
+ (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67,
+ (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb,
+ (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2,
+ (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79,
+ (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce,
+ (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08,
+ (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b,
+ (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4,
+ (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d,
+ (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23,
+ (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08,
+ (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1,
+ (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4,
+ (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16,
+ (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e,
+ (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01,
+ (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16,
+ (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98,
+ (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf,
+ (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a,
+ (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2,
+ (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc,
+ (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5,
+ (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a,
+ (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b,
+ (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9,
+ (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12,
+ (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e,
+ (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d,
+ (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2,
+ (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d,
+ (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc,
+ (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98,
+ (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96,
+ (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30,
+ (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e,
+ (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad,
+ (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f,
+ (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89,
+ (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13,
+ (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a,
+ (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e,
+ (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa,
+ (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47,
+ (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44,
+ (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22,
+ (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10,
+ (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45,
+ (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4,
+ (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda,
+ (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1,
+ (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab,
+ (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7,
+ (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc,
+ (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d,
+ (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82,
+ (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3,
+ (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a,
+ (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9,
+ (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6,
+ (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00,
+ (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd,
+ (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb,
+ (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4,
+ (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0,
+ (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2,
+ (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce,
+ (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a,
+ (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21,
+ (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d,
+ (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1,
+ (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41,
+ (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce,
+ (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0,
+ (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40,
+ (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a,
+ (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c,
+ (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90,
+ (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf,
+ (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb,
+ (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14,
+ (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab,
+ (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02,
+ (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67,
+ (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d,
+ (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d,
+ (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b,
+ (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2,
+ (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28,
+ (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd,
+ (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d,
+ (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b,
+ (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1,
+ (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51
+ };
+ public static final PrivateKey RSA_KEY1 = loadPrivateRSAKey(FAKE_RSA_KEY_1);
private static X509Certificate loadCertificate(String blob) {
try {
@@ -80,4 +225,13 @@
return null;
}
}
+
+ private static PrivateKey loadPrivateRSAKey(byte[] fakeKey) {
+ try {
+ KeyFactory kf = KeyFactory.getInstance("RSA");
+ return kf.generatePrivate(new PKCS8EncodedKeySpec(fakeKey));
+ } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
+ return null;
+ }
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/ParcelUtilTest.java b/wifi/tests/src/android/net/wifi/ParcelUtilTest.java
new file mode 100644
index 0000000..6787594
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/ParcelUtilTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.net.wifi;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+/**
+ * Unit tests for {@link android.net.wifi.ParcelUtil}.
+ */
+@SmallTest
+public class ParcelUtilTest {
+ private Parcel mParcel;
+
+ @Before
+ public void setUp() throws Exception {
+ mParcel = Parcel.obtain();
+ }
+
+ @Test
+ public void readWriteNullPrivateKey() throws Exception {
+ ParcelUtil.writePrivateKey(mParcel, null);
+
+ mParcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ PrivateKey readKey = ParcelUtil.readPrivateKey(mParcel);
+ assertNull(readKey);
+ }
+
+ @Test
+ public void readWriteValidPrivateKey() throws Exception {
+ PrivateKey writeKey = FakeKeys.RSA_KEY1;
+ ParcelUtil.writePrivateKey(mParcel, writeKey);
+
+ mParcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ PrivateKey readKey = ParcelUtil.readPrivateKey(mParcel);
+ assertNotNull(readKey);
+ assertEquals(writeKey.getAlgorithm(), readKey.getAlgorithm());
+ assertArrayEquals(writeKey.getEncoded(), readKey.getEncoded());
+ }
+
+ @Test
+ public void readWriteNullCertificate() throws Exception {
+ ParcelUtil.writeCertificate(mParcel, null);
+
+ mParcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ X509Certificate readCert = ParcelUtil.readCertificate(mParcel);
+ assertNull(readCert);
+ }
+
+ @Test
+ public void readWriteValidCertificate() throws Exception {
+ X509Certificate writeCert = FakeKeys.CA_CERT1;
+ ParcelUtil.writeCertificate(mParcel, writeCert);
+
+ mParcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ X509Certificate readCert = ParcelUtil.readCertificate(mParcel);
+ assertNotNull(readCert);
+ assertArrayEquals(writeCert.getEncoded(), readCert.getEncoded());
+ }
+
+ @Test
+ public void readWriteNullCertificates() throws Exception {
+ ParcelUtil.writeCertificates(mParcel, null);
+
+ mParcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ X509Certificate[] readCerts = ParcelUtil.readCertificates(mParcel);
+ assertNull(readCerts);
+ }
+
+ @Test
+ public void readWriteValidCertificates() throws Exception {
+ X509Certificate[] writeCerts = new X509Certificate[2];
+ writeCerts[0] = FakeKeys.CA_CERT0;
+ writeCerts[1] = FakeKeys.CA_CERT1;
+ ParcelUtil.writeCertificates(mParcel, writeCerts);
+
+ mParcel.setDataPosition(0); // Rewind data position back to the beginning for read.
+ X509Certificate[] readCerts = ParcelUtil.readCertificates(mParcel);
+ assertNotNull(readCerts);
+ assertEquals(writeCerts.length, readCerts.length);
+ for (int i = 0; i < writeCerts.length; i++) {
+ assertNotNull(readCerts[i]);
+ assertArrayEquals(writeCerts[i].getEncoded(), readCerts[i].getEncoded());
+ }
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index 0d964b7..0e503d5 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -16,10 +16,12 @@
package android.net.wifi;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import android.net.wifi.WifiEnterpriseConfig.Eap;
import android.net.wifi.WifiEnterpriseConfig.Phase2;
@@ -30,6 +32,7 @@
import org.junit.Before;
import org.junit.Test;
+import java.security.PrivateKey;
import java.security.cert.X509Certificate;
@@ -259,6 +262,45 @@
assertEquals("\"autheap=GTC\"", getSupplicantPhase2Method());
}
+ /**
+ * Verifies that parceling a WifiEnterpriseConfig preserves the key
+ * and certificates information.
+ */
+ @Test
+ public void parcelConfigWithKeyAndCerts() throws Exception {
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ PrivateKey clientKey = FakeKeys.RSA_KEY1;
+ X509Certificate clientCert = FakeKeys.CLIENT_CERT;
+ X509Certificate[] caCerts = new X509Certificate[] {FakeKeys.CA_CERT0, FakeKeys.CA_CERT1};
+ enterpriseConfig.setClientKeyEntry(clientKey, clientCert);
+ enterpriseConfig.setCaCertificates(caCerts);
+ Parcel parcel = Parcel.obtain();
+ enterpriseConfig.writeToParcel(parcel, 0);
+
+ parcel.setDataPosition(0); // Allow parcel to be read from the beginning.
+ mEnterpriseConfig = WifiEnterpriseConfig.CREATOR.createFromParcel(parcel);
+ PrivateKey actualClientKey = mEnterpriseConfig.getClientPrivateKey();
+ X509Certificate actualClientCert = mEnterpriseConfig.getClientCertificate();
+ X509Certificate[] actualCaCerts = mEnterpriseConfig.getCaCertificates();
+
+ /* Verify client private key. */
+ assertNotNull(actualClientKey);
+ assertEquals(clientKey.getAlgorithm(), actualClientKey.getAlgorithm());
+ assertArrayEquals(clientKey.getEncoded(), actualClientKey.getEncoded());
+
+ /* Verify client certificate. */
+ assertNotNull(actualClientCert);
+ assertArrayEquals(clientCert.getEncoded(), actualClientCert.getEncoded());
+
+ /* Verify CA certificates. */
+ assertNotNull(actualCaCerts);
+ assertEquals(caCerts.length, actualCaCerts.length);
+ for (int i = 0; i < caCerts.length; i++) {
+ assertNotNull(actualCaCerts[i]);
+ assertArrayEquals(caCerts[i].getEncoded(), actualCaCerts[i].getEncoded());
+ }
+ }
+
/** Verifies proper operation of the getKeyId() method. */
@Test
public void getKeyId() {